Changes On Branch label_linkedlist
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch label_linkedlist Excluding Merge-Ins

This is equivalent to a diff from e2ebb1f5ca to 58a02a2e4a

2011-09-13
16:43
Getting in the changes reducing the leak on annotate. In the fossil mailing list, I received only opinions in favour of getting mallocs and frees properly paired, so I think noone will refuse the change. check-in: 7870a89b10 user: viriketo tags: annotate_noleak
2011-09-06
20:30
Documenting the Label structure I introduced. Closed-Leaf check-in: 58a02a2e4a user: viriketo tags: label_linkedlist
2011-09-04
22:14
Implementation of a linked list to solve the memory leak described in a TODO in [e2ebb1f5cae8].    This code is slower than having the memory leak, and at the end, it was not a big memory leak. Let's say, 10 byte per revision involved in a file annotate. If a file has 30000 revisions, it may go around 300KB then.    For this leak to be noticeable ... check-in: ef8266b710 user: viriketo tags: label_linkedlist
21:39
Reducing the leak of annotate even more.    I wrote a TODO in the file, for a leak still present and relevant for files modified by many versions, but that requires harder work to get right. check-in: e2ebb1f5ca user: viriketo tags: annotate_noleak
21:02
Making annotate not segfault for the complex test case I have. There is still a little leak... but muuuch smaller than it was. check-in: fa760a24cd user: viriketo tags: annotate_noleak

Changes to src/diff.c.

   617    617   }
   618    618   
   619    619   /**************************************************************************
   620    620   ** The basic difference engine is above.  What follows is the annotation
   621    621   ** engine.  Both are in the same file since they share many components.
   622    622   */
   623    623   
          624  +/*
          625  +** Linked list of strings, labels used in the annotator code.
          626  +** The elements of the list and the pointed string (str)
          627  +** will be freed once they become totally unreferenced
          628  +** (nref == 0).
          629  +*/
          630  +struct Label
          631  +{
          632  +    struct Label *prev;   /* previous element */
          633  +    struct Label *next;   /* next element */
          634  +    char *str;            /* The label string */
          635  +    int nref;             /* Number of references to the string */
          636  +};
          637  +
   624    638   /*
   625    639   ** The status of an annotation operation is recorded by an instance
   626    640   ** of the following structure.
   627    641   */
   628    642   typedef struct Annotator Annotator;
   629    643   struct Annotator {
   630    644     DContext c;       /* The diff-engine context */
   631    645     struct AnnLine {  /* Lines of the original files... */
   632    646       const char *z;       /* The text of the line */
   633    647       short int n;         /* Number of bytes (omitting trailing space and \n) */
   634    648       short int iLevel;    /* Level at which tag was set */
   635         -    const char *zSrc;    /* Tag showing origin of this line */
          649  +    struct Label *zSrc;    /* Tag showing origin of this line */
   636    650     } *aOrig;
   637    651     int nOrig;        /* Number of elements in aOrig[] */
   638    652     int nNoSrc;       /* Number of entries where aOrig[].zSrc==NULL */
   639    653     int iLevel;       /* Current level */
   640    654     int nVers;        /* Number of versions analyzed */
   641         -  char **azVers;    /* Names of versions analyzed */
          655  +  struct Label **azVers;    /* Names of versions analyzed */
   642    656     Blob toAnnotate;
          657  +  struct Label *firstLabel;
   643    658   };
   644    659   
   645    660   /*
   646    661   ** Initialize the annotation process by specifying the file that is
   647    662   ** to be annotated.  The annotator takes control of the input Blob and
   648    663   ** will release it when it is finished with it.
   649    664   */
