blob: 424943643dcc0ab693d810186aa3bd1878307268 [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.
#pragma once
#include <cstddef>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <glog/logging.h>
#include "kudu/gutil/macros.h"
#include "kudu/util/cache.h"
#include "kudu/util/locks.h"
#include "kudu/util/slice.h"
namespace kudu {
struct CacheMetrics;
namespace master {
class GetTableLocationsRequestPB;
class GetTableLocationsResponsePB;
class TableLocationsCache final {
public:
// The handle for an entry in the cache.
class EntryHandle {
public:
// Construct an empty/nullptr handle.
EntryHandle();
~EntryHandle() = default;
EntryHandle(EntryHandle&& other) noexcept;
EntryHandle& operator=(EntryHandle&& other) noexcept;
explicit operator bool() const noexcept {
return ptr_ != nullptr;
}
// No modifications of the value are allowed through EntryHandle.
const GetTableLocationsResponsePB& value() const {
DCHECK(ptr_);
return *ptr_;
}
private:
friend class TableLocationsCache;
DISALLOW_COPY_AND_ASSIGN(EntryHandle);
EntryHandle(GetTableLocationsResponsePB* ptr, Cache::UniqueHandle handle);
GetTableLocationsResponsePB* ptr_;
Cache::UniqueHandle handle_;
};
// Create a new cache (LRU eviction policy) with the specified capacity.
explicit TableLocationsCache(size_t capacity_bytes);
~TableLocationsCache() = default;
// Retrieve an entry from the cache for the specified table identifier
// and parameters of GetTableLocationsRequest.
//
// Cached key/value pairs may still be evicted even with an outstanding
// handle, but a cached value won't be destroyed until the handle goes
// out of scope.
EntryHandle Get(const std::string& table_id,
size_t num_tablets,
const std::string& first_tablet_id,
const GetTableLocationsRequestPB& req);
// For the specified key, add an entry into the cache or replace already
// existing one. This method returns a smart pointer for the entry's handle.
//
// Put() evicts already existing entry with the same key (if any), effectively
// replacing corresponding entry in the cache as the result.
EntryHandle Put(const std::string& table_id,
size_t num_tablets,
const std::string& first_tablet_id,
const GetTableLocationsRequestPB& req,
std::unique_ptr<GetTableLocationsResponsePB> val);
// Remove all entries for the specified table identifier.
void Remove(const std::string& table_id);
// Set metrics for the cache.
void SetMetrics(std::unique_ptr<CacheMetrics> metrics);
private:
friend class EvictionCallback;
// An entry to store in the underlying LRU cache.
struct Entry {
// Raw pointer to the 'value'. The cache owns the memory allocated and takes
// care of deallocating it upon call of EvictionCallback::EvictedEntry()
// by the underlying cache instance.
GetTableLocationsResponsePB* val_ptr;
};
// Callback invoked by the underlying LRU cache when a cached entry's
// reference count reaches zero and is evicted.
class EvictionCallback : public Cache::EvictionCallback {
public:
explicit EvictionCallback(TableLocationsCache* cache);
// This method called upon evicting an entry with the specified key ('key')
// and value ('val').
void EvictedEntry(Slice key, Slice val) override;
private:
TableLocationsCache* cache_;
DISALLOW_COPY_AND_ASSIGN(EvictionCallback);
};
// Build a key for the item in the cache given table identifier
// and the information in the request. The key is a composite one and includes
// request parameters because the response depends on them, so there might be
// multiple cached items in the cache for the same table identifier.
static std::string BuildKey(const std::string& table_id,
size_t num_tablets,
const std::string& first_tablet_id,
const GetTableLocationsRequestPB& req);
// Invoked whenever a cached entry reaches zero reference count, i.e. it was
// removed from the cache and there aren't any other references
// floating around.
EvictionCallback eviction_cb_;
// The underlying LRU cache instance.
std::unique_ptr<Cache> cache_;
// A convenience dictionary to keep correspondence between a table's
// identifier and cached locations for the table. This map is used when
// invalidating element in the cache given table identifier.
std::unordered_map<std::string, std::unordered_set<std::string>> keys_by_table_id_;
// A synchronisation primitive to guard access to keys_by_table_id_.
simple_spinlock keys_by_table_id_lock_;
DISALLOW_COPY_AND_ASSIGN(TableLocationsCache);
};
} // namespace master
} // namespace kudu