Fossil

Changes On Branch label_linkedlist
Login

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 (as we have a content cache until 50MB), it would mean having above a milion revisions for the file annotated. So, I keep this in a branch apart, as maybe the leak is worth the faster code. I have not measured the speed difference though. 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
618
619
620
621
622
623














624
625
626
627
628
629
630
631
632
633
634
635

636
637
638
639
640
641

642

643
644
645
646
647
648
649
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648

649
650
651
652
653
654

655
656
657
658
659
660
661
662
663
664







+
+
+
+
+
+
+
+
+
+
+
+
+
+











-
+





-
+

+







}

/**************************************************************************
** The basic difference engine is above.  What follows is the annotation
** engine.  Both are in the same file since they share many components.
*/

/*
** Linked list of strings, labels used in the annotator code.
** The elements of the list and the pointed string (str)
** will be freed once they become totally unreferenced
** (nref == 0).
*/
struct Label
{
    struct Label *prev;   /* previous element */
    struct Label *next;   /* next element */
    char *str;            /* The label string */
    int nref;             /* Number of references to the string */
};

/*
** The status of an annotation operation is recorded by an instance
** of the following structure.
*/
typedef struct Annotator Annotator;
struct Annotator {
  DContext c;       /* The diff-engine context */
  struct AnnLine {  /* Lines of the original files... */
    const char *z;       /* The text of the line */
    short int n;         /* Number of bytes (omitting trailing space and \n) */
    short int iLevel;    /* Level at which tag was set */
    const char *zSrc;    /* Tag showing origin of this line */
    struct Label *zSrc;    /* Tag showing origin of this line */
  } *aOrig;
  int nOrig;        /* Number of elements in aOrig[] */
  int nNoSrc;       /* Number of entries where aOrig[].zSrc==NULL */
  int iLevel;       /* Current level */
  int nVers;        /* Number of versions analyzed */
  char **azVers;    /* Names of versions analyzed */
  struct Label **azVers;    /* Names of versions analyzed */
  Blob toAnnotate;
  struct Label *firstLabel;
};

/*
** Initialize the annotation process by specifying the file that is
** to be annotated.  The annotator takes control of the input Blob and
** will release it when it is finished with it.
*/
668
669
670
671
672
673
674
675

676
677
678
679
680
681
682
683
684
685
686
687
688
689

690
691
692
693
694
695
696
697







-
+







/*
** The input pParent is the next most recent ancestor of the file
** being annotated.  Do another step of the annotation.  Return true
** if additional annotation is required.  zPName is the tag to insert
** on each line of the file being annotated that was contributed by
** pParent.  Memory to hold zPName is leaked.
*/
static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){
  int i, j;
  int lnTo;
  int iPrevLevel;
  int iThisLevel;

  /* Prepare the parent file to be diffed */
  p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
696
697
698
699
700
701
702
703
704










705

706
707
708
709
710
711
712
711
712
713
714
715
716
717


718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736







-
-
+
+
+
+
+
+
+
+
+
+

+







  iPrevLevel = p->iLevel;
  p->iLevel++;
  iThisLevel = p->iLevel;
  for(i=lnTo=0; i<p->c.nEdit; i+=3){
    struct AnnLine *x = &p->aOrig[lnTo];
    for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){
      if( x->zSrc==0 || x->iLevel==iPrevLevel ){
         /* TODO: handle zPName so we can free labels
          * if they get totally unreferenced in the Annotator */
         if (x->zSrc!=0)
         {
           if(--x->zSrc->nref == 0)
           {
               free(x->zSrc->str);
               x->zSrc->prev->next = x->zSrc->next;
               x->zSrc->next->prev = x->zSrc->prev;
               free(x->zSrc);
           }
         }
         x->zSrc = zPName;
         ++zPName->nref;
         x->iLevel = iThisLevel;
      }
    }
    lnTo += p->c.aEdit[i+2];
  }

  /* Clear out the diff results */
737
738
739
740
741
742
743

744
745







746

747
748
749
750
751

752
753








754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777

778
779
780
781
782

783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800







+


+
+
+
+
+
+
+
-
+




-
+


+
+
+
+
+
+
+
+







  memset(&x, 0, sizeof(x));
  x.toAnnotate = empty_blob;
  content_get(name_to_rid(g.argv[2]), &x.toAnnotate);
  if( annotation_start(&x) ){
    fossil_fatal("binary file");
  }
  for(i=3; i<g.argc; i++){
    struct Label *l;
    blob_zero(&b);
    content_get(name_to_rid(g.argv[i]), &b);
    l = fossil_malloc(sizeof(*l));
    l->str = g.argv[i-1];
    l->nref = 0;
    l->next = x.firstLabel;
    if (x.firstLabel)
      x.firstLabel->prev = l;
    x.firstLabel = l;
    if( annotation_step(&x, &b, g.argv[i-1]) ){
    if( annotation_step(&x, &b, l) ){
      fossil_fatal("binary file");
    }
  }
  for(i=0; i<x.nOrig; i++){
    const char *zSrc = x.aOrig[i].zSrc;
    const char *zSrc = x.aOrig[i].zSrc->str;
    if( zSrc==0 ) zSrc = g.argv[g.argc-1];
    fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
  }
  while(x.firstLabel) {
    struct Label *l;
    l = x.firstLabel->next;
    assert(x.firstLabel->nref > 0);
    free(x.firstLabel->str);
    free(x.firstLabel);
    x.firstLabel = l;
  }
}

