LevelDB源碼分析-Write

來源:互聯網
上載者:User

標籤:current   love   mat   option   cte   turn   push   during   tor   

Write

LevelDB提供了write和put兩個介面進行插入操作,但是put實際上是調用write實現的,所以我在這裡只分析write函數:

Status DBImpl::Write(const WriteOptions &options, WriteBatch *my_batch)

首先初始化一個Writer對象,Writer對象用於封裝一個插入操作,LevelDB用一個deque來管理Writer對象,建立的Writer對象被插入到這個deque的尾部,如果Writer對象未被處理且不在deque頭部,則會一直等待:

    Writer w(&mutex_);    w.batch = my_batch;    w.sync = options.sync;    w.done = false;    MutexLock l(&mutex_);    writers_.push_back(&w);    while (!w.done && &w != writers_.front())    {        w.cv.Wait();    }    if (w.done)    {        return w.status;    }

然後調用MakeRoomForWrite函數保證memtable中有插入的空間:

    // May temporarily unlock and wait.    Status status = MakeRoomForWrite(my_batch == nullptr);    uint64_t last_sequence = versions_->LastSequence();    Writer *last_writer = &w;

接下來調用BuildBatchGroup函數將此時writers_隊列中的Writer對象全部封裝為一個WriteBatch,也就是說LevelDB實際上一次會處理當前的所有插入任務:

    if (status.ok() && my_batch != nullptr)    { // nullptr batch is for compactions        WriteBatch *updates = BuildBatchGroup(&last_writer);        WriteBatchInternal::SetSequence(updates, last_sequence + 1);        last_sequence += WriteBatchInternal::Count(updates);

再調用函數將KV值插入memtable中:

        // Add to log and apply to memtable.  We can release the lock        // during this phase since &w is currently responsible for logging        // and protects against concurrent loggers and concurrent writes        // into mem_.        {            mutex_.Unlock();            status = log_->AddRecord(WriteBatchInternal::Contents(updates));            bool sync_error = false;            if (status.ok() && options.sync)            {                status = logfile_->Sync();                if (!status.ok())                {                    sync_error = true;                }            }            if (status.ok())            {                status = WriteBatchInternal::InsertInto(updates, mem_);            }            mutex_.Lock();            if (sync_error)            {                // The state of the log file is indeterminate: the log record we                // just added may or may not show up when the DB is re-opened.                // So we force the DB into a mode where all future writes fail.                RecordBackgroundError(status);            }        }        if (updates == tmp_batch_)            tmp_batch_->Clear();        versions_->SetLastSequence(last_sequence);    }

將隊列中此次已經處理的Writer對象都刪除,並且給那些Writer對象發送訊號,使它們能夠結束自己的任務:

    while (true)    {        Writer *ready = writers_.front();        writers_.pop_front();        if (ready != &w)        {            ready->status = status;            ready->done = true;            ready->cv.Signal();        }        if (ready == last_writer)            break;    }

如果當前隊列中有新的Writer對象,發送訊號啟用隊首的Writer對象:

    // Notify new head of write queue    if (!writers_.empty())    {        writers_.front()->cv.Signal();    }    return status;

Write函數調用的MakeRoomForWrite函數為:

// REQUIRES: mutex_ is held// REQUIRES: this thread is currently at the front of the writer queueStatus DBImpl::MakeRoomForWrite(bool force)

函數將一直進行迴圈,判斷各個條件並執行相應操作,直到memtable中有足夠空間可以插入。

如果level0的檔案數量超過閾值,且這是第一次檢測到這種情況,那麼sleep1ms:

        else if (            allow_delay &&            versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger)        {            // We are getting close to hitting a hard limit on the number of            // L0 files.  Rather than delaying a single write by several            // seconds when we hit the hard limit, start delaying each            // individual write by 1ms to reduce latency variance.  Also,            // this delay hands over some CPU to the compaction thread in            // case it is sharing the same core as the writer.            mutex_.Unlock();            env_->SleepForMicroseconds(1000);            allow_delay = false; // Do not delay a single write more than once            mutex_.Lock();        }

如果當前memtable中有足夠的空間,則跳出迴圈:

        else if (!force &&                 (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size))        {            // There is room in current memtable            break;        }

如果當前memtable中空間不足,immutable memtable也沒有被寫出,則等待compact的背景線程完成compact(immutable memtable需要compact):

        else if (imm_ != nullptr)        {            // We have filled up the current memtable, but the previous            // one is still being compacted, so we wait.            Log(options_.info_log, "Current memtable full; waiting...\n");            background_work_finished_signal_.Wait();        }

如果當前memtable空間不足,level0中的檔案數量超過了閾值,且不是第一次檢測到這種情況,則等待compact的背景線程完成compact(level0需要compact):

        else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger)        {            // There are too many level-0 files.            Log(options_.info_log, "Too many L0 files; waiting...\n");            background_work_finished_signal_.Wait();        }

如果以上情況都不存在,則說明可以將當前memtable寫入immutable memtable,然後建立一個新的memtable,當然需要調用MaybeScheduleCompaction函數,因為產生了immutable memtable需要compact:

        else        {            // Attempt to switch to a new memtable and trigger compaction of old            assert(versions_->PrevLogNumber() == 0);            uint64_t new_log_number = versions_->NewFileNumber();            WritableFile *lfile = nullptr;            s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);            if (!s.ok())            {                // Avoid chewing through file number space in a tight loop.                versions_->ReuseFileNumber(new_log_number);                break;            }            delete log_;            delete logfile_;            logfile_ = lfile;            logfile_number_ = new_log_number;            log_ = new log::Writer(lfile);            imm_ = mem_;            has_imm_.Release_Store(imm_);            mem_ = new MemTable(internal_comparator_);            mem_->Ref();            force = false; // Do not force another compaction if have room            MaybeScheduleCompaction();        }

231 Love u

LevelDB源碼分析-Write

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.