[{"data":1,"prerenderedAt":1470},["ShallowReactive",2],{"blog-current-btrfs-finding-and-fixing-highly-fragmented-files-en":3,"blog-previous-btrfs-finding-and-fixing-highly-fragmented-files-en":514,"blog-next-btrfs-finding-and-fixing-highly-fragmented-files-en":525,"blog-alt-de-btrfs-finding-and-fixing-highly-fragmented-files-en":541,"blog-alt-en-btrfs-finding-and-fixing-highly-fragmented-files-en":543,"employee-bernd-helm":544,"content-query-xGvaff9H60":650,"content-query-ViehLtZIqO":883,"content-query-1PFeYVQSzn":1408,"related-refs-devops--en":1444},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"author":10,"image":11,"releaseDate":12,"blogCategories":13,"tags":16,"body":18,"_type":508,"_id":509,"_source":510,"_file":511,"_stem":512,"_extension":513},"/en/blog/btrfs-finding-and-fixing-highly-fragmented-files","blog",false,"","BTRFS: Finding and fixing highly fragmented files","Most of the best BTRFS features are powered by the copy-on-write technology. If an application wants to rewrite a part of a file, like the first MB, the Data is not written in-place but in an so-called extend. This enables BTRFS to keep multiple versions of partially rewritten files with only claiming ...","bernd-helm","/blog/thumbnails/BTRFS_white.png","2020-10-21",[14,15],"What moves us","Infrastructure",[17],"devops",{"type":19,"children":20,"toc":498},"root",[21,30,44,50,55,61,66,107,113,118,124,136,265,283,289,446,451,457,486,492],{"type":22,"tag":23,"props":24,"children":26},"element","h2",{"id":25},"what-is-btrfs-fragmentation",[27],{"type":28,"value":29},"text","What is BTRFS fragmentation?",{"type":22,"tag":31,"props":32,"children":33},"p",{},[34,36,42],{"type":28,"value":35},"Most of the best BTRFS features are powered by the ",{"type":22,"tag":37,"props":38,"children":39},"em",{},[40],{"type":28,"value":41},"copy-on-write technology",{"type":28,"value":43},". If a application wants to rewrite a part of a file, like the first megabyte, the data is not written in-place but in an so-called extend. This enables BTRFS to keep multiple versions of partially rewritten files with only claiming disk space assigned to the changes and not multiple full copies of a file. The old data can be discarded at some point (i.e. if its not used by any snapshots anymore) and the extend will serve the files current version.",{"type":22,"tag":23,"props":45,"children":47},{"id":46},"btrfs-fragmentation-can-hurt-the-performance-of-your-system",[48],{"type":28,"value":49},"BTRFS fragmentation can hurt the performance of your System",{"type":22,"tag":31,"props":51,"children":52},{},[53],{"type":28,"value":54},"You can guess, reading a file with 100k+ extends and adding more extends requires a lot of bookkeeping and storage seeks from your system. That 10GB file there is internally shattered into 100k parts that need to be collected if you want to read the whole file. This clearly adds complexity - and decreases performance.",{"type":22,"tag":23,"props":56,"children":58},{"id":57},"btrfs-fragmentation-can-block-huge-amounts-of-disk-space",[59],{"type":28,"value":60},"BTRFS fragmentation can block huge amounts of disk space",{"type":22,"tag":31,"props":62,"children":63},{},[64],{"type":28,"value":65},"Yes, BTRFS has to store the locations of these 100k extends somewhere, easily adding some extra GB of used disk space to your system. The bad thing is that BTRFS does not tell you that",{"type":22,"tag":31,"props":67,"children":68},{},[69,71,77,79,84,86,91,93,98,100,105],{"type":28,"value":70},"If you see your btrfs filesystem using ",{"type":22,"tag":72,"props":73,"children":74},"strong",{},[75],{"type":28,"value":76},"80GB",{"type":28,"value":78}," in ",{"type":22,"tag":37,"props":80,"children":81},{},[82],{"type":28,"value":83},"df",{"type":28,"value":85}," and ",{"type":22,"tag":37,"props":87,"children":88},{},[89],{"type":28,"value":90},"btrfs fi show",{"type":28,"value":92}," while ",{"type":22,"tag":37,"props":94,"children":95},{},[96],{"type":28,"value":97},"du -hsx",{"type":28,"value":99}," only shows ",{"type":22,"tag":72,"props":101,"children":102},{},[103],{"type":28,"value":104},"54GB",{"type":28,"value":106}," there are only two reasons i am aware of to cause this: either you have snapshots that keep old extends - or you have massive fragmentation.",{"type":22,"tag":23,"props":108,"children":110},{"id":109},"btrfs-filesystem-defrag",[111],{"type":28,"value":112},"BTRFS filesystem defrag",{"type":22,"tag":31,"props":114,"children":115},{},[116],{"type":28,"value":117},"It is possible to use BTRFS filesystem defrag on your whole file system, but that causes all you snapshots to duplicate the data. it also causes a lot of IO so this is nothing you want to do on your production server without a reason. There is really no point in defrag'ing static files that are almost never changed.",{"type":22,"tag":23,"props":119,"children":121},{"id":120},"find-the-most-fragmented-files-on-your-system",[122],{"type":28,"value":123},"Find the most fragmented files on your System",{"type":22,"tag":31,"props":125,"children":126},{},[127,129,134],{"type":28,"value":128},"There is a linux-tool called ",{"type":22,"tag":37,"props":130,"children":131},{},[132],{"type":28,"value":133},"filefrag",{"type":28,"value":135}," which reports how many fragments a file consists of. So i thought ... „why not try to find the most fragmented files and fix just these?“ here you go:",{"type":22,"tag":137,"props":138,"children":142},"pre",{"className":139,"code":140,"language":141,"meta":7,"style":7},"language-bash shiki shiki-themes github-dark github-dark monokai","find / -xdev -type f| xargs filefrag 2>/dev/null | sed 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/' | awk -F ' ' '$1 > 500' | sort -n -r\n","bash",[143],{"type":22,"tag":144,"props":145,"children":146},"code",{"__ignoreMap":7},[147],{"type":22,"tag":148,"props":149,"children":152},"span",{"class":150,"line":151},"line",1,[153,159,165,171,176,181,187,192,197,202,207,212,217,222,226,231,236,241,246,250,255,260],{"type":22,"tag":148,"props":154,"children":156},{"style":155},"--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E",[157],{"type":28,"value":158},"find",{"type":22,"tag":148,"props":160,"children":162},{"style":161},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74",[163],{"type":28,"value":164}," /",{"type":22,"tag":148,"props":166,"children":168},{"style":167},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF",[169],{"type":28,"value":170}," -xdev",{"type":22,"tag":148,"props":172,"children":173},{"style":167},[174],{"type":28,"value":175}," -type",{"type":22,"tag":148,"props":177,"children":178},{"style":161},[179],{"type":28,"value":180}," f",{"type":22,"tag":148,"props":182,"children":184},{"style":183},"--shiki-default:#F97583;--shiki-dark:#F97583;--shiki-sepia:#F92672",[185],{"type":28,"value":186},"|",{"type":22,"tag":148,"props":188,"children":189},{"style":155},[190],{"type":28,"value":191}," xargs",{"type":22,"tag":148,"props":193,"children":194},{"style":161},[195],{"type":28,"value":196}," filefrag",{"type":22,"tag":148,"props":198,"children":199},{"style":183},[200],{"type":28,"value":201}," 2>",{"type":22,"tag":148,"props":203,"children":204},{"style":161},[205],{"type":28,"value":206},"/dev/null",{"type":22,"tag":148,"props":208,"children":209},{"style":183},[210],{"type":28,"value":211}," |",{"type":22,"tag":148,"props":213,"children":214},{"style":155},[215],{"type":28,"value":216}," sed",{"type":22,"tag":148,"props":218,"children":219},{"style":161},[220],{"type":28,"value":221}," 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/'",{"type":22,"tag":148,"props":223,"children":224},{"style":183},[225],{"type":28,"value":211},{"type":22,"tag":148,"props":227,"children":228},{"style":155},[229],{"type":28,"value":230}," awk",{"type":22,"tag":148,"props":232,"children":233},{"style":167},[234],{"type":28,"value":235}," -F",{"type":22,"tag":148,"props":237,"children":238},{"style":161},[239],{"type":28,"value":240}," ' '",{"type":22,"tag":148,"props":242,"children":243},{"style":161},[244],{"type":28,"value":245}," '$1 > 500'",{"type":22,"tag":148,"props":247,"children":248},{"style":183},[249],{"type":28,"value":211},{"type":22,"tag":148,"props":251,"children":252},{"style":155},[253],{"type":28,"value":254}," sort",{"type":22,"tag":148,"props":256,"children":257},{"style":167},[258],{"type":28,"value":259}," -n",{"type":22,"tag":148,"props":261,"children":262},{"style":167},[263],{"type":28,"value":264}," -r\n",{"type":22,"tag":31,"props":266,"children":267},{},[268,270,275,277,281],{"type":28,"value":269},"You should review this list. If there is something with 10k+ extends, it is a candidate to be flagged as ",{"type":22,"tag":37,"props":271,"children":272},{},[273],{"type":28,"value":274},"nodatacow",{"type":28,"value":276},". In my case, I have discovered that the fail2ban sqlite database was using 170k extends which is a lot! If you have database-files with a high fragmentation while using ",{"type":22,"tag":37,"props":278,"children":279},{},[280],{"type":28,"value":274},{"type":28,"value":282},", it is better to run a \"optimize table\" on them, as this also cleans up the database-related fragmentation of frequently rewritten tables. If you use snapshots, make sure to have some free space, as the defrag does an in-place copy of the files while snapshots are blocking the old version from being released.",{"type":22,"tag":23,"props":284,"children":286},{"id":285},"if-everything-is-fine-you-can-go-ahead-and-defrag-all-files-on-that-list",[287],{"type":28,"value":288},"If everything is fine, you can go ahead and defrag all files on that list",{"type":22,"tag":137,"props":290,"children":292},{"className":139,"code":291,"language":141,"meta":7,"style":7},"find / -xdev -type f| xargs filefrag 2>/dev/null | sed 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/' |\nawk -F ' ' '$1 > 500' | cut -d ' ' -f2 2>/dev/null | xargs -r btrfs fi defrag -f -v\n",[293],{"type":22,"tag":144,"props":294,"children":295},{"__ignoreMap":7},[296,356],{"type":22,"tag":148,"props":297,"children":298},{"class":150,"line":151},[299,303,307,311,315,319,323,327,331,335,339,343,347,351],{"type":22,"tag":148,"props":300,"children":301},{"style":155},[302],{"type":28,"value":158},{"type":22,"tag":148,"props":304,"children":305},{"style":161},[306],{"type":28,"value":164},{"type":22,"tag":148,"props":308,"children":309},{"style":167},[310],{"type":28,"value":170},{"type":22,"tag":148,"props":312,"children":313},{"style":167},[314],{"type":28,"value":175},{"type":22,"tag":148,"props":316,"children":317},{"style":161},[318],{"type":28,"value":180},{"type":22,"tag":148,"props":320,"children":321},{"style":183},[322],{"type":28,"value":186},{"type":22,"tag":148,"props":324,"children":325},{"style":155},[326],{"type":28,"value":191},{"type":22,"tag":148,"props":328,"children":329},{"style":161},[330],{"type":28,"value":196},{"type":22,"tag":148,"props":332,"children":333},{"style":183},[334],{"type":28,"value":201},{"type":22,"tag":148,"props":336,"children":337},{"style":161},[338],{"type":28,"value":206},{"type":22,"tag":148,"props":340,"children":341},{"style":183},[342],{"type":28,"value":211},{"type":22,"tag":148,"props":344,"children":345},{"style":155},[346],{"type":28,"value":216},{"type":22,"tag":148,"props":348,"children":349},{"style":161},[350],{"type":28,"value":221},{"type":22,"tag":148,"props":352,"children":353},{"style":183},[354],{"type":28,"value":355}," |\n",{"type":22,"tag":148,"props":357,"children":359},{"class":150,"line":358},2,[360,365,369,373,377,381,386,391,395,400,404,408,412,416,421,426,431,436,441],{"type":22,"tag":148,"props":361,"children":362},{"style":155},[363],{"type":28,"value":364},"awk",{"type":22,"tag":148,"props":366,"children":367},{"style":167},[368],{"type":28,"value":235},{"type":22,"tag":148,"props":370,"children":371},{"style":161},[372],{"type":28,"value":240},{"type":22,"tag":148,"props":374,"children":375},{"style":161},[376],{"type":28,"value":245},{"type":22,"tag":148,"props":378,"children":379},{"style":183},[380],{"type":28,"value":211},{"type":22,"tag":148,"props":382,"children":383},{"style":155},[384],{"type":28,"value":385}," cut",{"type":22,"tag":148,"props":387,"children":388},{"style":167},[389],{"type":28,"value":390}," -d",{"type":22,"tag":148,"props":392,"children":393},{"style":161},[394],{"type":28,"value":240},{"type":22,"tag":148,"props":396,"children":397},{"style":167},[398],{"type":28,"value":399}," -f2",{"type":22,"tag":148,"props":401,"children":402},{"style":183},[403],{"type":28,"value":201},{"type":22,"tag":148,"props":405,"children":406},{"style":161},[407],{"type":28,"value":206},{"type":22,"tag":148,"props":409,"children":410},{"style":183},[411],{"type":28,"value":211},{"type":22,"tag":148,"props":413,"children":414},{"style":155},[415],{"type":28,"value":191},{"type":22,"tag":148,"props":417,"children":418},{"style":167},[419],{"type":28,"value":420}," -r",{"type":22,"tag":148,"props":422,"children":423},{"style":161},[424],{"type":28,"value":425}," btrfs",{"type":22,"tag":148,"props":427,"children":428},{"style":161},[429],{"type":28,"value":430}," fi",{"type":22,"tag":148,"props":432,"children":433},{"style":161},[434],{"type":28,"value":435}," defrag",{"type":22,"tag":148,"props":437,"children":438},{"style":167},[439],{"type":28,"value":440}," -f",{"type":22,"tag":148,"props":442,"children":443},{"style":167},[444],{"type":28,"value":445}," -v\n",{"type":22,"tag":31,"props":447,"children":448},{},[449],{"type":28,"value":450},"This will print out all filenames that are processed.",{"type":22,"tag":23,"props":452,"children":454},{"id":453},"a-short-explanation-of-the-command",[455],{"type":28,"value":456},"A short explanation of the command",{"type":22,"tag":31,"props":458,"children":459},{},[460,464,466,470,472,477,479,484],{"type":22,"tag":37,"props":461,"children":462},{},[463],{"type":28,"value":158},{"type":28,"value":465}," gets all files on the specified path (/) without descending into other mounted filesystems (-xdev). Then ",{"type":22,"tag":37,"props":467,"children":468},{},[469],{"type":28,"value":133},{"type":28,"value":471}," determines the fragmentation, the ",{"type":22,"tag":37,"props":473,"children":474},{},[475],{"type":28,"value":476},"sed",{"type":28,"value":478}," command reformats the output so that the extent count is on first position followed by the filename. Then awk parses that list filtering only files that have more than 500 extends. After that is done, the output is „cut“ to only contain the filenames and passed to btrfs defrag for defragmentation. -v on the ",{"type":22,"tag":37,"props":480,"children":481},{},[482],{"type":28,"value":483},"defrag",{"type":28,"value":485}," command prints out all processed files. Also take a look on the longterm IO usage before and after the defrag to see how big the difference in the real world is.",{"type":22,"tag":23,"props":487,"children":489},{"id":488},"have-fun",[490],{"type":28,"value":491},"Have fun!",{"type":22,"tag":493,"props":494,"children":495},"style",{},[496],{"type":28,"value":497},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":7,"searchDepth":358,"depth":358,"links":499},[500,501,502,503,504,505,506,507],{"id":25,"depth":358,"text":29},{"id":46,"depth":358,"text":49},{"id":57,"depth":358,"text":60},{"id":109,"depth":358,"text":112},{"id":120,"depth":358,"text":123},{"id":285,"depth":358,"text":288},{"id":453,"depth":358,"text":456},{"id":488,"depth":358,"text":491},"markdown","common:en:blog:8.btrfs-finding-and-fixing-highly-fragmented-files.md","common","en/blog/8.btrfs-finding-and-fixing-highly-fragmented-files.md","en/blog/8.btrfs-finding-and-fixing-highly-fragmented-files","md",{"_path":515,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":516,"description":517,"author":10,"image":518,"releaseDate":519,"blogCategories":520,"tags":521,"_type":508,"_id":522,"_source":510,"_file":523,"_stem":524,"_extension":513},"/en/blog/proper-chroot-in-rescue-mode-using-arch-chroot","Proper CHROOT in rescue mode using arch-chroot","Most Sysadmins know how to setup a basic chroot on a mounted filesystem (mount-binding dev, proc and sys) but this does not work in any case; for a complete chroot setup you would aso need dev/pts dev/shm, run, tmp, a working resolve.conf and more. After you have set it up, and you want to bring it ...","/images/linux_os-mono.svg","2020-04-17",[14,15],[17],"common:en:blog:7.proper-chroot-in-rescue-mode-using-arch-chroot.md","en/blog/7.proper-chroot-in-rescue-mode-using-arch-chroot.md","en/blog/7.proper-chroot-in-rescue-mode-using-arch-chroot",{"_path":526,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":527,"description":528,"author":10,"image":529,"releaseDate":530,"blogCategories":531,"articleTags":534,"tags":536,"_type":508,"_id":538,"_source":510,"_file":539,"_stem":540,"_extension":513},"/en/blog/shopware-5-parallel-thumbnail-generation","Shopware 5 – High-Speed Parallel Thumbnail Generation","How to tune the integrated SW5 mechanism to work more then 22 times faster! Shopware 5 - parallel thumbnail generation after moving a Shopware 5 system to another server. We had a customer with 400k images and 1600k thumbnails that needed to move from an old HDD based server to a new SSD …","/images/shopware.svg","2021-04-29",[532,533],"Shopware","DevOps",[535],"VPN",[537],"shopware","common:en:blog:9.shopware-5-parallel-thumbnail-generation.md","en/blog/9.shopware-5-parallel-thumbnail-generation.md","en/blog/9.shopware-5-parallel-thumbnail-generation",{"_path":542},"/blog/btrfs-auffinden-und-reparieren-stark-fragmentierter-dataien",{"_path":4},{"_path":545,"_dir":546,"_draft":6,"_partial":6,"_locale":7,"slug":10,"teams":547,"primaryTeam":549,"firstName":550,"lastName":551,"prefixTitle":7,"suffixTitle":7,"education":552,"executiveRole":557,"role":558,"workingSince":566,"inTheCompanySince":567,"techSkills":568,"skills":613,"projects":626,"contactDetails":639,"_image":643,"image":644,"_id":645,"_type":646,"title":647,"_source":546,"_file":648,"_stem":649,"_extension":646},"/employees/bernd-helm","employees",[548,549],"ai","devOps","Bernd","Helm",[553],[554,555,556],"B. Sc. Angewandte Informatik","FHDW Dresden","2010","CTO",[559,560,549,561,562,563,564,565],"founder","chiefTechnologyOfficer","databaseSpecialist","admin","softwareDeveloper","backendDeveloper","consultant","2005","2008",[569,573,575,577,580,582,585,587,589,591,594,598,601,604,607,610],{"name":570,"level":571,"icon":572},"Docker","expert","/images/Docker.svg",{"name":574,"level":571,"icon":518},"Linux",{"name":576,"level":571},"Zabbix",{"name":578,"level":571,"icon":579},"MariaDB ColumnStore","/images/maria-db-logo.svg",{"name":581,"level":571},"OpenAI",{"name":583,"level":571,"icon":584},"Pytorch","/images/PyTorch.svg",{"name":586,"level":571},"PHP",{"name":588,"level":571},"Java",{"name":590,"level":571},"Python",{"name":592,"level":571,"icon":593},"SQL","/images/SQL.svg",{"name":595,"level":596,"icon":597},"C++","advanced","/images/cpp-logo.svg",{"name":599,"level":596,"icon":600},"C#","/images/csharp.svg",{"name":602,"level":596,"icon":603},"CSS","/images/css.svg",{"name":605,"level":596,"icon":606},"HTML","/images/html.svg",{"name":608,"level":596,"icon":609},"OpenCV","/images/OpenCV.svg",{"name":611,"level":596,"icon":612},"Vue.js","/images/vuejs.svg",[614,616,618,620,622,624],{"name":615,"level":571},"artificialIntelligence",{"name":617,"level":571},"codingGuidelines",{"name":619,"level":571},"databases",{"name":621,"level":571},"linuxServerAdministration",{"name":623,"level":571},"softwareArchitect",{"name":625,"level":596},"qualityAssurance",[627,630,632,634,637],{"project":628,"position":629},"Gridside","Technical Consultant",{"project":631,"position":629},"Herole",{"project":633,"position":629},"Montagespezis",{"project":635,"position":636},"Orsee","Technical Manager",{"project":638,"position":629},"Vipr",{"eMail":640,"phone":641,"visibility":642},"bernd.helm@helmundwalter.de","+49 351 799 035 20","1","images/employees/Portraits/bernd_helm.webp","images/employees/Portraits/BerndHelm_MS.webp","employees:employees:1.bernd-helm.json","json","Bernd Helm","employees/1.bernd-helm.json","employees/1.bernd-helm",{"_path":515,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":516,"description":517,"author":10,"image":518,"releaseDate":519,"blogCategories":651,"tags":652,"body":653,"_type":508,"_id":522,"_source":510,"_file":523,"_stem":524,"_extension":513},[14,15],[17],{"type":19,"children":654,"toc":881},[655,660,665,687,692,744,749,872,877],{"type":22,"tag":31,"props":656,"children":657},{},[658],{"type":28,"value":659},"Most Sysadmins know how to set up a basic chroot on a mounted filesystem (mount-binding dev, proc and sys) but this does not work in any case; for a complete chroot setup you would aso need dev/pts dev/shm, run, tmp, a working resolve.conf and more. After you have set it up, and you want to bring it down, you have to do a lot of typing again. But wait! There is a better solution.",{"type":22,"tag":31,"props":661,"children":662},{},[663],{"type":28,"value":664},"There is a script called arch-chroot shipped with the Archlinux distribution, but it is not limited to be run with Archlinux. It works on any linux distri!",{"type":22,"tag":31,"props":666,"children":667},{},[668,670,677,679,685],{"type":28,"value":669},"For your convenience, I have ",{"type":22,"tag":671,"props":672,"children":674},"a",{"href":673},"https://gist.github.com/bhelm/65283c37a0cb585089041214002df4f7",[675],{"type":28,"value":676},"created a gist",{"type":28,"value":678}," for you. You can also use the Direct ",{"type":22,"tag":671,"props":680,"children":682},{"href":681},"https://gist.githubusercontent.com/bhelm/65283c37a0cb585089041214002df4f7/raw/536099a5f969a6888c85e48a487ec19870c596a2/arch-chroot.sh",[683],{"type":28,"value":684},"download link for wget",{"type":28,"value":686},".",{"type":22,"tag":31,"props":688,"children":689},{},[690],{"type":28,"value":691},"you can install it like this:",{"type":22,"tag":137,"props":693,"children":695},{"className":139,"code":694,"language":141,"meta":7,"style":7},"wget https://gist.githubusercontent.com/bhelm/65283c37a0cb585089041214002df4f7/raw/536099a5f969a6888c85e48a487ec19870c596a2/arch-chroot.sh\nchmod +x arch-chroot.sh\n./arch-chroot.sh -h\n",[696],{"type":22,"tag":144,"props":697,"children":698},{"__ignoreMap":7},[699,712,730],{"type":22,"tag":148,"props":700,"children":701},{"class":150,"line":151},[702,707],{"type":22,"tag":148,"props":703,"children":704},{"style":155},[705],{"type":28,"value":706},"wget",{"type":22,"tag":148,"props":708,"children":709},{"style":161},[710],{"type":28,"value":711}," https://gist.githubusercontent.com/bhelm/65283c37a0cb585089041214002df4f7/raw/536099a5f969a6888c85e48a487ec19870c596a2/arch-chroot.sh\n",{"type":22,"tag":148,"props":713,"children":714},{"class":150,"line":358},[715,720,725],{"type":22,"tag":148,"props":716,"children":717},{"style":155},[718],{"type":28,"value":719},"chmod",{"type":22,"tag":148,"props":721,"children":722},{"style":161},[723],{"type":28,"value":724}," +x",{"type":22,"tag":148,"props":726,"children":727},{"style":161},[728],{"type":28,"value":729}," arch-chroot.sh\n",{"type":22,"tag":148,"props":731,"children":733},{"class":150,"line":732},3,[734,739],{"type":22,"tag":148,"props":735,"children":736},{"style":155},[737],{"type":28,"value":738},"./arch-chroot.sh",{"type":22,"tag":148,"props":740,"children":741},{"style":167},[742],{"type":28,"value":743}," -h\n",{"type":22,"tag":31,"props":745,"children":746},{},[747],{"type":28,"value":748},"Using this script, I was able to install grub without getting errors like:",{"type":22,"tag":137,"props":750,"children":752},{"className":139,"code":751,"language":141,"meta":7,"style":7},"grub-install: error: cannot find a device for /boot/grub (is /dev mounted?).\ngrub-probe: error: cannot find a device for / (is /dev mounted?).\n",[753],{"type":22,"tag":144,"props":754,"children":755},{"__ignoreMap":7},[756,820],{"type":22,"tag":148,"props":757,"children":758},{"class":150,"line":151},[759,764,769,774,779,784,789,794,799,805,810,815],{"type":22,"tag":148,"props":760,"children":761},{"style":155},[762],{"type":28,"value":763},"grub-install:",{"type":22,"tag":148,"props":765,"children":766},{"style":161},[767],{"type":28,"value":768}," error:",{"type":22,"tag":148,"props":770,"children":771},{"style":161},[772],{"type":28,"value":773}," cannot",{"type":22,"tag":148,"props":775,"children":776},{"style":161},[777],{"type":28,"value":778}," find",{"type":22,"tag":148,"props":780,"children":781},{"style":161},[782],{"type":28,"value":783}," a",{"type":22,"tag":148,"props":785,"children":786},{"style":161},[787],{"type":28,"value":788}," device",{"type":22,"tag":148,"props":790,"children":791},{"style":161},[792],{"type":28,"value":793}," for",{"type":22,"tag":148,"props":795,"children":796},{"style":161},[797],{"type":28,"value":798}," /boot/grub",{"type":22,"tag":148,"props":800,"children":802},{"style":801},"--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2",[803],{"type":28,"value":804}," (is ",{"type":22,"tag":148,"props":806,"children":807},{"style":161},[808],{"type":28,"value":809},"/dev",{"type":22,"tag":148,"props":811,"children":812},{"style":161},[813],{"type":28,"value":814}," mounted?",{"type":22,"tag":148,"props":816,"children":817},{"style":801},[818],{"type":28,"value":819},").\n",{"type":22,"tag":148,"props":821,"children":822},{"class":150,"line":358},[823,828,832,836,840,844,848,852,856,860,864,868],{"type":22,"tag":148,"props":824,"children":825},{"style":155},[826],{"type":28,"value":827},"grub-probe:",{"type":22,"tag":148,"props":829,"children":830},{"style":161},[831],{"type":28,"value":768},{"type":22,"tag":148,"props":833,"children":834},{"style":161},[835],{"type":28,"value":773},{"type":22,"tag":148,"props":837,"children":838},{"style":161},[839],{"type":28,"value":778},{"type":22,"tag":148,"props":841,"children":842},{"style":161},[843],{"type":28,"value":783},{"type":22,"tag":148,"props":845,"children":846},{"style":161},[847],{"type":28,"value":788},{"type":22,"tag":148,"props":849,"children":850},{"style":161},[851],{"type":28,"value":793},{"type":22,"tag":148,"props":853,"children":854},{"style":161},[855],{"type":28,"value":164},{"type":22,"tag":148,"props":857,"children":858},{"style":801},[859],{"type":28,"value":804},{"type":22,"tag":148,"props":861,"children":862},{"style":161},[863],{"type":28,"value":809},{"type":22,"tag":148,"props":865,"children":866},{"style":161},[867],{"type":28,"value":814},{"type":22,"tag":148,"props":869,"children":870},{"style":801},[871],{"type":28,"value":819},{"type":22,"tag":31,"props":873,"children":874},{},[875],{"type":28,"value":876},"If you are looking for a perfect rescue system, i recommend the archlinux install image; it contains the arch-chroot script, all low level tools needed to format hard drives and even supports mounting of ntfs read-write and accessing samba shares.",{"type":22,"tag":493,"props":878,"children":879},{},[880],{"type":28,"value":497},{"title":7,"searchDepth":358,"depth":358,"links":882},[],{"_path":526,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":527,"description":528,"author":10,"image":529,"releaseDate":530,"blogCategories":884,"articleTags":885,"tags":886,"body":887,"_type":508,"_id":538,"_source":510,"_file":539,"_stem":540,"_extension":513},[532,533],[535],[537],{"type":19,"children":888,"toc":1403},[889,895,900,911,916,922,927,946,955,960,965,1303,1308,1313,1318,1323,1335,1385,1393,1399],{"type":22,"tag":23,"props":890,"children":892},{"id":891},"shopware-5-parallel-thumbnail-generation-after-moving-a-shopware-5-system-to-another-server",[893],{"type":28,"value":894},"Shopware 5 - parallel thumbnail generation after moving a Shopware 5 system to another server",{"type":22,"tag":31,"props":896,"children":897},{},[898],{"type":28,"value":899},"We had a customer with 400k images and 1600k thumbnails that needed to move from an old hdd based server to a new ssd based one. The problem was that the old server was so slow that it already needed two days to count through all images, not speaking about coping them.",{"type":22,"tag":31,"props":901,"children":902},{},[903,905],{"type":28,"value":904},"So we decided to copy only the original images and regenerate the Thumbnails. For copying the original images, I created a small console command that exports all paths of the original images that we need to copy: ",{"type":22,"tag":671,"props":906,"children":908},{"href":907},"https://gist.github.com/bhelm/2d30f0cebcf4a7d8ea41c532ec67cd62",[909],{"type":28,"value":910},"ExportImagesCommand.php",{"type":22,"tag":31,"props":912,"children":913},{},[914],{"type":28,"value":915},"This filelist can be used with tar -T or rsync --files-from= options that tells these tools to only process the listed files. for the initial copy process, tar is highly recommended, as it just picks up the files listed without doing any \"calculation\" as rsync does.",{"type":22,"tag":23,"props":917,"children":919},{"id":918},"sw5-default-thumbnail-generation-would-have-taken-80-hours",[920],{"type":28,"value":921},"SW5 default thumbnail generation would have taken 80 hours",{"type":22,"tag":31,"props":923,"children":924},{},[925],{"type":28,"value":926},"... and would only use half of a core.",{"type":22,"tag":31,"props":928,"children":929},{},[930,932,937,939,944],{"type":28,"value":931},"I was curious if I can speed up this generation process. The server itself has 32 cores available, so I copied the ",{"type":22,"tag":37,"props":933,"children":934},{},[935],{"type":28,"value":936},"generate thumbnail",{"type":28,"value":938}," command from sw5 and modified it to work in batches with an ",{"type":22,"tag":37,"props":940,"children":941},{},[942],{"type":28,"value":943},"--batch",{"type":28,"value":945}," parameter:",{"type":22,"tag":31,"props":947,"children":948},{},[949],{"type":22,"tag":671,"props":950,"children":952},{"href":951},"https://gist.github.com/bhelm/2015d3829d4a3f24f9760f6e4e1aac1f",[953],{"type":28,"value":954},"ParallelThumbnailGenerateCommand.php",{"type":22,"tag":31,"props":956,"children":957},{},[958],{"type":28,"value":959},"To make it work, I just modified the Shopware core at engine/Shopware/Models/Media/Repository.php",{"type":22,"tag":31,"props":961,"children":962},{},[963],{"type":28,"value":964},"I just changed the getAlbumMediaQuery function to:",{"type":22,"tag":137,"props":966,"children":970},{"className":967,"code":968,"language":969,"meta":7,"style":7},"language-cpp shiki shiki-themes github-dark github-dark monokai","public function getAlbumMediaQuery($albumId, $filter = null, $orderBy = null, $offset = null, $limit = null, $validTypes = null, $batch = null)\n{\n$builder = $this->getAlbumMediaQueryBuilder($albumId, $filter, $orderBy, $validTypes);\nif (is_numeric($batch)) {\n$builder->andWhere('MOD(media.id, 1000) = ?3');\n$builder->setParameter(3, $batch);\n}\n\n    if ($limit !== null) {\n        $builder->setFirstResult($offset)\n                ->setMaxResults($limit);\n    }\n\n    return $builder->getQuery();\n}\n","cpp",[971],{"type":22,"tag":144,"props":972,"children":973},{"__ignoreMap":7},[974,1047,1055,1093,1117,1146,1173,1182,1192,1216,1235,1254,1263,1271,1295],{"type":22,"tag":148,"props":975,"children":976},{"class":150,"line":151},[977,982,987,992,997,1002,1006,1011,1015,1020,1024,1029,1033,1038,1042],{"type":22,"tag":148,"props":978,"children":979},{"style":801},[980],{"type":28,"value":981},"public function ",{"type":22,"tag":148,"props":983,"children":984},{"style":155},[985],{"type":28,"value":986},"getAlbumMediaQuery",{"type":22,"tag":148,"props":988,"children":989},{"style":801},[990],{"type":28,"value":991},"($albumId, $filter ",{"type":22,"tag":148,"props":993,"children":994},{"style":183},[995],{"type":28,"value":996},"=",{"type":22,"tag":148,"props":998,"children":999},{"style":801},[1000],{"type":28,"value":1001}," null, $orderBy ",{"type":22,"tag":148,"props":1003,"children":1004},{"style":183},[1005],{"type":28,"value":996},{"type":22,"tag":148,"props":1007,"children":1008},{"style":801},[1009],{"type":28,"value":1010}," null, $offset ",{"type":22,"tag":148,"props":1012,"children":1013},{"style":183},[1014],{"type":28,"value":996},{"type":22,"tag":148,"props":1016,"children":1017},{"style":801},[1018],{"type":28,"value":1019}," null, $limit ",{"type":22,"tag":148,"props":1021,"children":1022},{"style":183},[1023],{"type":28,"value":996},{"type":22,"tag":148,"props":1025,"children":1026},{"style":801},[1027],{"type":28,"value":1028}," null, $validTypes ",{"type":22,"tag":148,"props":1030,"children":1031},{"style":183},[1032],{"type":28,"value":996},{"type":22,"tag":148,"props":1034,"children":1035},{"style":801},[1036],{"type":28,"value":1037}," null, $batch ",{"type":22,"tag":148,"props":1039,"children":1040},{"style":183},[1041],{"type":28,"value":996},{"type":22,"tag":148,"props":1043,"children":1044},{"style":801},[1045],{"type":28,"value":1046}," null)\n",{"type":22,"tag":148,"props":1048,"children":1049},{"class":150,"line":358},[1050],{"type":22,"tag":148,"props":1051,"children":1052},{"style":801},[1053],{"type":28,"value":1054},"{\n",{"type":22,"tag":148,"props":1056,"children":1057},{"class":150,"line":732},[1058,1063,1067,1072,1078,1083,1088],{"type":22,"tag":148,"props":1059,"children":1060},{"style":801},[1061],{"type":28,"value":1062},"$builder ",{"type":22,"tag":148,"props":1064,"children":1065},{"style":183},[1066],{"type":28,"value":996},{"type":22,"tag":148,"props":1068,"children":1069},{"style":801},[1070],{"type":28,"value":1071}," $",{"type":22,"tag":148,"props":1073,"children":1075},{"style":1074},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#FD971F",[1076],{"type":28,"value":1077},"this",{"type":22,"tag":148,"props":1079,"children":1080},{"style":801},[1081],{"type":28,"value":1082},"->",{"type":22,"tag":148,"props":1084,"children":1085},{"style":155},[1086],{"type":28,"value":1087},"getAlbumMediaQueryBuilder",{"type":22,"tag":148,"props":1089,"children":1090},{"style":801},[1091],{"type":28,"value":1092},"($albumId, $filter, $orderBy, $validTypes);\n",{"type":22,"tag":148,"props":1094,"children":1096},{"class":150,"line":1095},4,[1097,1102,1107,1112],{"type":22,"tag":148,"props":1098,"children":1099},{"style":183},[1100],{"type":28,"value":1101},"if",{"type":22,"tag":148,"props":1103,"children":1104},{"style":801},[1105],{"type":28,"value":1106}," (",{"type":22,"tag":148,"props":1108,"children":1109},{"style":155},[1110],{"type":28,"value":1111},"is_numeric",{"type":22,"tag":148,"props":1113,"children":1114},{"style":801},[1115],{"type":28,"value":1116},"($batch)) {\n",{"type":22,"tag":148,"props":1118,"children":1120},{"class":150,"line":1119},5,[1121,1126,1131,1136,1141],{"type":22,"tag":148,"props":1122,"children":1123},{"style":801},[1124],{"type":28,"value":1125},"$builder->",{"type":22,"tag":148,"props":1127,"children":1128},{"style":155},[1129],{"type":28,"value":1130},"andWhere",{"type":22,"tag":148,"props":1132,"children":1133},{"style":801},[1134],{"type":28,"value":1135},"(",{"type":22,"tag":148,"props":1137,"children":1138},{"style":161},[1139],{"type":28,"value":1140},"'MOD(media.id, 1000) = ?3'",{"type":22,"tag":148,"props":1142,"children":1143},{"style":801},[1144],{"type":28,"value":1145},");\n",{"type":22,"tag":148,"props":1147,"children":1149},{"class":150,"line":1148},6,[1150,1154,1159,1163,1168],{"type":22,"tag":148,"props":1151,"children":1152},{"style":801},[1153],{"type":28,"value":1125},{"type":22,"tag":148,"props":1155,"children":1156},{"style":155},[1157],{"type":28,"value":1158},"setParameter",{"type":22,"tag":148,"props":1160,"children":1161},{"style":801},[1162],{"type":28,"value":1135},{"type":22,"tag":148,"props":1164,"children":1165},{"style":167},[1166],{"type":28,"value":1167},"3",{"type":22,"tag":148,"props":1169,"children":1170},{"style":801},[1171],{"type":28,"value":1172},", $batch);\n",{"type":22,"tag":148,"props":1174,"children":1176},{"class":150,"line":1175},7,[1177],{"type":22,"tag":148,"props":1178,"children":1179},{"style":801},[1180],{"type":28,"value":1181},"}\n",{"type":22,"tag":148,"props":1183,"children":1185},{"class":150,"line":1184},8,[1186],{"type":22,"tag":148,"props":1187,"children":1189},{"emptyLinePlaceholder":1188},true,[1190],{"type":28,"value":1191},"\n",{"type":22,"tag":148,"props":1193,"children":1195},{"class":150,"line":1194},9,[1196,1201,1206,1211],{"type":22,"tag":148,"props":1197,"children":1198},{"style":183},[1199],{"type":28,"value":1200},"    if",{"type":22,"tag":148,"props":1202,"children":1203},{"style":801},[1204],{"type":28,"value":1205}," ($limit ",{"type":22,"tag":148,"props":1207,"children":1208},{"style":183},[1209],{"type":28,"value":1210},"!==",{"type":22,"tag":148,"props":1212,"children":1213},{"style":801},[1214],{"type":28,"value":1215}," null) {\n",{"type":22,"tag":148,"props":1217,"children":1219},{"class":150,"line":1218},10,[1220,1225,1230],{"type":22,"tag":148,"props":1221,"children":1222},{"style":801},[1223],{"type":28,"value":1224},"        $builder->",{"type":22,"tag":148,"props":1226,"children":1227},{"style":155},[1228],{"type":28,"value":1229},"setFirstResult",{"type":22,"tag":148,"props":1231,"children":1232},{"style":801},[1233],{"type":28,"value":1234},"($offset)\n",{"type":22,"tag":148,"props":1236,"children":1238},{"class":150,"line":1237},11,[1239,1244,1249],{"type":22,"tag":148,"props":1240,"children":1241},{"style":183},[1242],{"type":28,"value":1243},"                ->",{"type":22,"tag":148,"props":1245,"children":1246},{"style":155},[1247],{"type":28,"value":1248},"setMaxResults",{"type":22,"tag":148,"props":1250,"children":1251},{"style":801},[1252],{"type":28,"value":1253},"($limit);\n",{"type":22,"tag":148,"props":1255,"children":1257},{"class":150,"line":1256},12,[1258],{"type":22,"tag":148,"props":1259,"children":1260},{"style":801},[1261],{"type":28,"value":1262},"    }\n",{"type":22,"tag":148,"props":1264,"children":1266},{"class":150,"line":1265},13,[1267],{"type":22,"tag":148,"props":1268,"children":1269},{"emptyLinePlaceholder":1188},[1270],{"type":28,"value":1191},{"type":22,"tag":148,"props":1272,"children":1274},{"class":150,"line":1273},14,[1275,1280,1285,1290],{"type":22,"tag":148,"props":1276,"children":1277},{"style":183},[1278],{"type":28,"value":1279},"    return",{"type":22,"tag":148,"props":1281,"children":1282},{"style":801},[1283],{"type":28,"value":1284}," $builder->",{"type":22,"tag":148,"props":1286,"children":1287},{"style":155},[1288],{"type":28,"value":1289},"getQuery",{"type":22,"tag":148,"props":1291,"children":1292},{"style":801},[1293],{"type":28,"value":1294},"();\n",{"type":22,"tag":148,"props":1296,"children":1298},{"class":150,"line":1297},15,[1299],{"type":22,"tag":148,"props":1300,"children":1301},{"style":801},[1302],{"type":28,"value":1181},{"type":22,"tag":31,"props":1304,"children":1305},{},[1306],{"type":28,"value":1307},"It is an optional parameter and won’t break anything. If you do a Shopware update, this would be gone, but as I was in the quest to speed up things for a one-time task, I just modified it in the core instead of finding a long-term solution.",{"type":22,"tag":31,"props":1309,"children":1310},{},[1311],{"type":28,"value":1312},"What this function does is calculating a modulo of 1000 on the media id and compares it with the batch id. So we basically have 1000 batches to process until all work is done.",{"type":22,"tag":31,"props":1314,"children":1315},{},[1316],{"type":28,"value":1317},"Now we only need to start all 1000 batches in a parallel manner. For doing so, I used the very helpful tool parallel - which is available in Linux:",{"type":22,"tag":31,"props":1319,"children":1320},{},[1321],{"type":28,"value":1322},"It starts 64 batches in parallel and continues its work until all 1000 batches are finished.",{"type":22,"tag":31,"props":1324,"children":1325},{},[1326,1328,1333],{"type":28,"value":1327},"And this is how it looks at ",{"type":22,"tag":37,"props":1329,"children":1330},{},[1331],{"type":28,"value":1332},"htop",{"type":28,"value":1334},":",{"type":22,"tag":137,"props":1336,"children":1338},{"className":139,"code":1337,"language":141,"meta":7,"style":7},"parallel -j 64 ./bin/console my:image:generate:thumbnails --batch ::: {0..999}\n",[1339],{"type":22,"tag":144,"props":1340,"children":1341},{"__ignoreMap":7},[1342],{"type":22,"tag":148,"props":1343,"children":1344},{"class":150,"line":151},[1345,1350,1355,1360,1365,1370,1375,1380],{"type":22,"tag":148,"props":1346,"children":1347},{"style":155},[1348],{"type":28,"value":1349},"parallel",{"type":22,"tag":148,"props":1351,"children":1352},{"style":167},[1353],{"type":28,"value":1354}," -j",{"type":22,"tag":148,"props":1356,"children":1357},{"style":167},[1358],{"type":28,"value":1359}," 64",{"type":22,"tag":148,"props":1361,"children":1362},{"style":161},[1363],{"type":28,"value":1364}," ./bin/console",{"type":22,"tag":148,"props":1366,"children":1367},{"style":161},[1368],{"type":28,"value":1369}," my:image:generate:thumbnails",{"type":22,"tag":148,"props":1371,"children":1372},{"style":167},[1373],{"type":28,"value":1374}," --batch",{"type":22,"tag":148,"props":1376,"children":1377},{"style":161},[1378],{"type":28,"value":1379}," :::",{"type":22,"tag":148,"props":1381,"children":1382},{"style":161},[1383],{"type":28,"value":1384}," {0..999}\n",{"type":22,"tag":1386,"props":1387,"children":1392},"img",{"alt":1332,"aspect-ratio":1388,"height":1389,"object-fit":1390,"src":1391},"2",300,"contain","/blog/htop.png",[],{"type":22,"tag":23,"props":1394,"children":1396},{"id":1395},"finally-all-the-work-is-now-finished-in-35-hours-instead-of-80",[1397],{"type":28,"value":1398},"Finally, all the work is now finished in 3.5 hours instead of 80.",{"type":22,"tag":493,"props":1400,"children":1401},{},[1402],{"type":28,"value":497},{"title":7,"searchDepth":358,"depth":358,"links":1404},[1405,1406,1407],{"id":891,"depth":358,"text":894},{"id":918,"depth":358,"text":921},{"id":1395,"depth":358,"text":1398},{"_path":545,"_dir":546,"_draft":6,"_partial":6,"_locale":7,"slug":10,"teams":1409,"primaryTeam":549,"firstName":550,"lastName":551,"prefixTitle":7,"suffixTitle":7,"education":1410,"executiveRole":557,"role":1412,"workingSince":566,"inTheCompanySince":567,"techSkills":1413,"skills":1430,"projects":1437,"contactDetails":1443,"_image":643,"image":644,"_id":645,"_type":646,"title":647,"_source":546,"_file":648,"_stem":649,"_extension":646},[548,549],[1411],[554,555,556],[559,560,549,561,562,563,564,565],[1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429],{"name":570,"level":571,"icon":572},{"name":574,"level":571,"icon":518},{"name":576,"level":571},{"name":578,"level":571,"icon":579},{"name":581,"level":571},{"name":583,"level":571,"icon":584},{"name":586,"level":571},{"name":588,"level":571},{"name":590,"level":571},{"name":592,"level":571,"icon":593},{"name":595,"level":596,"icon":597},{"name":599,"level":596,"icon":600},{"name":602,"level":596,"icon":603},{"name":605,"level":596,"icon":606},{"name":608,"level":596,"icon":609},{"name":611,"level":596,"icon":612},[1431,1432,1433,1434,1435,1436],{"name":615,"level":571},{"name":617,"level":571},{"name":619,"level":571},{"name":621,"level":571},{"name":623,"level":571},{"name":625,"level":596},[1438,1439,1440,1441,1442],{"project":628,"position":629},{"project":631,"position":629},{"project":633,"position":629},{"project":635,"position":636},{"project":638,"position":629},{"eMail":640,"phone":641,"visibility":642},[1445,1459],{"_path":1446,"_dir":1447,"_draft":6,"_partial":1188,"_locale":7,"name":1448,"slug":1447,"text":1449,"hoverText":1450,"image":1451,"customer":1448,"tags":1452,"_id":1454,"_type":1455,"title":1456,"_source":510,"_file":1457,"_stem":1458,"_extension":1455},"/en/portfolio/pixelx/_teaser","pixelx","PixelX","IT Security with Precision and Expertise","For PixelX, we conducted a targeted security analysis where, thanks to our deep technical understanding, we were able to identify a critical SQL injection vulnerability. With minimal time investment, we achieved maximum security gain.","/images/portfolio/pixelx/pixelx_secured.png",[1453,17],"security","common:en:portfolio:9010.pixelx:_teaser.yaml","yaml","Teaser","en/portfolio/9010.pixelx/_teaser.yaml","en/portfolio/9010.pixelx/_teaser",{"_path":1460,"_dir":1461,"_draft":6,"_partial":1188,"_locale":7,"name":1462,"slug":1461,"text":1463,"hoverText":1464,"image":1465,"customer":1462,"tags":1466,"_id":1467,"_type":1455,"title":1456,"_source":510,"_file":1468,"_stem":1469,"_extension":1455},"/en/portfolio/slimspots/_teaser","slimspots","SlimSpots","Processing large amounts of data in real-time","For SlimSpots, a global provider of ad marketing solutions, we developed a highly scalable infrastructure that enables the processing of trillions of data records in real-time.","/images/portfolio/slimspots/slim_spots_prtfolio.png",[619,17],"common:en:portfolio:9020.slimspots:_teaser.yaml","en/portfolio/9020.slimspots/_teaser.yaml","en/portfolio/9020.slimspots/_teaser",1782284053670]