blob: 2bf25bb78c2ae62741233b6d369e5e1f9ae83c43 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <gflags/gflags.h>
#include "kudu/cfile/block_cache.h"
#include "kudu/gutil/port.h"
#include "kudu/util/cache.h"
#include "kudu/util/flag_tags.h"
#include "kudu/util/metrics.h"
#include "kudu/util/slice.h"
#include "kudu/util/string_case.h"
DEFINE_int64(block_cache_capacity_mb, 512, "block cache capacity in MB");
TAG_FLAG(block_cache_capacity_mb, stable);
DEFINE_string(block_cache_type, "DRAM",
"Which type of block cache to use for caching data. "
"Valid choices are 'DRAM' or 'NVM'. DRAM, the default, "
"caches data in regular memory. 'NVM' caches data "
"in a memory-mapped file using the NVML library.");
TAG_FLAG(block_cache_type, experimental);
namespace kudu {
class MetricEntity;
namespace cfile {
struct CacheKey {
CacheKey(BlockCache::FileId file_id, uint64_t offset) :
file_id_(file_id.id()),
offset_(offset)
{}
const Slice slice() const {
return Slice(reinterpret_cast<const uint8_t *>(this), sizeof(*this));
}
uint64_t file_id_;
uint64_t offset_;
} PACKED;
namespace {
class Deleter : public CacheDeleter {
public:
explicit Deleter(Cache* cache) : cache_(cache) {
}
virtual void Delete(const Slice& slice, void* value) OVERRIDE {
Slice *value_slice = reinterpret_cast<Slice *>(value);
// The actual data was allocated from the cache's memory
// (i.e. it may be in nvm)
cache_->Free(value_slice->mutable_data());
delete value_slice;
}
private:
Cache* cache_;
DISALLOW_COPY_AND_ASSIGN(Deleter);
};
Cache* CreateCache(int64_t capacity) {
CacheType t;
ToUpperCase(FLAGS_block_cache_type, &FLAGS_block_cache_type);
if (FLAGS_block_cache_type == "NVM") {
t = NVM_CACHE;
} else if (FLAGS_block_cache_type == "DRAM") {
t = DRAM_CACHE;
} else {
LOG(FATAL) << "Unknown block cache type: '" << FLAGS_block_cache_type
<< "' (expected 'DRAM' or 'NVM')";
}
return NewLRUCache(t, capacity, "block_cache");
}
} // anonymous namespace
BlockCache::BlockCache()
: cache_(CreateCache(FLAGS_block_cache_capacity_mb * 1024 * 1024)) {
deleter_.reset(new Deleter(cache_.get()));
}
BlockCache::BlockCache(size_t capacity)
: cache_(CreateCache(capacity)) {
deleter_.reset(new Deleter(cache_.get()));
}
uint8_t* BlockCache::Allocate(size_t size) {
return cache_->Allocate(size);
}
void BlockCache::Free(uint8_t* p) {
cache_->Free(p);
}
uint8_t* BlockCache::MoveToHeap(uint8_t* p, size_t size) {
return cache_->MoveToHeap(p, size);
}
bool BlockCache::Lookup(FileId file_id, uint64_t offset, Cache::CacheBehavior behavior,
BlockCacheHandle *handle) {
CacheKey key(file_id, offset);
Cache::Handle *h = cache_->Lookup(key.slice(), behavior);
if (h != nullptr) {
handle->SetHandle(cache_.get(), h);
}
return h != nullptr;
}
bool BlockCache::Insert(FileId file_id, uint64_t offset, const Slice &block_data,
BlockCacheHandle *inserted) {
CacheKey key(file_id, offset);
// Allocate a copy of the value Slice (not the referred-to-data!)
// for insertion in the cache.
gscoped_ptr<Slice> value(new Slice(block_data));
Cache::Handle *h = cache_->Insert(key.slice(), value.get(), value->size(),
deleter_.get());
if (h != nullptr) {
inserted->SetHandle(cache_.get(), h);
ignore_result(value.release());
}
return h != nullptr;
}
void BlockCache::StartInstrumentation(const scoped_refptr<MetricEntity>& metric_entity) {
cache_->SetMetrics(metric_entity);
}
} // namespace cfile
} // namespace kudu