| /** @file cache.cc | |
| Metadata cache to store object sizes. | |
| @section license License | |
| 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 "ObjectSizeCache.h" | |
| #include <cassert> | |
| ObjectSizeCache::ObjectSizeCache(cache_size_type cache_size) | |
| : _cache_capacity(cache_size), _urls(cache_size), _object_sizes(cache_size, 0), _visits(cache_size, false) | |
| { | |
| } | |
| std::optional<uint64_t> | |
| ObjectSizeCache::get(const std::string_view url) | |
| { | |
| std::lock_guard lock{_mutex}; | |
| if (auto it = _index.find(url); it != _index.end()) { | |
| // Cache hit | |
| cache_size_type i = it->second; | |
| _visits[i] = true; | |
| assert(url == _urls[i]); | |
| return _object_sizes[i]; | |
| } else { | |
| // Cache miss | |
| return std::nullopt; | |
| } | |
| } | |
| void | |
| ObjectSizeCache::set(const std::string_view url, uint64_t object_size) | |
| { | |
| std::lock_guard lock{_mutex}; | |
| cache_size_type i; | |
| if (auto it = _index.find(url); it != _index.end()) { | |
| // Already exists in cache. Overwrite. | |
| i = it->second; | |
| } else { | |
| // Doesn't exist in cache. Evict something else. | |
| find_eviction_slot(); | |
| i = _hand; | |
| _urls[i] = url; | |
| _index[_urls[i]] = _hand; | |
| _hand++; | |
| if (_hand >= _cache_capacity) { | |
| _hand = 0; | |
| } | |
| } | |
| _object_sizes[i] = object_size; | |
| } | |
| void | |
| ObjectSizeCache::remove(const std::string_view url) | |
| { | |
| std::lock_guard lock{_mutex}; | |
| if (auto it = _index.find(url); it != _index.end()) { | |
| cache_size_type i = it->second; | |
| _visits[i] = false; | |
| _urls[i].erase(); | |
| _index.erase(it); | |
| } | |
| } | |
| /** | |
| * @brief Make _hand point to the next entry that should be replaced, and clear that entry if it exists. | |
| * | |
| */ | |
| void | |
| ObjectSizeCache::find_eviction_slot() | |
| { | |
| while (_visits[_hand]) { | |
| _visits[_hand] = false; | |
| _hand++; | |
| if (_hand >= _cache_capacity) { | |
| _hand = 0; | |
| } | |
| } | |
| std::string_view evicted_url = _urls[_hand]; | |
| if (!evicted_url.empty()) { | |
| auto it = _index.find(evicted_url); | |
| assert(it != _index.end()); | |
| _index.erase(it); | |
| _urls[_hand].erase(); | |
| } | |
| } | |
| ObjectSizeCache::cache_size_type | |
| ObjectSizeCache::cache_capacity() | |
| { | |
| return _cache_capacity; | |
| } | |
| ObjectSizeCache::cache_size_type | |
| ObjectSizeCache::cache_count() | |
| { | |
| return _index.size(); | |
| } |