| 394 | } |
| 395 | |
| 396 | func (s *FileStore) FlushCache(ctx context.Context) (stats FlushStats, rtnErr error) { |
| 397 | wasFlushing := s.setUnlessFlushing() |
| 398 | if wasFlushing { |
| 399 | return stats, fmt.Errorf("flush already in progress") |
| 400 | } |
| 401 | defer s.setIsFlushing(false) |
| 402 | startTime := time.Now() |
| 403 | defer func() { |
| 404 | stats.FlushDuration = time.Since(startTime) |
| 405 | }() |
| 406 | |
| 407 | // get a copy of dirty keys so we can iterate without the lock |
| 408 | dirtyCacheKeys := s.getDirtyCacheKeys() |
| 409 | stats.NumDirtyEntries = len(dirtyCacheKeys) |
| 410 | for _, key := range dirtyCacheKeys { |
| 411 | err := withLock(s, key.ZoneId, key.Name, func(entry *CacheEntry) error { |
| 412 | return entry.flushToDB(ctx, false) |
| 413 | }) |
| 414 | if ctx.Err() != nil { |
| 415 | // transient error (also must stop the loop) |
| 416 | return stats, ctx.Err() |
| 417 | } |
| 418 | if err != nil { |
| 419 | return stats, fmt.Errorf("error flushing cache entry[%v]: %v", key, err) |
| 420 | } |
| 421 | stats.NumCommitted++ |
| 422 | } |
| 423 | return stats, nil |
| 424 | } |
| 425 | |
| 426 | /////////////////////////////////// |
| 427 | |