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 }