REQUIRES: mutex_ is held REQUIRES: this thread is currently at the front of the writer queue
| 1319 | // REQUIRES: mutex_ is held |
| 1320 | // REQUIRES: this thread is currently at the front of the writer queue |
| 1321 | Status DBImpl::MakeRoomForWrite(bool force) { |
| 1322 | mutex_.AssertHeld(); |
| 1323 | assert(!writers_.empty()); |
| 1324 | bool allow_delay = !force; |
| 1325 | Status s; |
| 1326 | while (true) { |
| 1327 | if (!bg_error_.ok()) { |
| 1328 | // Yield previous error |
| 1329 | s = bg_error_; |
| 1330 | break; |
| 1331 | } else if (allow_delay && versions_->NumLevelFiles(0) >= |
| 1332 | config::kL0_SlowdownWritesTrigger) { |
| 1333 | // We are getting close to hitting a hard limit on the number of |
| 1334 | // L0 files. Rather than delaying a single write by several |
| 1335 | // seconds when we hit the hard limit, start delaying each |
| 1336 | // individual write by 1ms to reduce latency variance. Also, |
| 1337 | // this delay hands over some CPU to the compaction thread in |
| 1338 | // case it is sharing the same core as the writer. |
| 1339 | mutex_.Unlock(); |
| 1340 | env_->SleepForMicroseconds(1000); |
| 1341 | allow_delay = false; // Do not delay a single write more than once |
| 1342 | mutex_.Lock(); |
| 1343 | } else if (!force && |
| 1344 | (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { |
| 1345 | // There is room in current memtable |
| 1346 | break; |
| 1347 | } else if (imm_ != nullptr) { |
| 1348 | // We have filled up the current memtable, but the previous |
| 1349 | // one is still being compacted, so we wait. |
| 1350 | Log(options_.info_log, "Current memtable full; waiting...\n"); |
| 1351 | background_work_finished_signal_.Wait(); |
| 1352 | } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { |
| 1353 | // There are too many level-0 files. |
| 1354 | Log(options_.info_log, "Too many L0 files; waiting...\n"); |
| 1355 | background_work_finished_signal_.Wait(); |
| 1356 | } else { |
| 1357 | // Attempt to switch to a new memtable and trigger compaction of old |
| 1358 | assert(versions_->PrevLogNumber() == 0); |
| 1359 | uint64_t new_log_number = versions_->NewFileNumber(); |
| 1360 | WritableFile* lfile = nullptr; |
| 1361 | s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); |
| 1362 | if (!s.ok()) { |
| 1363 | // Avoid chewing through file number space in a tight loop. |
| 1364 | versions_->ReuseFileNumber(new_log_number); |
| 1365 | break; |
| 1366 | } |
| 1367 | delete log_; |
| 1368 | delete logfile_; |
| 1369 | logfile_ = lfile; |
| 1370 | logfile_number_ = new_log_number; |
| 1371 | log_ = new log::Writer(lfile); |
| 1372 | imm_ = mem_; |
| 1373 | has_imm_.store(true, std::memory_order_release); |
| 1374 | mem_ = new MemTable(internal_comparator_); |
| 1375 | mem_->Ref(); |
| 1376 | force = false; // Do not force another compaction if have room |
| 1377 | MaybeScheduleCompaction(); |
| 1378 | } |
nothing calls this directly
no test coverage detected