................................................................................
   668    683   /*
   669    684   ** The input pParent is the next most recent ancestor of the file
   670    685   ** being annotated.  Do another step of the annotation.  Return true
   671    686   ** if additional annotation is required.  zPName is the tag to insert
   672    687   ** on each line of the file being annotated that was contributed by
   673    688   ** pParent.  Memory to hold zPName is leaked.
   674    689   */
   675         -static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
          690  +static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){
   676    691     int i, j;
   677    692     int lnTo;
   678    693     int iPrevLevel;
   679    694     int iThisLevel;
   680    695   
   681    696     /* Prepare the parent file to be diffed */
   682    697     p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
................................................................................
   696    711     iPrevLevel = p->iLevel;
   697    712     p->iLevel++;
   698    713     iThisLevel = p->iLevel;
   699    714     for(i=lnTo=0; i<p->c.nEdit; i+=3){
   700    715       struct AnnLine *x = &p->aOrig[lnTo];
   701    716       for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){
   702    717         if( x->zSrc==0 || x->iLevel==iPrevLevel ){
   703         -         /* TODO: handle zPName so we can free labels
   704         -          * if they get totally unreferenced in the Annotator */
          718  +         if (x->zSrc!=0)
          719  +         {
          720  +           if(--x->zSrc->nref == 0)
          721  +           {
          722  +               free(x->zSrc->str);
          723  +               x->zSrc->prev->next = x->zSrc->next;
          724  +               x->zSrc->next->prev = x->zSrc->prev;
          725  +               free(x->zSrc);
          726  +           }
          727  +         }
   705    728            x->zSrc = zPName;
          729  +         ++zPName->nref;
   706    730            x->iLevel = iThisLevel;
   707    731         }
   708    732       }
   709    733       lnTo += p->c.aEdit[i+2];
   710    734     }
   711    735   
   712    736     /* Clear out the diff results */
