Fossil SCM

In graph layout, if we run out of rails for new graph elements, do the best as we can, but continue to try to show a graph. Better to draw a goofy graph than to not show the graph at all.

drh 2025-03-21 15:56 trunk
Commit a8c6f3a47038eaba1c6b1c6127155d46cb759f5c7348594aefba1e3bfca29d62
1 file changed +29 -11
+29 -11
--- src/graph.c
+++ src/graph.c
@@ -59,11 +59,11 @@
5959
** check-ins and many files. For this reason, we make the identifier
6060
** a 64-bit integer, to dramatically reduce the risk of an overflow.
6161
*/
6262
typedef sqlite3_int64 GraphRowId;
6363
64
-#define GR_MAX_RAIL 60 /* Max number of "rails" to display */
64
+#define GR_MAX_RAIL 64 /* Max number of "rails" to display */
6565
6666
/* The graph appears vertically beside a timeline. Each row in the
6767
** timeline corresponds to a row in the graph. GraphRow.idx is 0 for
6868
** the top-most row and increases moving down. Hence (in the absence of
6969
** time skew) parents have a larger index than their children.
@@ -118,10 +118,11 @@
118118
char **azBranch; /* Names of the branches */
119119
int nRow; /* Number of rows */
120120
int nHash; /* Number of slots in apHash[] */
121121
u8 hasOffsetMergeRiser; /* Merge arrow from leaf goes up on a different
122122
** rail that the node */
123
+ u8 bOverfull; /* Unable to allocate sufficient rails */
123124
u64 mergeRail; /* Rails used for merge lines */
124125
GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
125126
u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */
126127
};
127128
@@ -336,11 +337,18 @@
336337
iBestDist = dist;
337338
iBest = i;
338339
}
339340
}
340341
}
341
- if( iBestDist>1000 ) p->nErr++;
342
+ if( iBestDist>1000 ){
343
+ p->bOverfull = 1;
344
+ iBest = GR_MAX_RAIL;
345
+ }
346
+ if( iBest>GR_MAX_RAIL ){
347
+ p->bOverfull = 1;
348
+ iBest = GR_MAX_RAIL;
349
+ }
342350
if( iBest>p->mxRail ) p->mxRail = iBest;
343351
if( bMergeRail ) p->mergeRail |= BIT(iBest);
344352
return iBest;
345353
}
346354
@@ -709,11 +717,11 @@
709717
if( pRow->iRail>=0 ) continue;
710718
if( pRow->isDup ) continue;
711719
if( pRow->nParent<0 ) continue;
712720
if( pRow->nParent==0 || hashFind(p,pRow->aParent[0])==0 ){
713721
pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx+riserMargin,0,0);
714
- if( p->mxRail>=GR_MAX_RAIL ) return;
722
+ /* if( p->mxRail>=GR_MAX_RAIL ) return; */
715723
mask = BIT(pRow->iRail);
716724
if( !omitDescenders ){
717725
int n = RISER_MARGIN;
718726
pRow->bDescender = pRow->nParent>0;
719727
for(pLoop=pRow; pLoop && (n--)>0; pLoop=pLoop->pNext){
@@ -744,28 +752,38 @@
744752
assert( pRow->nParent>0 );
745753
parentRid = pRow->aParent[0];
746754
pParent = hashFind(p, parentRid);
747755
if( pParent==0 ){
748756
pRow->iRail = ++p->mxRail;
749
- if( p->mxRail>=GR_MAX_RAIL ) return;
757
+ if( p->mxRail>=GR_MAX_RAIL ){
758
+ pRow->iRail = p->mxRail = GR_MAX_RAIL;
759
+ p->bOverfull = 1;
760
+ }
750761
pRow->railInUse = BIT(pRow->iRail);
751762
continue;
752763
}
753764
if( pParent->idx>pRow->idx ){
754765
/* Common case: Child occurs after parent and is above the
755766
** parent in the timeline */
756767
pRow->iRail = findFreeRail(p, pRow->idxTop, pParent->idx,
757768
pParent->iRail, 0);
758
- if( p->mxRail>=GR_MAX_RAIL ) return;
769
+ /* if( p->mxRail>=GR_MAX_RAIL ) return; */
759770
pParent->aiRiser[pRow->iRail] = pRow->idx;
760771
}else{
761772
/* Timewarp case: Child occurs earlier in time than parent and
762773
** appears below the parent in the timeline. */
763774
int iDownRail = ++p->mxRail;
764775
if( iDownRail<1 ) iDownRail = ++p->mxRail;
776
+ if( p->mxRail>GR_MAX_RAIL ){
777
+ iDownRail = p->mxRail = GR_MAX_RAIL;
778
+ p->bOverfull = 1;
779
+ }
765780
pRow->iRail = ++p->mxRail;
766
- if( p->mxRail>=GR_MAX_RAIL ) return;
781
+ if( p->mxRail>=GR_MAX_RAIL ){
782
+ pRow->iRail = p->mxRail = GR_MAX_RAIL;
783
+ p->bOverfull = 1;
784
+ }
767785
pRow->railInUse = BIT(pRow->iRail);
768786
pParent->aiRiser[iDownRail] = pRow->idx;
769787
mask = BIT(iDownRail);
770788
for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){
771789
pLoop->railInUse |= mask;
@@ -824,11 +842,11 @@
824842
break;
825843
}
826844
}
827845
if( iMrail==-1 ){
828846
iMrail = findFreeRail(p, pRow->idx, p->pLast->idx, 0, 1);
829
- if( p->mxRail>=GR_MAX_RAIL ) return;
847
+ /*if( p->mxRail>=GR_MAX_RAIL ) return;*/
830848
mergeRiserFrom[iMrail] = parentRid;
831849
}
832850
iReuseIdx = p->nRow+1;
833851
iReuseRail = iMrail;
834852
mask = BIT(iMrail);
@@ -856,11 +874,11 @@
856874
pDesc->mergeUpto = pDesc->idx;
857875
}
858876
}else{
859877
/* Create a new merge for an on-screen node */
860878
createMergeRiser(p, pDesc, pRow, isCherrypick);
861
- if( p->mxRail>=GR_MAX_RAIL ) return;
879
+ /* if( p->mxRail>=GR_MAX_RAIL ) return; */
862880
if( iReuseIdx<0
863881
&& pDesc->nMergeChild==1
864882
&& (pDesc->iRail!=pDesc->mergeOut || pDesc->isLeaf)
865883
){
866884
iReuseIdx = pDesc->idx;
@@ -872,17 +890,17 @@
872890
}
873891
874892
/*
875893
** Insert merge rails from primaries to duplicates.
876894
*/
877
- if( hasDup ){
895
+ if( hasDup && p->mxRail<GR_MAX_RAIL ){
878896
int dupRail;
879897
int mxRail;
880898
find_max_rail(p);
881899
mxRail = p->mxRail;
882900
dupRail = mxRail+1;
883
- if( p->mxRail>=GR_MAX_RAIL ) return;
901
+ /* if( p->mxRail>=GR_MAX_RAIL ) return; */
884902
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
885903
if( !pRow->isDup ) continue;
886904
pRow->iRail = dupRail;
887905
pDesc = hashFind(p, pRow->rid);
888906
assert( pDesc!=0 && pDesc!=pRow );
@@ -893,11 +911,11 @@
893911
dupRail = mxRail+1;
894912
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
895913
if( pRow->isDup ) pRow->iRail = dupRail;
896914
}
897915
}
898
- if( mxRail>=GR_MAX_RAIL ) return;
916
+ /* if( mxRail>=GR_MAX_RAIL ) return; */
899917
}
900918
901919
/*
902920
** Find the maximum rail number.
903921
*/
904922
--- src/graph.c
+++ src/graph.c
@@ -59,11 +59,11 @@
59 ** check-ins and many files. For this reason, we make the identifier
60 ** a 64-bit integer, to dramatically reduce the risk of an overflow.
61 */
62 typedef sqlite3_int64 GraphRowId;
63
64 #define GR_MAX_RAIL 60 /* Max number of "rails" to display */
65
66 /* The graph appears vertically beside a timeline. Each row in the
67 ** timeline corresponds to a row in the graph. GraphRow.idx is 0 for
68 ** the top-most row and increases moving down. Hence (in the absence of
69 ** time skew) parents have a larger index than their children.
@@ -118,10 +118,11 @@
118 char **azBranch; /* Names of the branches */
119 int nRow; /* Number of rows */
120 int nHash; /* Number of slots in apHash[] */
121 u8 hasOffsetMergeRiser; /* Merge arrow from leaf goes up on a different
122 ** rail that the node */
 
