blob: deec826000c67d15ab94f647f2f64a87b99e19ac [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 "kudu/codegen/code_cache.h"
#include <cstring>
#include <memory>
#include <utility>
#include <glog/logging.h>
#include "kudu/codegen/jit_wrapper.h"
#include "kudu/gutil/port.h"
#include "kudu/gutil/ref_counted.h"
#include "kudu/util/cache.h"
#include "kudu/util/faststring.h"
#include "kudu/util/slice.h"
#include "kudu/util/status.h"
namespace kudu {
namespace codegen {
namespace {
// The values we store in cache are actually just pointers to JITWrapper
// objects. This returns the 'unwrapped' pointer from a cache value.
JITWrapper* CacheValueToJITWrapper(Slice val) {
JITWrapper* jw;
DCHECK_EQ(val.size(), sizeof(jw));
memcpy(&jw, val.data(), sizeof(jw));
return jw;
}
} // anonymous namespace
// When an entry is evicted from the cache, we need to also
// decrement the ref-count on the wrapper, since the cache
// itself isn't managing all of the associated objects.
class CodeCache::EvictionCallback : public Cache::EvictionCallback {
public:
EvictionCallback() {}
virtual void EvictedEntry(Slice key, Slice value) OVERRIDE {
CacheValueToJITWrapper(value)->Release();
}
private:
DISALLOW_COPY_AND_ASSIGN(EvictionCallback);
};
CodeCache::CodeCache(size_t capacity)
: cache_(NewCache(capacity, "code_cache")) {
eviction_callback_.reset(new EvictionCallback);
}
CodeCache::~CodeCache() {}
Status CodeCache::AddEntry(const scoped_refptr<JITWrapper>& value) {
// Get the key
faststring key;
RETURN_NOT_OK(value->EncodeOwnKey(&key));
JITWrapper* val = value.get();
size_t val_len = sizeof(val);
// We CHECK_NOTNULL because this is always a DRAM-based cache, and if allocation
// failed, we'd just crash the process.
auto pending(cache_->Allocate(Slice(key), val_len, /*charge = */1));
CHECK(pending);
memcpy(cache_->MutableValue(&pending), &val, val_len);
// Because Cache only accepts void* values, we store just the JITWrapper*
// and increase its ref count.
value->AddRef();
// Insert into cache and release the handle (we have a local copy of a refptr).
auto inserted(cache_->Insert(std::move(pending), eviction_callback_.get()));
DCHECK(inserted);
return Status::OK();
}
scoped_refptr<JITWrapper> CodeCache::Lookup(const Slice& key) {
// Look up in Cache after generating key, returning NULL if not found.
auto found(cache_->Lookup(key, Cache::EXPECT_IN_CACHE));
if (!found) {
return scoped_refptr<JITWrapper>();
}
// Retrieve the value
return CacheValueToJITWrapper(cache_->Value(found));
}
} // namespace codegen
} // namespace kudu