| 283 | std::optional<std::pair<uint64_t, int32_t>> SsdFile::getSpace( |
| 284 | const std::vector<CachePin>& pins, |
| 285 | int32_t begin) { |
| 286 | int32_t next = begin; |
| 287 | std::lock_guard<std::shared_mutex> l(mutex_); |
| 288 | for (;;) { |
| 289 | if (writableRegions_.empty()) { |
| 290 | if (!growOrEvictLocked()) { |
| 291 | return std::nullopt; |
| 292 | } |
| 293 | } |
| 294 | assert(!writableRegions_.empty()); |
| 295 | const auto region = writableRegions_[0]; |
| 296 | const auto offset = regionSizes_[region]; |
| 297 | auto available = kRegionSize - offset; |
| 298 | int64_t toWrite = 0; |
| 299 | for (; next < pins.size(); ++next) { |
| 300 | auto* entry = pins[next].checkedEntry(); |
| 301 | if (entry->size() > available) { |
| 302 | break; |
| 303 | } |
| 304 | available -= entry->size(); |
| 305 | toWrite += entry->size(); |
| 306 | } |
| 307 | if (toWrite > 0) { |
| 308 | // At least some pins got space from this region. If the region is full |
| 309 | // the next call will get space from another region. |
| 310 | regionSizes_[region] += toWrite; |
| 311 | return std::make_pair<uint64_t, int32_t>( |
| 312 | region * kRegionSize + offset, toWrite); |
| 313 | } |
| 314 | |
| 315 | tracker_.regionFilled(region); |
| 316 | writableRegions_.erase(writableRegions_.begin()); |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | bool SsdFile::growOrEvictLocked() { |
| 321 | if (numRegions_ < maxRegions_) { |
| 322 | const auto newSize = (numRegions_ + 1) * kRegionSize; |
| 323 | const auto rc = ::ftruncate(fd_, newSize); |
nothing calls this directly
no test coverage detected