123 u64 mergeRail; /* Rails used for merge lines */
124 GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
125 u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */
126 };
127
@@ -336,11 +337,18 @@
336 iBestDist = dist;
337 iBest = i;
338 }
339 }
340 }
341 if( iBestDist>1000 ) p->nErr++;
 
 
 
 
 
 
 
342 if( iBest>p->mxRail ) p->mxRail = iBest;
343 if( bMergeRail ) p->mergeRail |= BIT(iBest);
344 return iBest;
345 }
346
@@ -709,11 +717,11 @@
709 if( pRow->iRail>=0 ) continue;
710 if( pRow->isDup ) continue;
711 if( pRow->nParent<0 ) continue;
712 if( pRow->nParent==0 || hashFind(p,pRow->aParent[0])==0 ){
713 pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx+riserMargin,0,0);
714 if( p->mxRail>=GR_MAX_RAIL ) return;
715 mask = BIT(pRow->iRail);
716 if( !omitDescenders ){
717 int n = RISER_MARGIN;
718 pRow->bDescender = pRow->nParent>0;
719 for(pLoop=pRow; pLoop && (n--)>0; pLoop=pLoop->pNext){
@@ -744,28 +752,38 @@
744 assert( pRow->nParent>0 );
745 parentRid = pRow->aParent[0];
746 pParent = hashFind(p, parentRid);
747 if( pParent==0 ){
748 pRow->iRail = ++p->mxRail;
749 if( p->mxRail>=GR_MAX_RAIL ) return;
 
 
 
750 pRow->railInUse = BIT(pRow->iRail);
751 continue;
752 }
753 if( pParent->idx>pRow->idx ){
754 /* Common case: Child occurs after parent and is above the
755 ** parent in the timeline */
756 pRow->iRail = findFreeRail(p, pRow->idxTop, pParent->idx,
757 pParent->iRail, 0);
758 if( p->mxRail>=GR_MAX_RAIL ) return;
759 pParent->aiRiser[pRow->iRail] = pRow->idx;
760 }else{
761 /* Timewarp case: Child occurs earlier in time than parent and
762 ** appears below the parent in the timeline. */
763 int iDownRail = ++p->mxRail;
764 if( iDownRail<1 ) iDownRail = ++p->mxRail;
 
 
 
 
765 pRow->iRail = ++p->mxRail;
766 if( p->mxRail>=GR_MAX_RAIL ) return;
 
 
 
767 pRow->railInUse = BIT(pRow->iRail);
768 pParent->aiRiser[iDownRail] = pRow->idx;
769 mask = BIT(iDownRail);
770 for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){
771 pLoop->railInUse |= mask;
@@ -824,11 +842,11 @@
824 break;
825 }
826 }
827 if( iMrail==-1 ){
828 iMrail = findFreeRail(p, pRow->idx, p->pLast->idx, 0, 1);
829 if( p->mxRail>=GR_MAX_RAIL ) return;
830 mergeRiserFrom[iMrail] = parentRid;
831 }
832 iReuseIdx = p->nRow+1;
833 iReuseRail = iMrail;
834 mask = BIT(iMrail);
@@ -856,11 +874,11 @@
856 pDesc->mergeUpto = pDesc->idx;
857 }
858 }else{
859 /* Create a new merge for an on-screen node */
860 createMergeRiser(p, pDesc, pRow, isCherrypick);
861 if( p->mxRail>=GR_MAX_RAIL ) return;
862 if( iReuseIdx<0
863 && pDesc->nMergeChild==1
864 && (pDesc->iRail!=pDesc->mergeOut || pDesc->isLeaf)
865 ){
866 iReuseIdx = pDesc->idx;
@@ -872,17 +890,17 @@
872 }
873
874 /*
875 ** Insert merge rails from primaries to duplicates.
876 */
877 if( hasDup ){
878 int dupRail;
879 int mxRail;
880 find_max_rail(p);
881 mxRail = p->mxRail;
882 dupRail = mxRail+1;
883 if( p->mxRail>=GR_MAX_RAIL ) return;
884 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
885 if( !pRow->isDup ) continue;
886 pRow->iRail = dupRail;
887 pDesc = hashFind(p, pRow->rid);
888 assert( pDesc!=0 && pDesc!=pRow );
@@ -893,11 +911,11 @@
893 dupRail = mxRail+1;
894 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
895 if( pRow->isDup ) pRow->iRail = dupRail;
896 }
897 }
898 if( mxRail>=GR_MAX_RAIL ) return;
899 }
900
901 /*
902 ** Find the maximum rail number.
903 */
904
--- src/graph.c
+++ src/graph.c
@@ -59,11 +59,11 @@
59 ** check-ins and many files. For this reason, we make the identifier
60 ** a 64-bit integer, to dramatically reduce the risk of an overflow.
61 */
62 typedef sqlite3_int64 GraphRowId;
63
64 #define GR_MAX_RAIL 64 /* Max number of "rails" to display */
65
66 /* The graph appears vertically beside a timeline. Each row in the
67 ** timeline corresponds to a row in the graph. GraphRow.idx is 0 for
68 ** the top-most row and increases moving down. Hence (in the absence of
69 ** time skew) parents have a larger index than their children.
@@ -118,10 +118,11 @@
118 char **azBranch; /* Names of the branches */
119 int nRow; /* Number of rows */
120 int nHash; /* Number of slots in apHash[] */
121 u8 hasOffsetMergeRiser; /* Merge arrow from leaf goes up on a different
122 ** rail that the node */
123 u8 bOverfull; /* Unable to allocate sufficient rails */
124 u64 mergeRail; /* Rails used for merge lines */
125 GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
126 u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */
127 };
128
@@ -336,11 +337,18 @@
337 iBestDist = dist;
338 iBest = i;
339 }
340 }
341 }
342 if( iBestDist>1000 ){
343 p->bOverfull = 1;
344 iBest = GR_MAX_RAIL;
345 }
346 if( iBest>GR_MAX_RAIL ){
347 p->bOverfull = 1;
348 iBest = GR_MAX_RAIL;
349 }
350 if( iBest>p->mxRail ) p->mxRail = iBest;
351 if( bMergeRail ) p->mergeRail |= BIT(iBest);
352 return iBest;
353 }
354
@@ -709,11 +717,11 @@
717 if( pRow->iRail>=0 ) continue;
718 if( pRow->isDup ) continue;
719 if( pRow->nParent<0 ) continue;
720 if( pRow->nParent==0 || hashFind(p,pRow->aParent[0])==0 ){
721 pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx+riserMargin,0,0);
722 /* if( p->mxRail>=GR_MAX_RAIL ) return; */
723 mask = BIT(pRow->iRail);
724 if( !omitDescenders ){
725 int n = RISER_MARGIN;
726 pRow->bDescender = pRow->nParent>0;
727 for(pLoop=pRow; pLoop && (n--)>0; pLoop=pLoop->pNext){
@@ -744,28 +752,38 @@
752 assert( pRow->nParent>0 );
753 parentRid = pRow->aParent[0];
754 pParent = hashFind(p, parentRid);
755 if( pParent==0 ){
756 pRow->iRail = ++p->mxRail;
757 if( p->mxRail>=GR_MAX_RAIL ){
758 pRow->iRail = p->mxRail = GR_MAX_RAIL;
759 p->bOverfull = 1;
760 }
761 pRow->railInUse = BIT(pRow->iRail);
762 continue;
763 }
764 if( pParent->idx>pRow->idx ){
765 /* Common case: Child occurs after parent and is above the
766 ** parent in the timeline */
767 pRow->iRail = findFreeRail(p, pRow->idxTop, pParent->idx,
768 pParent->iRail, 0);
769 /* if( p->mxRail>=GR_MAX_RAIL ) return; */
770 pParent->aiRiser[pRow->iRail] = pRow->idx;
771 }else{
772 /* Timewarp case: Child occurs earlier in time than parent and
773 ** appears below the parent in the timeline. */
774 int iDownRail = ++p->mxRail;
775 if( iDownRail<1 ) iDownRail = ++p->mxRail;
776 if( p->mxRail>GR_MAX_RAIL ){
777 iDownRail = p->mxRail = GR_MAX_RAIL;
778 p->bOverfull = 1;
779 }
780 pRow->iRail = ++p->mxRail;
781 if( p->mxRail>=GR_MAX_RAIL ){
782 pRow->iRail = p->mxRail = GR_MAX_RAIL;
783 p->bOverfull = 1;
784 }
785 pRow->railInUse = BIT(pRow->iRail);
786 pParent->aiRiser[iDownRail] = pRow->idx;
787 mask = BIT(iDownRail);
788 for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){
789 pLoop->railInUse |= mask;
@@ -824,11 +842,11 @@
842 break;
843 }
844 }
845 if( iMrail==-1 ){
846 iMrail = findFreeRail(p, pRow->idx, p->pLast->idx, 0, 1);
847 /*if( p->mxRail>=GR_MAX_RAIL ) return;*/
848 mergeRiserFrom[iMrail] = parentRid;
849 }
850 iReuseIdx = p->nRow+1;
851 iReuseRail = iMrail;
852 mask = BIT(iMrail);
@@ -856,11 +874,11 @@
874 pDesc->mergeUpto = pDesc->idx;
875 }
876 }else{
877 /* Create a new merge for an on-screen node */
878 createMergeRiser(p, pDesc, pRow, isCherrypick);
879 /* if( p->mxRail>=GR_MAX_RAIL ) return; */
880 if( iReuseIdx<0
881 && pDesc->nMergeChild==1
882 && (pDesc->iRail!=pDesc->mergeOut || pDesc->isLeaf)
883 ){
884 iReuseIdx = pDesc->idx;
@@ -872,17 +890,17 @@
890 }
891
892 /*
893 ** Insert merge rails from primaries to duplicates.
894 */
895 if( hasDup && p->mxRail<GR_MAX_RAIL ){
896 int dupRail;
897 int mxRail;
898 find_max_rail(p);
899 mxRail = p->mxRail;
900 dupRail = mxRail+1;
901 /* if( p->mxRail>=GR_MAX_RAIL ) return; */
902 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
903 if( !pRow->isDup ) continue;
904 pRow->iRail = dupRail;
905 pDesc = hashFind(p, pRow->rid);
906 assert( pDesc!=0 && pDesc!=pRow );
@@ -893,11 +911,11 @@
911 dupRail = mxRail+1;
912 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
913 if( pRow->isDup ) pRow->iRail = dupRail;
914 }
915 }
916 /* if( mxRail>=GR_MAX_RAIL ) return; */
917 }
918
919 /*
920 ** Find the maximum rail number.
921 */
922

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button