................................................................................
   737    761     memset(&x, 0, sizeof(x));
   738    762     x.toAnnotate = empty_blob;
   739    763     content_get(name_to_rid(g.argv[2]), &x.toAnnotate);
   740    764     if( annotation_start(&x) ){
   741    765       fossil_fatal("binary file");
   742    766     }
   743    767     for(i=3; i<g.argc; i++){
          768  +    struct Label *l;
   744    769       blob_zero(&b);
   745    770       content_get(name_to_rid(g.argv[i]), &b);
   746         -    if( annotation_step(&x, &b, g.argv[i-1]) ){
          771  +    l = fossil_malloc(sizeof(*l));
          772  +    l->str = g.argv[i-1];
          773  +    l->nref = 0;
          774  +    l->next = x.firstLabel;
          775  +    if (x.firstLabel)
          776  +      x.firstLabel->prev = l;
          777  +    x.firstLabel = l;
          778  +    if( annotation_step(&x, &b, l) ){
   747    779         fossil_fatal("binary file");
   748    780       }
   749    781     }
   750    782     for(i=0; i<x.nOrig; i++){
   751         -    const char *zSrc = x.aOrig[i].zSrc;
          783  +    const char *zSrc = x.aOrig[i].zSrc->str;
   752    784       if( zSrc==0 ) zSrc = g.argv[g.argc-1];
   753    785       fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
          786  +  }
          787  +  while(x.firstLabel) {
          788  +    struct Label *l;
          789  +    l = x.firstLabel->next;
          790  +    assert(x.firstLabel->nref > 0);
          791  +    free(x.firstLabel->str);
          792  +    free(x.firstLabel);
          793  +    x.firstLabel = l;
   754    794     }
   755    795   }
   756    796   
   757    797   /* Annotation flags */
   758    798   #define ANN_FILE_VERS  0x001  /* Show file version rather than commit version */
   759    799   
   760    800   /*
................................................................................
   768    808     int mid,             /* Use the version of the file in this check-in */
   769    809     int webLabel,        /* Use web-style annotations if true */
   770    810     int iLimit,          /* Limit the number of levels if greater than zero */
   771    811     int annFlags         /* Flags to alter the annotation */
   772    812   ){
   773    813     Blob step = empty_blob;           /* Text of previous revision */
   774    814     int rid;             /* Artifact ID of the file being annotated */
   775         -  char *zLabel;        /* Label to apply to a line */
   776    815     Stmt q;              /* Query returning all ancestor versions */
   777    816   
   778    817     /* Initialize the annotation */
   779    818     rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
   780    819     if( rid==0 ){
   781    820       fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
   782    821     }
................................................................................
   806    845       iLimit>0 ? iLimit : 10000000
   807    846     );
   808    847     while( db_step(&q)==SQLITE_ROW ){
   809    848       int pid = db_column_int(&q, 0);
   810    849       const char *zUuid = db_column_text(&q, 1);
   811    850       const char *zDate = db_column_text(&q, 2);
   812    851       const char *zUser = db_column_text(&q, 3);
          852  +    struct Label *l = fossil_malloc(sizeof(*l));
          853  +    l->nref = 0;
          854  +    l->next = p->firstLabel;
          855  +    if (p->firstLabel)
          856  +      p->firstLabel->prev = l;
   813    857       if( webLabel ){
   814         -      zLabel = mprintf(
          858  +      l->str = mprintf(
   815    859             "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", 
   816    860             g.zTop, zUuid, zUuid, zDate, zUser
   817    861         );
   818    862       }else{
   819         -      zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
          863  +      l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
   820    864       }
          865  +    p->firstLabel = l;
   821    866       p->nVers++;
   822    867       p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
   823         -    p->azVers[p->nVers-1] = zLabel;
          868  +    p->azVers[p->nVers-1] = l;
   824    869       content_get(pid, &step);
   825         -    annotation_step(p, &step, zLabel);
          870  +    annotation_step(p, &step, l);
          871  +    if (l->nref == 0)
          872  +      free(l->str);
   826    873       blob_reset(&step);
   827    874     }
   828    875     db_finalize(&q);
   829    876     free(p->c.aTo);
   830    877   }
   831    878   
   832    879   /*
................................................................................
   858    905     if( P("filevers") ) annFlags |= ANN_FILE_VERS;
   859    906     annotate_file(&ann, fnid, mid, g.okHistory, iLimit, annFlags);
   860    907     if( P("log") ){
   861    908       int i;
   862    909       @ <h2>Versions analyzed:</h2>
   863    910       @ <ol>
   864    911       for(i=0; i<ann.nVers; i++){
   865         -      @ <li><tt>%s(ann.azVers[i])</tt></li>
          912  +      @ <li><tt>%s(ann.azVers[i]->str)</tt></li>
   866    913       }
   867    914       @ </ol>
   868    915       @ <hr>
   869    916       @ <h2>Annotation:</h2>
   870    917     }
   871    918     @ <pre>
   872    919     for(i=0; i<ann.nOrig; i++){
   873    920       ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
   874         -    @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z)
          921  +    @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z)
   875    922     }
   876    923     @ </pre>
   877    924     style_footer();
   878    925   }
   879    926   
   880    927   /*
   881    928   ** COMMAND: annotate
................................................................................
   928    975     if( mid==0 ){
   929    976       fossil_panic("unable to find manifest");
   930    977     }
   931    978     if( fileVers ) annFlags |= ANN_FILE_VERS;
   932    979     annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
   933    980     if( showLog ){
   934    981       for(i=0; i<ann.nVers; i++){
   935         -      printf("version %3d: %s\n", i+1, ann.azVers[i]);
          982  +      printf("version %3d: %s\n", i+1, ann.azVers[i]->str);
   936    983       }
   937    984       printf("---------------------------------------------------\n");
   938    985     }
   939    986     for(i=0; i<ann.nOrig; i++){
   940    987       fossil_print("%s: %.*s\n", 
   941         -                 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
          988  +                 ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z);
   942    989     }
   943    990     free(ann.azVers);
   944    991     free(ann.aOrig);
   945    992     blob_reset(&ann.toAnnotate);
          993  +  while(ann.firstLabel) {
          994  +    struct Label *l;
          995  +    l = ann.firstLabel->next;
          996  +    assert(ann.firstLabel->nref > 0);
          997  +    free(ann.firstLabel->str);
          998  +    free(ann.firstLabel);
          999  +    ann.firstLabel = l;
         1000  +  }
   946   1001   }