2010-08-31 два проблема
Tuesday, August 31st, 2010И малко по работа – занимавах се с два проблема тия дни, които заслужават малко внимание.
Единия е свързан с thread-ове, сигнали и libc I/O. Ситуацията излеждаше в общи линии по следния начин – един демон с няколко thread-а, които пишат в log, който пък се re-open-ва в един signal handler. Има един lock, който се ползва за друга синхронизация, колкото да направи нещата по-весели.
Накратко изводът е “не правете така”. В signal handler нищо не трябва да се прави, освен може би да се пипне някоя глобална променлива, ползвана като семафор, иначе се получава deadlock, който е бая сложен за откриване (виждате няколко thread-а, висящи във futex() и почти нищо друго), понеже и lock-овете съвсем не са ясни (понеже са вътре в libc, а семантиката на futex е бая крива, в man-а даже си пише – това иска и малко асемблер да се ползва, предназначено е за lib-ове, не за простосмъртни).
Вторият проблем оправих преди малко и е един от най-глупавите, в които съм се набивал (и съм си причинявал сам). Имаме в общи линии следния код:
int a,b,crap;
log=fopen("/path/to/log",a);
while (!feof(log))
{
// log format: 120102121 25 1024
// timestamp seconds bytes
fscanf(log,"%d %d %d",&crap,&a,&b);
// do something
}
който в общи линии обработва един log, обръща го в sql заявки и го насипва в една база. Изведнъж започна да не свършва работа – като в началото реших, че базата се претоварва и не успява да поеме всичките (около 800 000) заявки. След половин ден тестове (и няколко други неща за оправяне, с почивки) най-накрая открих проблема – в log формата изведнъж (е, не особено изведнъж, написано беше преди месец, сега случайно беше пуснато в действие) изведнъж се появило още едно поле, което води до fscanf да не прочете нищо и същевременно feof() да не познае, че файла е свършил.
Решенията са две – или да се проверява колко точно елемента е прочел fscanf(), или да се оправи какво точно се чете. За момента е второто, поне докато не си измисля малко по-хубав начин от първия.