blob: 4ad37ded1b0c5014fbcf8430dcf55e8510f982a8 [file] [log] [blame]
// Copyright 2016 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVTOOLS_GOMA_CLIENT_LOCAL_OUTPUT_CACHE_H_
#define DEVTOOLS_GOMA_CLIENT_LOCAL_OUTPUT_CACHE_H_
#include <cstdint>
#include <string>
#include "absl/strings/string_view.h"
#include "atomic_stats_counter.h"
#include "autolock_timer.h"
#include "compiler_specific.h"
#include "goma_hash.h"
#include "linked_unordered_map.h"
#include "sha256hash_hasher.h"
#include "worker_thread_manager.h"
MSVC_PUSH_DISABLE_WARNING_FOR_PROTO()
#include "prototmp/goma_data.pb.h"
#include "prototmp/local_output_cache_data.pb.h"
MSVC_POP_WARNING()
namespace devtools_goma {
class LocalOutputCacheStats;
// LocalOutputCache is a cache that ExecReq -> output files.
class LocalOutputCache {
public:
struct GarbageCollectionStat {
size_t num_removed = 0; // # of garbage collected entries
size_t num_failed = 0; // failed to remove
std::int64_t removed_bytes = 0; // total removed bytes
};
static bool IsEnabled() { return instance_ != nullptr; }
static LocalOutputCache* instance() { return instance_; }
// When |server| is nullptr, GC won't run. This will be useful
// for testing.
static void Init(std::string cache_dir,
WorkerThreadManager* wm,
int max_cache_amount_in_mb,
int threshold_cache_amount_in_mb,
size_t max_cache_items,
size_t threshold_cache_items);
static void Quit();
LocalOutputCache(const LocalOutputCache&) = delete;
LocalOutputCache(LocalOutputCache&&) = delete;
LocalOutputCache& operator=(const LocalOutputCache&) = delete;
LocalOutputCache& operator=(LocalOutputCache&&) = delete;
// Creates cache key from |req|.
static std::string MakeCacheKey(const ExecReq& req);
// SaveOutput copies output files to cache.
// |trace_id| is just used for logging.
bool SaveOutput(const std::string& key,
const ExecReq* req,
const ExecResp* resp,
const std::string& trace_id);
// Finds cache with |key|.
// Returns true when a cache is found and read correctly. In this case,
// |resp| will be filled with output data.
// Otherwise, false is returned.
// |trace_id| is just used for logging.
bool Lookup(const std::string& key,
ExecResp* resp,
const std::string& trace_id);
// Dumps stats.
void DumpStatsToProto(LocalOutputCacheStats* stats);
// For stats. These will be removed after merged to GomaStats.
size_t TotalCacheCount();
std::int64_t TotalCacheAmountInByte();
size_t TotalGCRemovedItems() const { return stats_gc_removed_items_.value(); }
std::int64_t TotalGCRemovedBytes() const {
return stats_gc_removed_bytes_.value();
}
private:
struct CacheEntry {
CacheEntry() : mtime(0), amount_byte(0) {}
CacheEntry(time_t mtime, std::int64_t amount_byte)
: mtime(mtime), amount_byte(amount_byte) {
}
~CacheEntry() {
}
time_t mtime;
std::int64_t amount_byte;
};
LocalOutputCache(std::string cache_dir,
std::int64_t max_cache_amount_byte,
std::int64_t threashold_cache_amount_byte,
size_t max_cache_items,
size_t threshold_cache_items);
~LocalOutputCache();
// load cache entries.
void StartLoadCacheEntries(WorkerThreadManager* wm);
void LoadCacheEntries();
void LoadCacheEntriesDone();
// Wait until all cache entries are loaded from the file.
void WaitUntilReady();
void AddCacheEntry(const SHA256HashValue& key,
std::int64_t cache_amount_in_byte);
// A cache entry is updated, so move it to last.
void UpdateCacheEntry(const SHA256HashValue& key);
void StartGarbageCollection(WorkerThreadManager* wm)
LOCKS_EXCLUDED(entries_mu_);
void StopGarbageCollection() LOCKS_EXCLUDED(entries_mu_);
void GarbageCollectionThread() LOCKS_EXCLUDED(entries_mu_);
bool ShouldInvokeGarbageCollection() const
LOCKS_EXCLUDED(entries_mu_);
bool ShouldInvokeGarbageCollectionUnlocked() const
SHARED_LOCKS_REQUIRED(entries_mu_);
bool ShouldContinueGarbageCollectionUnlocked() const
SHARED_LOCKS_REQUIRED(entries_mu_);
void RunGarbageCollection(GarbageCollectionStat* stat)
LOCKS_EXCLUDED(entries_mu_);
void WakeGCThread() LOCKS_EXCLUDED(entries_mu_);
void WaitUntilGarbageCollectionThreadDone() LOCKS_EXCLUDED(entries_mu_);
// Used only for test.
void SetReady(bool ready);
// Full path of cache directory + key prefix.
std::string CacheDirWithKeyPrefix(absl::string_view key) const;
// Full path of cache directory + key prefix + key.
std::string CacheFilePath(absl::string_view key) const;
static LocalOutputCache* instance_;
// LocalOutputCache configurations
const std::string cache_dir_;
const std::int64_t max_cache_amount_byte_;
const std::int64_t threshold_cache_amount_byte_;
const size_t max_cache_items_;
const size_t threshold_cache_items_;
// Using in initial load of cache entries.
// After loading all cache entries, |ready_| will become true.
mutable Lock ready_mu_;
ConditionVariable ready_cond_;
bool ready_ GUARDED_BY(ready_mu_);
// cache entries. Older cache is first.
using CacheEntryMap =
LinkedUnorderedMap<SHA256HashValue, CacheEntry, SHA256HashValueHasher>;
mutable ReadWriteLock entries_mu_ ACQUIRED_AFTER(gc_mu_);
CacheEntryMap entries_ GUARDED_BY(entries_mu_);
// total cache amount in bytes.
std::int64_t entries_total_cache_amount_ GUARDED_BY(entries_mu_);
mutable Lock gc_mu_;
ConditionVariable gc_cond_;
bool gc_should_done_ GUARDED_BY(gc_mu_);
bool gc_working_ GUARDED_BY(gc_mu_);
StatsCounter stats_save_success_;
StatsCounter stats_save_success_time_ms_;
StatsCounter stats_save_failure_;
StatsCounter stats_lookup_success_;
StatsCounter stats_lookup_success_time_ms_;
StatsCounter stats_lookup_miss_;
StatsCounter stats_lookup_failure_;
StatsCounter stats_commit_success_;
StatsCounter stats_commit_success_time_ms_;
StatsCounter stats_commit_failure_;
StatsCounter stats_gc_count_;
StatsCounter stats_gc_total_time_ms_;
StatsCounter stats_gc_removed_items_;
StatsCounter stats_gc_removed_bytes_;
StatsCounter stats_gc_failed_items_;
friend class LocalOutputCacheTest;
};
} // namespace devtools_goma
#endif // DEVTOOLS_GOMA_CLIENT_LOCAL_OUTPUT_CACHE_H_