| 141 | } |
| 142 | |
| 143 | Status FileHandleCache::GetFileHandle(const hdfsFS& fs, std::string* fname, int64_t mtime, |
| 144 | bool require_new_handle, FileHandleCache::Accessor* accessor, bool* cache_hit) { |
| 145 | DCHECK_GT(mtime, 0); |
| 146 | // Hash the key and get appropriate partition |
| 147 | int index = HashUtil::Hash(fname->data(), fname->size(), 0) % cache_partitions_.size(); |
| 148 | FileHandleCachePartition& p = cache_partitions_[index]; |
| 149 | |
| 150 | auto cache_key = std::make_pair(*fname, mtime); |
| 151 | |
| 152 | // If this requires a new handle, skip to the creation codepath. Otherwise, |
| 153 | // find an unused entry with the same mtime |
| 154 | if (!require_new_handle) { |
| 155 | auto cache_accessor = p.cache.Get(cache_key); |
| 156 | |
| 157 | if (cache_accessor.Get()) { |
| 158 | // Found a handler in cache and reserved it |
| 159 | *cache_hit = true; |
| 160 | accessor->Set(std::move(cache_accessor)); |
| 161 | return Status::OK(); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | // There was no entry that was free or caller asked for a new handle |
| 166 | *cache_hit = false; |
| 167 | |
| 168 | // Emplace a new file handle and get access |
| 169 | auto accessor_tmp = p.cache.EmplaceAndGet(cache_key, fs, fname, mtime); |
| 170 | |
| 171 | // Opening a file handle requires talking to the NameNode so it can take some time. |
| 172 | Status status = accessor_tmp.Get()->Init(hdfs_monitor_); |
| 173 | if (UNLIKELY(!status.ok())) { |
| 174 | // Removing the handler from the cache after failed initialization. |
| 175 | accessor_tmp.Destroy(); |
| 176 | return status; |
| 177 | } |
| 178 | |
| 179 | // Moving the cache accessor to the in/out parameter |
| 180 | accessor->Set(std::move(accessor_tmp)); |
| 181 | |
| 182 | return Status::OK(); |
| 183 | } |
| 184 | |
| 185 | void FileHandleCache::EvictHandlesLoop() { |
| 186 | while (true) { |