/* Annotation flags */
#define ANN_FILE_VERS  0x001  /* Show file version rather than commit version */

/*
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
808
809
810
811
812
813
814

815
816
817
818
819
820
821







-







  int mid,             /* Use the version of the file in this check-in */
  int webLabel,        /* Use web-style annotations if true */
  int iLimit,          /* Limit the number of levels if greater than zero */
  int annFlags         /* Flags to alter the annotation */
){
  Blob step = empty_blob;           /* Text of previous revision */
  int rid;             /* Artifact ID of the file being annotated */
  char *zLabel;        /* Label to apply to a line */
  Stmt q;              /* Query returning all ancestor versions */

  /* Initialize the annotation */
  rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
  if( rid==0 ){
    fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
  }
806
807
808
809
810
811
812





813
814

815
816
817
818
819

820

821
822
823

824
825



826
827
828
829
830
831
832
845
846
847
848
849
850
851
852
853
854
855
856
857

858
859
860
861
862

863
864
865
866
867

868
869

870
871
872
873
874
875
876
877
878
879







+
+
+
+
+

-
+




-
+

+


-
+

-
+
+
+







    iLimit>0 ? iLimit : 10000000
  );
  while( db_step(&q)==SQLITE_ROW ){
    int pid = db_column_int(&q, 0);
    const char *zUuid = db_column_text(&q, 1);
    const char *zDate = db_column_text(&q, 2);
    const char *zUser = db_column_text(&q, 3);
    struct Label *l = fossil_malloc(sizeof(*l));
    l->nref = 0;
    l->next = p->firstLabel;
    if (p->firstLabel)
      p->firstLabel->prev = l;
    if( webLabel ){
      zLabel = mprintf(
      l->str = mprintf(
          "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", 
          g.zTop, zUuid, zUuid, zDate, zUser
      );
    }else{
      zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
      l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
    }
    p->firstLabel = l;
    p->nVers++;
    p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
    p->azVers[p->nVers-1] = zLabel;
    p->azVers[p->nVers-1] = l;
    content_get(pid, &step);
    annotation_step(p, &step, zLabel);
    annotation_step(p, &step, l);
    if (l->nref == 0)
      free(l->str);
    blob_reset(&step);
  }
  db_finalize(&q);
  free(p->c.aTo);
}

/*
858
859
860
861
862
863
864
865

866
867
868
869
870
871
872
873
874

875
876
877
878
879
880
881
905
906
907
908
909
910
911

912
913
914
915
916
917
918
919
920

921
922
923
924
925
926
927
928







-
+








-
+







  if( P("filevers") ) annFlags |= ANN_FILE_VERS;
  annotate_file(&ann, fnid, mid, g.okHistory, iLimit, annFlags);
  if( P("log") ){
    int i;
    @ <h2>Versions analyzed:</h2>
    @ <ol>
    for(i=0; i<ann.nVers; i++){
      @ <li><tt>%s(ann.azVers[i])</tt></li>
      @ <li><tt>%s(ann.azVers[i]->str)</tt></li>
    }
    @ </ol>
    @ <hr>
    @ <h2>Annotation:</h2>
  }
  @ <pre>
  for(i=0; i<ann.nOrig; i++){
    ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
    @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z)
    @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z)
  }
  @ </pre>
  style_footer();
}

/*
** COMMAND: annotate
928
929
930
931
932
933
934
935

936
937
938
939
940
941

942
943
944
945







946


975
976
977
978
979
980
981

982
983
984
985
986
987

988
989
990
991
992
993
994
995
996
997
998
999

1000
1001







-
+





-
+




+
+
+
+
+
+
+
-
+
+
  if( mid==0 ){
    fossil_panic("unable to find manifest");
  }
  if( fileVers ) annFlags |= ANN_FILE_VERS;
  annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
  if( showLog ){
    for(i=0; i<ann.nVers; i++){
      printf("version %3d: %s\n", i+1, ann.azVers[i]);
      printf("version %3d: %s\n", i+1, ann.azVers[i]->str);
    }
    printf("---------------------------------------------------\n");
  }
  for(i=0; i<ann.nOrig; i++){
    fossil_print("%s: %.*s\n", 
                 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
                 ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z);
  }
  free(ann.azVers);
  free(ann.aOrig);
  blob_reset(&ann.toAnnotate);
  while(ann.firstLabel) {
    struct Label *l;
    l = ann.firstLabel->next;
    assert(ann.firstLabel->nref > 0);
    free(ann.firstLabel->str);
    free(ann.firstLabel);
    ann.firstLabel = l;
}
  }
}