@@ -100,6 +100,10 @@ type MutableLayer struct {
100100
101101 // We also cache some things required for us to update currentEntries faster
102102 currentUids map [uint64 ]int // Stores the uid to index mapping in the currentEntries posting list
103+
104+ // Cache for calculated UIDS
105+ isUidsCalculated bool
106+ calculatedUids []uint64
103107}
104108
105109func newMutableLayer () * MutableLayer {
@@ -110,6 +114,8 @@ func newMutableLayer() *MutableLayer {
110114 length : math .MaxInt ,
111115 committedUids : make (map [uint64 ]* pb.Posting ),
112116 committedUidsTime : math .MaxUint64 ,
117+ isUidsCalculated : false ,
118+ calculatedUids : []uint64 {},
113119 }
114120}
115121
@@ -136,6 +142,8 @@ func (mm *MutableLayer) clone() *MutableLayer {
136142 length : mm .length ,
137143 lastEntry : mm .lastEntry ,
138144 committedUidsTime : mm .committedUidsTime ,
145+ isUidsCalculated : mm .isUidsCalculated ,
146+ calculatedUids : mm .calculatedUids ,
139147 }
140148}
141149
@@ -153,6 +161,8 @@ func (mm *MutableLayer) setCurrentEntries(ts uint64, pl *pb.PostingList) {
153161 mm .readTs = ts
154162 mm .currentEntries = pl
155163 clear (mm .currentUids )
164+ mm .isUidsCalculated = false
165+ mm .calculatedUids = nil
156166 mm .deleteAllMarker = math .MaxUint64
157167 mm .populateUidMap (pl )
158168}
@@ -770,6 +780,9 @@ func (l *List) updateMutationLayer(mpost *pb.Posting, singleUidUpdate, hasCountI
770780 l .mutationMap .currentEntries = & pb.PostingList {}
771781 }
772782
783+ l .mutationMap .isUidsCalculated = false
784+ l .mutationMap .calculatedUids = nil
785+
773786 if singleUidUpdate {
774787 // This handles the special case when adding a value to predicates of type uid.
775788 // The current value should be deleted in favor of this value. This needs to
@@ -1010,6 +1023,8 @@ func (l *List) setMutationAfterCommit(startTs, commitTs uint64, pl *pb.PostingLi
10101023 l .mutationMap .currentEntries = nil
10111024 l .mutationMap .readTs = 0
10121025 l .mutationMap .currentUids = nil
1026+ l .mutationMap .isUidsCalculated = false
1027+ l .mutationMap .calculatedUids = nil
10131028
10141029 if pl .CommitTs != 0 {
10151030 l .maxTs = x .Max (l .maxTs , pl .CommitTs )
@@ -1691,6 +1706,43 @@ func (l *List) ApproxLen() int {
16911706 return l .mutationMap .len () + codec .ApproxLen (l .plist .Pack )
16921707}
16931708
1709+ func (l * List ) calculateUids () error {
1710+ l .RLock ()
1711+ if l .mutationMap == nil || l .mutationMap .isUidsCalculated {
1712+ l .RUnlock ()
1713+ return nil
1714+ }
1715+ res := make ([]uint64 , 0 , l .ApproxLen ())
1716+
1717+ err := l .iterate (l .mutationMap .committedUidsTime , 0 , func (p * pb.Posting ) error {
1718+ if p .PostingType == pb .Posting_REF {
1719+ res = append (res , p .Uid )
1720+ }
1721+ return nil
1722+ })
1723+
1724+ l .RUnlock ()
1725+
1726+ if err != nil {
1727+ return err
1728+ }
1729+
1730+ l .Lock ()
1731+ defer l .Unlock ()
1732+
1733+ l .mutationMap .calculatedUids = res
1734+ l .mutationMap .isUidsCalculated = true
1735+
1736+ return nil
1737+ }
1738+
1739+ func (l * List ) canUseCalculatedUids () bool {
1740+ if l .mutationMap == nil {
1741+ return false
1742+ }
1743+ return l .mutationMap .isUidsCalculated && l .mutationMap .currentEntries == nil
1744+ }
1745+
16941746// Uids returns the UIDs given some query params.
16951747// We have to apply the filtering before applying (offset, count).
16961748// WARNING: Calling this function just to get UIDs is expensive
@@ -1700,6 +1752,30 @@ func (l *List) Uids(opt ListOptions) (*pb.List, error) {
17001752 }
17011753
17021754 getUidList := func () (* pb.List , error , bool ) {
1755+ if l .canUseCalculatedUids () {
1756+ l .RLock ()
1757+
1758+ afterIdx := 0
1759+
1760+ if opt .AfterUid != 0 {
1761+ after := sort .Search (len (l .mutationMap .calculatedUids ), func (i int ) bool {
1762+ return l .mutationMap .calculatedUids [i ] > opt .AfterUid
1763+ })
1764+ if after >= len (l .mutationMap .calculatedUids ) {
1765+ l .RUnlock ()
1766+ return & pb.List {}, nil , false
1767+ }
1768+
1769+ afterIdx = after
1770+ }
1771+
1772+ copyArr := make ([]uint64 , len (l .mutationMap .calculatedUids )- afterIdx )
1773+ copy (copyArr , l .mutationMap .calculatedUids [afterIdx :])
1774+ out := & pb.List {Uids : copyArr }
1775+ l .RUnlock ()
1776+
1777+ return out , nil , opt .Intersect != nil
1778+ }
17031779 // Pre-assign length to make it faster.
17041780 l .RLock ()
17051781 defer l .RUnlock ()
@@ -1752,13 +1828,7 @@ func (l *List) Uids(opt ListOptions) (*pb.List, error) {
17521828 }
17531829 res = append (res , p .Uid )
17541830
1755- if opt .First < 0 {
1756- // We need the last N.
1757- // TODO: This could be optimized by only considering some of the last UidBlocks.
1758- if len (res ) > - opt .First {
1759- res = res [1 :]
1760- }
1761- } else if len (res ) > opt .First {
1831+ if opt .First != 0 && len (res ) > opt .First {
17621832 return ErrStopIteration
17631833 }
17641834 }
@@ -1774,19 +1844,22 @@ func (l *List) Uids(opt ListOptions) (*pb.List, error) {
17741844
17751845 // Do The intersection here as it's optimized.
17761846 out , err , applyIntersectWith := getUidList ()
1777- if err != nil || ! applyIntersectWith {
1847+ if err != nil || ! applyIntersectWith || opt . First == 0 {
17781848 return out , err
17791849 }
17801850
1781- lenBefore := len (out .Uids )
1782- if opt .Intersect != nil {
1851+ if opt .Intersect != nil && applyIntersectWith {
17831852 algo .IntersectWith (out , opt .Intersect , out )
17841853 }
1785- lenAfter := len (out .Uids )
1786- if lenBefore - lenAfter > 0 {
1787- // If we see this log, that means that iterate is going over too many elements that it doesn't need to
1788- glog .V (3 ).Infof ("Retrieved a list. length before intersection: %d, length after: %d, extra" +
1789- " elements: %d" , lenBefore , lenAfter , lenBefore - lenAfter )
1854+
1855+ if opt .First != 0 {
1856+ if opt .First < 0 {
1857+ if len (out .Uids ) > - opt .First {
1858+ out .Uids = out .Uids [(len (out .Uids ) + opt .First ):]
1859+ }
1860+ } else if len (out .Uids ) > opt .First {
1861+ out .Uids = out .Uids [:opt .First ]
1862+ }
17901863 }
17911864 return out , nil
17921865}
0 commit comments