GarbageCollect removes resources (snapshots, contents, ...) that are no longer used.
(ctx context.Context)
| 381 | |
| 382 | // GarbageCollect removes resources (snapshots, contents, ...) that are no longer used. |
| 383 | func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) { |
| 384 | m.wlock.Lock() |
| 385 | t1 := time.Now() |
| 386 | c := startGCContext(ctx, m.collectors) |
| 387 | |
| 388 | marked, err := m.getMarked(ctx, c) // Pass in gc context |
| 389 | if err != nil { |
| 390 | m.wlock.Unlock() |
| 391 | c.cancel(ctx) |
| 392 | return nil, err |
| 393 | } |
| 394 | |
| 395 | events := []namespacedEvent{} |
| 396 | if err := m.db.Update(func(tx *bolt.Tx) error { |
| 397 | ctx, cancel := context.WithCancel(ctx) |
| 398 | defer cancel() |
| 399 | |
| 400 | rm := func(ctx context.Context, n gc.Node) error { |
| 401 | if _, ok := marked[n]; ok { |
| 402 | return nil |
| 403 | } |
| 404 | |
| 405 | switch n.Type { |
| 406 | case ResourceSnapshot: |
| 407 | if idx := strings.IndexRune(n.Key, '/'); idx > 0 { |
| 408 | m.dirtySS[n.Key[:idx]] = struct{}{} |
| 409 | } |
| 410 | // queue event to publish after successful commit |
| 411 | case ResourceContent, ResourceIngest: |
| 412 | m.dirtyCS = true |
| 413 | } |
| 414 | |
| 415 | event, err := c.remove(ctx, tx, n) |
| 416 | if event != nil && err == nil { |
| 417 | events = append(events, |
| 418 | namespacedEvent{ |
| 419 | namespace: n.Namespace, |
| 420 | event: event, |
| 421 | }) |
| 422 | } |
| 423 | return err |
| 424 | } |
| 425 | |
| 426 | if err := c.scanAll(ctx, tx, rm); err != nil { // From gc context |
| 427 | return fmt.Errorf("failed to scan and remove: %w", err) |
| 428 | } |
| 429 | |
| 430 | return nil |
| 431 | }); err != nil { |
| 432 | m.wlock.Unlock() |
| 433 | c.cancel(ctx) |
| 434 | return nil, err |
| 435 | } |
| 436 | |
| 437 | var stats GCStats |
| 438 | var wg sync.WaitGroup |
| 439 | |
| 440 | // Flush events asynchronously after commit |
nothing calls this directly
no test coverage detected