Skip to content

Commit 053d6cf

Browse files
committed
address comments
1 parent 56c734e commit 053d6cf

File tree

1 file changed

+30
-19
lines changed

1 file changed

+30
-19
lines changed

storage/gcp/gcp.go

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ func (a *Appender) garbageCollectorJob(ctx context.Context, i time.Duration) {
348348
defer t.Stop()
349349

350350
// Entirely arbitrary number.
351-
maxDeletesPerRun := uint(1024)
351+
maxBundlesPerRun := uint(100)
352352

353353
for {
354354
select {
@@ -372,7 +372,7 @@ func (a *Appender) garbageCollectorJob(ctx context.Context, i time.Duration) {
372372
klog.Warningf("Failed to parse published checkpoint: %v", err)
373373
}
374374

375-
if err := a.sequencer.garbageCollect(ctx, pubSize, maxDeletesPerRun, a.logStore.objStore.deleteObjectsWithPrefix); err != nil {
375+
if err := a.sequencer.garbageCollect(ctx, pubSize, maxBundlesPerRun, a.logStore.objStore.deleteObjectsWithPrefix); err != nil {
376376
klog.Warningf("GarbageCollect failed: %v", err)
377377
}
378378
}()
@@ -1008,13 +1008,12 @@ func (s *spannerCoordinator) publishTree(ctx context.Context, minAge time.Durati
10081008
return nil
10091009
}
10101010

1011-
// garbageCollect is a long running function which will identify unneeded partial tiles/entry bundles, and call the provided function to remove them.
1011+
// garbageCollect will identify up to maxBundles unneeded partial entry bundles (and any unneeded partial tiles which sit above them in the tree) and
1012+
// call the provided function to remove them.
10121013
//
10131014
// Uses the `GCCoord` table to ensure that only one binary is actively garbage collecting at any given time, and to track progress so that we don't
10141015
// needlessly attempt to GC over regions which have already been cleaned.
1015-
//
1016-
// Returns true if we've "caught up" with the current state of the tree.
1017-
func (s *spannerCoordinator) garbageCollect(ctx context.Context, treeSize uint64, maxDeletes uint, deleteWithPrefix func(ctx context.Context, prefix string) error) error {
1016+
func (s *spannerCoordinator) garbageCollect(ctx context.Context, treeSize uint64, maxBundles uint, deleteWithPrefix func(ctx context.Context, prefix string) error) error {
10181017
_, err := s.dbPool.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
10191018
row, err := txn.ReadRowWithOptions(ctx, "GCCoord", spanner.Key{0}, []string{"fromSize"}, &spanner.ReadOptions{LockHint: spannerpb.ReadRequest_LOCK_HINT_EXCLUSIVE})
10201019
if err != nil {
@@ -1030,21 +1029,33 @@ func (s *spannerCoordinator) garbageCollect(ctx context.Context, treeSize uint64
10301029
return nil
10311030
}
10321031

1033-
d := uint(0)
1032+
n := uint(0)
10341033
eg := errgroup.Group{}
1035-
done:
1036-
for l, f, x := uint64(0), fromSize, treeSize; x > 0; l, f, x = l+1, f>>layout.TileHeight, x>>layout.TileHeight {
1037-
for ri := range layout.Range(f, x-f, x) {
1038-
if ri.Partial != 0 || d > maxDeletes {
1039-
break done
1040-
}
1041-
if l == 0 {
1042-
eg.Go(func() error { return deleteWithPrefix(ctx, layout.EntriesPath(ri.Index, 0)+".p/") })
1043-
d++
1044-
fromSize += uint64(ri.N)
1034+
// GC the tree in "vertical" chunks defined by entry bundles.
1035+
for ri := range layout.Range(fromSize, treeSize-fromSize, treeSize) {
1036+
// Only known-full bundles are in-scope for for GC, so exit if the current bundle is partial or
1037+
// we've reached our limit of chunks.
1038+
if ri.Partial > 0 || n > maxBundles {
1039+
break
1040+
}
1041+
1042+
// GC any partial versions of the entry bundle itself.
1043+
eg.Go(func() error { return deleteWithPrefix(ctx, layout.EntriesPath(ri.Index, 0)+".p/") })
1044+
fromSize += uint64(ri.N)
1045+
n++
1046+
1047+
// Now consider (only) the part of the tree which sits above the bundle.
1048+
// We'll walk up, layer by layer, until we find a tile which is non-full (and therefore ineligible
1049+
// for GC), at which point we can stop since there cannot be a full tile above a partial tile.
1050+
for lvl, idx := uint64(0), ri.Index; ; lvl, idx = lvl+1, idx>>layout.TileHeight {
1051+
// GC any partial versions of the tile.
1052+
eg.Go(func() error { return deleteWithPrefix(ctx, layout.TilePath(lvl, idx, 0)+".p/") })
1053+
1054+
// The tile above is full IFF this tile rolls up as the last element in that tile.
1055+
// If it's not full, then neither it, nor anything above it, needs GC yet so we're done.
1056+
if idx%layout.TileWidth != layout.TileWidth-1 {
1057+
break
10451058
}
1046-
eg.Go(func() error { return deleteWithPrefix(ctx, layout.TilePath(l, ri.Index, 0)+".p/") })
1047-
d++
10481059
}
10491060
}
10501061
if err := eg.Wait(); err != nil {

0 commit comments

Comments
 (0)