OmniSciDB  06b3bd477c
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ForeignStorageCache.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 OmniSci, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  TODO(Misiu): A lot of methods here can be made asyncronous. It may be worth an
19  investigation to determine if it's worth adding async versions of them for performance
20  reasons.
21 */
22 
23 #include "ForeignStorageCache.h"
24 
25 #include "Shared/measure.h"
26 
27 namespace foreign_storage {
28 using read_lock = mapd_shared_lock<mapd_shared_mutex>;
29 using write_lock = mapd_unique_lock<mapd_shared_mutex>;
30 
31 void ForeignStorageCache::cacheChunk(const ChunkKey& chunk_key, AbstractBuffer* buffer) {
32  auto timer = DEBUG_TIMER(__func__);
34  if (isCacheFull()) {
36  }
37  eviction_alg_->touchChunk(chunk_key);
38  cached_chunks_.emplace(chunk_key);
39  global_file_mgr_->putBuffer(chunk_key, buffer);
40 }
41 
43  auto timer = DEBUG_TIMER(__func__);
44  {
46  if (cached_chunks_.find(chunk_key) == cached_chunks_.end()) {
47  return nullptr;
48  }
49  }
51  eviction_alg_->touchChunk(chunk_key);
52  return global_file_mgr_->getBuffer(chunk_key);
53 }
54 
56  auto timer = DEBUG_TIMER(__func__);
58  return (cached_metadata_.find(chunk_key) != cached_metadata_.end());
59 }
60 
62  auto timer = DEBUG_TIMER(__func__);
64  for (auto& [chunk_key, metadata] : metadata_vec) {
65  cached_metadata_[chunk_key] = metadata;
66  }
67 }
68 
70  ChunkMetadataVector& metadata_vec,
71  const ChunkKey& chunk_prefix) {
72  auto timer = DEBUG_TIMER(__func__);
73  read_lock r_lock(metadata_mutex_);
74  ChunkKey upper_prefix(chunk_prefix);
75  upper_prefix.push_back(std::numeric_limits<int>::max());
76  auto end_it = cached_metadata_.upper_bound(static_cast<const ChunkKey>(upper_prefix));
77  for (auto meta_it = cached_metadata_.lower_bound(chunk_prefix); meta_it != end_it;
78  ++meta_it) {
79  metadata_vec.push_back(*meta_it);
80  }
81 }
82 
84  auto timer = DEBUG_TIMER(__func__);
86  ChunkKey upper_prefix(chunk_prefix);
87  upper_prefix.push_back(std::numeric_limits<int>::max());
88  auto end_it = cached_metadata_.upper_bound(static_cast<const ChunkKey>(upper_prefix));
89  for (auto meta_it = cached_metadata_.lower_bound(chunk_prefix); meta_it != end_it;
90  ++meta_it) {
91  return true;
92  }
93  return false;
94 }
95 
97  CHECK(chunk_prefix.size() == 2U);
98  auto timer = DEBUG_TIMER(__func__);
99  ChunkKey upper_prefix(chunk_prefix);
100  upper_prefix.push_back(std::numeric_limits<int>::max());
101  {
102  write_lock w_lock(chunks_mutex_);
103  // Delete chunks for prefix
104  auto end_it = cached_chunks_.upper_bound(static_cast<const ChunkKey>(upper_prefix));
105  for (auto chunk_it = cached_chunks_.lower_bound(chunk_prefix); chunk_it != end_it;) {
106  chunk_it = eraseChunk(chunk_it);
107  }
108  }
109  {
110  write_lock w_lock(metadata_mutex_);
111  // Delete metadata for prefix
112  cached_metadata_.erase(
113  cached_metadata_.lower_bound(chunk_prefix),
114  cached_metadata_.upper_bound(static_cast<const ChunkKey>(upper_prefix)));
115  }
116 }
117 
119  auto timer = DEBUG_TIMER(__func__);
120  {
121  write_lock w_lock(chunks_mutex_);
122  for (auto chunk_it = cached_chunks_.begin(); chunk_it != cached_chunks_.end();) {
123  chunk_it = eraseChunk(chunk_it);
124  }
125  }
126  {
127  write_lock w_lock(metadata_mutex_);
128  cached_metadata_.clear();
129  }
130 }
131 
132 void ForeignStorageCache::setLimit(size_t limit) {
133  auto timer = DEBUG_TIMER(__func__);
134  write_lock w_lock(chunks_mutex_);
135  entry_limit_ = limit;
136  // Need to make sure cache doesn't have more entries than the limit
137  // in case the limit was lowered.
138  while (cached_chunks_.size() > entry_limit_) {
139  evictChunkByAlg();
140  }
141 }
142 
143 // Private functions. Locks should be acquired in the public interface before calling
144 // these functions.
145 // This function assumes the chunk has been erased from the eviction algorithm already.
147  auto timer = DEBUG_TIMER(__func__);
148  global_file_mgr_->deleteBuffer(chunk_key);
149  cached_chunks_.erase(chunk_key);
150 }
151 
152 // This function assumes the chunk has not already been erased from the eviction alg.
153 std::set<ChunkKey>::iterator ForeignStorageCache::eraseChunk(
154  const std::set<ChunkKey>::iterator& chunk_it) {
155  auto timer = DEBUG_TIMER(__func__);
156  global_file_mgr_->deleteBuffer(*chunk_it);
157  eviction_alg_->removeChunk(*chunk_it);
158  return cached_chunks_.erase(chunk_it);
159 }
160 
162  auto timer = DEBUG_TIMER(__func__);
163  eraseChunk(eviction_alg_->evictNextChunk());
164 }
165 
167  auto timer = DEBUG_TIMER(__func__);
168  return (cached_chunks_.size() >= entry_limit_);
169 }
170 
172  auto timer = DEBUG_TIMER(__func__);
173  std::string ret_string = "Cached chunks:\n";
174  for (const auto& chunk_key : cached_chunks_) {
175  ret_string += " " + showChunk(chunk_key) + "\n";
176  }
177  return ret_string;
178 }
179 
181  auto timer = DEBUG_TIMER(__func__);
182  std::string ret_string = "Cached ChunkMetadata:\n";
183  for (const auto& meta_pair : cached_metadata_) {
184  ret_string += " " + showChunk(meta_pair.first) + "\n";
185  }
186  return ret_string;
187 }
188 
191 }
192 
193 } // namespace foreign_storage
AbstractBuffer * putBuffer(const ChunkKey &key, AbstractBuffer *d, const size_t numBytes=0) override
Puts the contents of d into the Chunk with the given key.
Definition: GlobalFileMgr.h:95
std::vector< int > ChunkKey
Definition: types.h:35
std::unique_ptr< CacheEvictionAlgorithm > eviction_alg_
File_Namespace::GlobalFileMgr * global_file_mgr_
AbstractBuffer * getCachedChunkIfExists(const ChunkKey &)
CHECK(cgen_state)
std::set< ChunkKey >::iterator eraseChunk(const std::set< ChunkKey >::iterator &)
bool hasCachedMetadataForKeyPrefix(const ChunkKey &)
std::vector< std::pair< ChunkKey, std::shared_ptr< ChunkMetadata >>> ChunkMetadataVector
An AbstractBuffer is a unit of data management for a data manager.
std::string showChunk(const ChunkKey &key)
Definition: types.h:37
void deleteBuffer(const ChunkKey &key, const bool purge=true) override
Deletes the chunk with the specified key.
Definition: GlobalFileMgr.h:71
AbstractBuffer * getBuffer(const ChunkKey &key, const size_t numBytes=0) override
Returns the a pointer to the chunk with the specified key.
Definition: GlobalFileMgr.h:79
mapd_shared_lock< mapd_shared_mutex > read_lock
#define DEBUG_TIMER(name)
Definition: Logger.h:313
void cacheMetadataVec(ChunkMetadataVector &)
mapd_unique_lock< mapd_shared_mutex > write_lock
std::map< ChunkKey, std::shared_ptr< ChunkMetadata > > cached_metadata_
void cacheChunk(const ChunkKey &, AbstractBuffer *)
void getCachedMetadataVecForKeyPrefix(ChunkMetadataVector &, const ChunkKey &)