Skip to content

Commit 80bdfe1

Browse files
authored
Clear step caches when -clear-cache is specified (#551)
1 parent 3d1ac4d commit 80bdfe1

File tree

3 files changed

+61
-24
lines changed

3 files changed

+61
-24
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ All notable changes to `src-cli` are documented in this file.
1717

1818
### Fixed
1919

20+
- Cached step results produced by `src batch [apply|preview]` are now properly cleared when using the `-clear-cache` command line flag.
21+
2022
### Removed
2123

2224
## 3.28.2

internal/batches/executor/coordinator.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,36 @@ func (c *Coordinator) checkCacheForTask(ctx context.Context, task *Task) (specs
139139
return specs, true, nil
140140
}
141141

142+
func (c *Coordinator) setCachedStepResults(ctx context.Context, task *Task) error {
143+
// We start at the back so that we can find the _last_ cached step,
144+
// then restart execution on the following step.
145+
for i := len(task.Steps) - 1; i > -1; i-- {
146+
key := StepsCacheKey{Task: task, StepIndex: i}
147+
148+
// If we need to clear the cache, we optimistically try this for every
149+
// step.
150+
if c.opts.ClearCache {
151+
if err := c.cache.Clear(ctx, key); err != nil {
152+
return errors.Wrapf(err, "clearing cache for step %d in %q", i, task.Repository.Name)
153+
}
154+
} else {
155+
result, found, err := c.cache.GetStepResult(ctx, key)
156+
if err != nil {
157+
return errors.Wrapf(err, "checking for cached diff for step %d", i)
158+
}
159+
160+
// Found a cached result, we're done
161+
if found {
162+
task.CachedResultFound = true
163+
task.CachedResult = result
164+
return nil
165+
}
166+
}
167+
}
168+
169+
return nil
170+
}
171+
142172
func (c *Coordinator) cacheAndBuildSpec(ctx context.Context, taskResult taskResult, status taskStatusHandler) (specs []*batches.ChangesetSpec, err error) {
143173
defer func() {
144174
// Set these two fields in any case
@@ -214,21 +244,8 @@ func (c *Coordinator) Execute(ctx context.Context, tasks []*Task, spec *batches.
214244
// If we are here, that means we didn't find anything in the cache for the
215245
// complete task. So, what if we have cached results for the steps?
216246
for _, t := range tasks {
217-
// We start at the back so that we can find the _last_ cached step,
218-
// then restart execution on the following step.
219-
for i := len(t.Steps) - 1; i > -1; i-- {
220-
key := StepsCacheKey{Task: t, StepIndex: i}
221-
222-
result, found, err := c.cache.GetStepResult(ctx, key)
223-
if err != nil {
224-
return nil, nil, errors.Wrapf(err, "checking for cached diff for step %d", i)
225-
}
226-
227-
if found {
228-
t.CachedResultFound = true
229-
t.CachedResult = result
230-
break
231-
}
247+
if err := c.setCachedStepResults(ctx, t); err != nil {
248+
return nil, nil, err
232249
}
233250
}
234251

internal/batches/executor/coordinator_test.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,9 @@ func TestCoordinator_Execute(t *testing.T) {
342342
}
343343

344344
func TestCoordinator_Execute_StepCaching(t *testing.T) {
345+
// Setup dependencies
345346
cache := newInMemoryExecutionCache()
347+
logManager := mock.LogNoOpManager{}
346348

347349
task := &Task{
348350
Steps: []batches.Step{
@@ -370,46 +372,62 @@ func TestCoordinator_Execute_StepCaching(t *testing.T) {
370372
},
371373
}}
372374

375+
// Build Coordinator
376+
coord := &Coordinator{cache: cache, exec: executor, logManager: logManager}
377+
373378
// First execution. Make sure that the Task executes all steps.
374-
execAndEnsure(t, cache, executor, task, assertNoCachedResult(t))
379+
execAndEnsure(t, coord, executor, task, assertNoCachedResult(t))
375380
// We now expect the cache to have 1+N entries: 1 for the complete task, N
376381
// for the steps.
377382
wantCacheSize := len(task.Steps) + 1
378383
assertCacheSize(t, cache, wantCacheSize)
379384

385+
// Reset task
386+
task.CachedResultFound = false
387+
380388
// Change the 2nd step's definition:
381389
task.Steps[1].Run = `echo "two modified"`
382390
// Re-execution should start with the diff produced by steps[0] as the
383391
// start state from which steps[1] is then re-executed.
384-
execAndEnsure(t, cache, executor, task, assertCachedResultForStep(t, 0))
392+
execAndEnsure(t, coord, executor, task, assertCachedResultForStep(t, 0))
385393
// Cache now contains old entries, plus another "complete task" entry and
386394
// two entries for newly executed steps.
387395
wantCacheSize += 1 + 2
388396
assertCacheSize(t, cache, wantCacheSize)
389397

398+
// Reset task
399+
task.CachedResultFound = false
400+
390401
// Change the 3rd step's definition:
391402
task.Steps[2].Run = `echo "three modified"`
392403
// Re-execution should use the diff from steps[1] as start state
393-
execAndEnsure(t, cache, executor, task, assertCachedResultForStep(t, 1))
404+
execAndEnsure(t, coord, executor, task, assertCachedResultForStep(t, 1))
394405
// Cache now contains old entries, plus another "complete task" entry and
395406
// a single new step entry
396407
wantCacheSize += 1 + 1
397408
assertCacheSize(t, cache, wantCacheSize)
409+
410+
// Reset task
411+
task.CachedResultFound = false
412+
413+
// Now we execute the spec with -clear-cache:
414+
coord.opts.ClearCache = true
415+
// We don't want any cached results set on the task:
416+
execAndEnsure(t, coord, executor, task, assertNoCachedResult(t))
417+
// Cache should have the same number of entries: the cached step results should
418+
// have been cleared (the complete-task-result is cleared in another
419+
// code path) and the same amount of cached entries has been added.
420+
assertCacheSize(t, cache, wantCacheSize)
398421
}
399422

400423
// execAndEnsure executes the given Task with the given cache and dummyExecutor
401424
// in a new Coordinator, setting cb as the startCallback on the executor.
402-
func execAndEnsure(t *testing.T, cache ExecutionCache, exec *dummyExecutor, task *Task, cb startCallback) {
425+
func execAndEnsure(t *testing.T, coord *Coordinator, exec *dummyExecutor, task *Task, cb startCallback) {
403426
t.Helper()
404427

405-
// Setup dependencies
406428
batchSpec := &batches.BatchSpec{ChangesetTemplate: testChangesetTemplate}
407-
logManager := mock.LogNoOpManager{}
408429
noopPrinter := func([]*TaskStatus) {}
409430

410-
// Build Coordinator
411-
coord := &Coordinator{cache: cache, exec: exec, logManager: logManager}
412-
413431
// Set the ChangesetTemplate on Task
414432
task.Template = batchSpec.ChangesetTemplate
415433

0 commit comments

Comments
 (0)