RocksDB——Put

RocksDB——Put

涉及的數據結構概覽

相關class以及對應的源文件

DB db/db.h
DB include/rocksdb/db.h
DB_impl db/db_impl.cc, db/db_impl_write.cc
WriteBatch include/rocksdb/write_batch.h, db/write_batch.cc
WriteThread db/write_thread.h, db/write_thread.cc
WriteBatchInternal db/write_batch_internal.h, db/write_batch.cc
WriteOptions include/rocksdb/options.h
MemtableInserter db/write_batch.cc

調用關系圖

image

默認配置下的put流程

外部調用流程

image

RocksDB從調用Put接口到真正開始執行Put操作之間還有幾層函數調用,在這幾層函數調用中主要進行數據的封裝操作,最后進入DB_Impl::WriteImpl執行寫操作過程。

首先是外部的Put接口,RocksDB提供了兩個Put接口,分別是指定了column_family以及沒有指定column_family的接口,其中沒有指定column_family的Put是調用指定column_family的Put并指定默認的column family(default)封裝實現的。

DBImpl的Put調用DB的Put實現,兩者定義一樣,參數直接傳遞

DB的Put會將傳入的column_family、key以及value封裝到WriteBatch中,然后調用Write函數,傳入WriteOption以及WriteBatch

Write函數直接調用WriteImple函數進入寫流程

WriteImpl

傳入WriteImpl的參數為:

const WriteOptions& write_options
WriteBatch* my_batch
WriteCallback* callback
uint64_t* log_used
uint64_t log_ref
bool disable_memtable
uint64_t* seq_used
size_t batch_cnt
PreReleaseCallback* pre_release_callback

(由Write調用的時候只提供了WriteOptions、WriteBatch*以及WriteCallback*(TODO:關于傳入參數的個數)

初步處理

進入WriteImpl之后首先判斷幾個設置參數并根據設置參數執行不同的操作:

  • tracer_:如果為true,則調用tracer_->Write,傳入my_batch(TODO:tracer是干啥的)
  • syncdisableWAL設置沖突,返回NotSurpport
  • two_write_queues_以及enable_pipelined_write設置沖突,返回NotSurpport
  • seq_per_batchenable_pipelined_write暫時不支持(TODO:seq_per_batch)
  • 如果WriteOptions設置了low_pri選項,則調用函數ThrottleLowPriWritesIfNeeded
  • 如果two_write_queue_以及disableMemtable同時設置,則進入WriteImplWALOnly函數(也就是說禁用memtable,后面的過程就不同了。只需要寫WAL)
  • 如果enable_pipelined_write同時設置,則進入PipelinedWriteImpl

writer以及Write_Group

傳入WriteImpl函數獲得的所有參數構造WriteThread::Writer結構w,然后調用write_thread_.JoinBatchGroup,這個函數會將當前這個Writer w加入到WriteThread的Writer鏈表中,當w通過JoinBatchGroup之后會自動被設置一個狀態state,如果當前writer是第一個進入WriteThread的writer,則成為當前Group的leader,狀態被設置為WriteThread::STATE_GROUP_LEADER,否則說明已經有了一個leader,則等待leader為當前的writer設置狀態(AwaitState)

image

PreProcessWrite

當程序執行到此處說明當前writer是Group_Leader,當two_write_queues_為false并且disable_memtable為false的時候,進入PreProcessWrite函數進行預處理,該過程需要mutex加鎖,傳入參數write_options、need_log_sync、write_contex。

根據官方文檔,memtable被flush有三個條件,滿足其中之一則觸發memtable的flush操作:

  1. 單個memtable的size超過writer_buffer_size
  2. 總memtable size超過db_write_buffer_size或者由write_bufer_namager發起了一次flush,此時會flush最大的那個memtable
  3. WAL的總size超過max_total_wal_size,此時會將包含最老的數據的memtable給flush,這樣讓包含這部分數據的WAL可以釋放

PreProcessWrite主要過程為一系列判斷,并根據判斷執行對應的操作。

  • !single_column_family_mode_ && total_log_size > GetMaxTotalSize():表明總的log size超過了額定的閾值,此時需要更換WAL,調用函數SwitchWAL,傳入write_context(滿足flush條件3
  • write_buffer_manager_->ShouldFlush():WriteBufferManager判斷當前memtable需要dump(memtable達到了設定的閾值大小),調用函數HandleWriteBufferFull,傳入write_context(滿足條件2中總size超出閾值
  • !flush_scheduler.Empty():調用ScheduleFlushes,傳入write_context(滿足條件2中的wbm觸發
  • write_controller_.IsStopped() || write_controller_.NeedsDelay():與write_controler相關,調用DelayWrite函數,傳入last_batch_group_size以及write_options
  • need_log_sync:等待log同步完成
UNLIKELY以及LIKELY

DB_Impl::PreProcessWrite中大量使用了UNLIKELY以及LIKELY兩個宏,其定義在源文件port/likely.h中。

實現上主要封裝了函數__builtin_expect(long exp, long c),這是一個編譯上的優化,expect函數告訴編譯器表達式exp值為c的幾率比較大,希望可以針對此做優化,返回值為exp的值。

宏LIKELY實現為buildtin_expect((x), 1),也就是說LIKELY中x表達式為真的概率比較大,對于一個if語句:if(LIKELY(x)),其等價于if(x),只不過這里告訴編譯器x的值為true的可能更大,則可以根據此來進行匯編上的優化。

UNLIKELY同理。

Insert過程

insert前的準備
image

首先調用write_thread_的EnterAsBatchGroupLeader,傳入參數w以及write_group,這一步的作用主要是盡可能將能夠一塊寫入memtable的writer都加入write group。

然后判斷是否能并行插入memtable,parallel為ture的條件為設置中allow_concurrent_memtable_write選項為真并且write_group中writer個數大于1(默認情況下只有一個所以這個時候parallel為false)

記錄各種本次write相關的狀態:NUMBER_KEYS_WRITTENBYTES_WRITETENWRITE_DONE_BY_SELFWRITE_DONE_BY_OTHER

如果開啟了disableWAL選項,則將has_unpersisted_data_這個flag設置為true。

然后將數據寫入WAL中,此時有兩種情況,一是當two_write_queue_為false的時候,直接調用WriteToWAL函數寫入WAL,傳入參數write_group、log_writer、log_used、need_log_sync、need_log_dir_sync、last_sequence+1;否則調用ConcurrentWriteToWAL。默認情況為前者。

insert

如果parallel為false,則執行普通的插入,調用函數WriteBatchInterl::InsertInto將當前write_group中的數據寫入memtable,傳入參數:

write_group
current_sequence
column_family_memtables.get()
flush_scheduler
write_options.ignore_missing_column_families
recover_log_number
this
parallel
seq_per_batch
batch_per_txn_

否則執行并發的插入操作。

后續處理

如果need_log_sync為真,即WriteOptions中sync參數為true,則需要對log進行同步操作。(默認沒有開啟two_write_queues_的情況下只需要調用MarkLogsSynced,否則才是調用FlushWAL或者SyncWAL)

如果當前writer在并行的write_group中則需要進行并行writer相關的處理,默認情況為false。

最后調用所有的writer的callback函數并更新version的LastSequence,最后執行write_thread_.ExitAsBatchGroupLeader將writer的狀態設置為STATE_COMPLETE并退出(ExitAsBatchGroupLeader在pipeiline write的時候操作比較復雜,普通情況下只是設置Writer狀態為COMPLETE)。

其他寫流程分支的實現

Concurrent Memtable Insert

在leader writer進入WriteThread的EnterAsWriteGroupLeader函數之后會將符合條件的別的writer加入到write_group中,此時如果能夠進行并行的memtable插入,則會由leader發起一次parallel memtable insert,各個writer共同完成插入memtable的過程。

在完成writer的選擇之后判斷是否能夠進行并行的插入,此時的條件為:

immutable_db_options_.allow_concurrent_memtable_write && write_group.size > 1

字面來看就是write_group中writer至少大于1個(這樣才有并行的意義),并且memtable的實現要支持并行的插入(目前只有skiplist才支持),rocksdb開發者在代碼注釋中寫了三條規則,只有滿足這三條規則的情況下才能夠執行并行插入:

  1. memtable支持
  2. 非inplace update
  3. 非merge(需要檢查每個batch)(具體體現為遍歷write_group中的每個writer,當batch的HasMerge標志位為true的時候設置parallel為false)

對于WAL,write_gorup中所有writer會由leader統一寫入WAL

進入插入流程,此時如果parallel為true,則進入并行插入的流程(注意此時除了leader到達了這里之外,其他的writer還在JoinBatchGroupAwaiteState階段)。首先遍歷所有的writer并設置其sequence number,完成之后調用WriteThread::LaunchParallelMemtableWriters(),通過該函數喚醒等待的其他writer,設置狀態成為STATE_PARALLEL_MEMTABLE_WRITER,并開始繼續執行。同時leader也將自己的數據寫入memtable中。

image

Parallel Memtable Writer的寫流程

這就回到了代碼前段調用JoinBatchGroup之后,此時有個判斷:

if (w.state == WriteThread::STATE_PARALLEL_MEMTABLE_WRITER) {
    // we are a non-leader in a parallel group
    ...
}

此處就是并行memtable插入時被leader喚醒的其他writer要執行的操作。

寫入過程比較簡單,調用WriteBatchInternal::InsertInto就完成寫入

image

完成寫入之后需要自行退出,首先調用WriteThread::CompleteParallelMemtableWriter函數判斷是否還有別的writer沒有結束,如果不是最后一個完成的writer則等待別的writer完成寫操作;否則就需要為所有的writer執行退出前的后續工作。這些后續工作主要就是挨個對write group中的所有writer調用callback函數,然后設置version的last_sequence,最后調用WriteThread::ExistAsBatchGroupFollower將其他等待的writer狀態設置成COMPLETED并退出。

image

WriteImplWALOnly

  • 觸發條件:two_write_queues_ & disable_memtable

PipelineWriteImpl

  • 觸發條件:enable_pipielined_write = true

重要數據結構分析

WriteThread

相關源代碼文件:db/write_thread.h, db/write_thread.cc

WriteThread主要負責管理封裝了Put操作的Writer

數據成員
// See AwaitState.
const uint64_t max_yield_usec_;
const uint64_t slow_yield_usec_;

// 并發memtable插入操作是否允許
const bool allow_concurrent_memtable_write_;

// 針對memtable以及WAL的pipeline write是否允許
const bool enable_pipelined_write_;

// Points to the newest pending writer. Only leader can remove
// elements, adding can be done lock-free by anybody.
std::atomic<Writer*> newest_writer_;

// Points to the newest pending memtable writer. Used only when pipelined
// write is enabled.
std::atomic<Writer*> newest_memtable_writer_;

// The last sequence that have been consumed by a writer. The sequence
// is not necessary visible to reads because the writer can be ongoing.
SequenceNumber last_sequence_;
主要API
  • void JoinBatchGroup(Writer* w);

    JoinBatchGroup實現的功能是將一個Writer插入到WriteThread的Writer鏈表中,WriteThread中通過一個atomic的指針newest_writer來指向最新的writer,并且這個writer連接了鏈表中其他的writer。

    w進入該函數之后首先調用LinkOne函數,本質上LinkOne函數做的事就是把傳入的w插入到鏈表中,實現這一操作的語句:

    Writer* writers = newest_writer->load(std::memory_order_relaxed);
    while (true) {
        w->link_older = writers;
        if (newest_writer->compare_exchange_weak(writers, w)) {
          return (writers == nullptr);
        }
      }
    

    對于這個compacre_exchange_weak,簡單的理解是一個原子的替換操作,原子地將w替換到newest_writer里面,當w替換成功的時候返回true,進入return語句,這個時候如果writer為nullptr說明當前writer是插入的第一個writer,那么當前writer就成為leader,否則替換失敗重復執行(這個時候應該是別的線程的writer插入了)直到插入成功

    image

    回到JoinBatchGroup,如果LinkOne返回值為true則設置當前writer狀態為STATE_GROUP_LEADER,其余調 用AwaitState等待狀態改變。

  • size_t EnterAsBatchGroupLeader(Writer* leader, WriteGroup* write_group);

    該函數將leader writer加入到Write Group中,并且選擇符合條件的其他writer加入到同一個group中

  • void ExitAsBatchGroupLeader(WriteGroup& write_group, Status status);

    這個函數主要執行退出的時候的狀態設置,先不考慮pipeline write的情況,最簡單的功能就是從last_writer開始遍歷group中的所有writer,然后設置他們的狀態為STATE_COMPLETE

  • void LaunchParallelMemTableWriters(WriteGroup* write_group);

    將write group中所有的writer的狀態設置成STATE_PARALLEL_MEMTABLE_WRITER以喚醒等待的writer執行并發的插入操作

  • bool CompleteParallelMemTableWriter(Writer* w)

    在每個并發memtable插入的writer執行過程最后調用,判斷如果當前writer不是最后一個writer(write group中還有正在執行的writer)則等待其他writer完成寫操作(AwaitState(w, STATE_COMPLETED, &cpmtw_ctx);),否則返回true

  • void ExitAsBatchGroupFollower(Writer* w)

    對Group Leader調用ExitAsBatchGroupLeader以及將leader的狀態設置為STATE_COMPLETED

Writer

在Put的時候對一個寫操作的封裝

數據成員
//writebatch以及write_options相關的數據
WriteBatch* batch;
bool sync;
bool no_slowdown;
bool disable_wal;
bool disable_memtable;


size_t batch_cnt;  // if non-zero, number of sub-batches in the write batch
                    //如果不為0表示batch中還有其他的子batch

//從write函數中傳入的數據
PreReleaseCallback* pre_release_callback;
uint64_t log_used;  // log number that this batch was inserted into
uint64_t log_ref;   // log number that memtable insert should reference
WriteCallback* callback;

bool made_waitable;          // records lazy construction of mutex and cv
std::atomic<uint8_t> state;  // write under StateMutex() or pre-link

WriteGroup* write_group;    //所屬的write_group

SequenceNumber sequence;  // the sequence number to use for the first key
Status status;            // status of memtable inserter
Status callback_status;   // status returned by callback->Callback()

std::aligned_storage<sizeof(std::mutex)>::type state_mutex_bytes;
std::aligned_storage<sizeof(std::condition_variable)>::type state_cv_bytes;

//write_group中的鏈表指針
Writer* link_older;  // read/write only before linking, or as leader
Writer* link_newer;  // lazy, read/write only before linking, or as leader

其中state初始為STATE_INIT,其余參數通過調用者傳入

writer結構中包含了writer指針link_older以及link_newer,也就是說多個writer在 write group中是以鏈表的形式組織,并且每個write攜帶者其對應batch的數據

主要API
  • bool CallbackFailed():當callback不為空,并且callback_status為不為OK的時候返回true,表示回調函數調用出問題
  • bool ShouldWriteToMemtable():當status沒有問題,Callback函數調用正常以及disable_memtable為false的時候返回true
  • bool ShouldWriteToWAL():同上,并且當disableWAL為false的時候為true
  • bool CheckCallback(DB* db):調用callback函數并將返回的狀態存儲到callback_status

WriteGroup

WriteGroup是一個將多個writer統一起來的結構,類似鏈表的頂層結構,其中包含兩個Writer指針分別為leader以及last_writer,類似鏈表中的頭指針和尾指針

數據成員
// Writer指針
Writer* leader = nullptr;
Writer* last_writer = nullptr;
SequenceNumber last_sequence;
// before running goes to zero, status needs leader->StateMutex()
// 狀態相關的變量
Status status;
std::atomic<size_t> running;
size_t size = 0;

State

state是write_thread中定義的writer的不同狀態,不同狀態下的writer有著不同的操作方式

enum State : uint8_t {
  // The initial state of a writer.  This is a Writer that is
  // waiting in JoinBatchGroup.  This state can be left when another
  // thread informs the waiter that it has become a group leader
  // (-> STATE_GROUP_LEADER), when a leader that has chosen to be
  // non-parallel informs a follower that its writes have been committed
  // (-> STATE_COMPLETED), or when a leader that has chosen to perform
  // updates in parallel and needs this Writer to apply its batch (->
  // STATE_PARALLEL_FOLLOWER).
  // writer的初始狀態,等待JoinBatchGroup,后續可能變成其他狀態
  STATE_INIT = 1,

  // The state used to inform a waiting Writer that it has become the
  // leader, and it should now build a write batch group.  Tricky:
  // this state is not used if newest_writer_ is empty when a writer
  // enqueues itself, because there is no need to wait (or even to
  // create the mutex and condvar used to wait) in that case.  This is
  // a terminal state unless the leader chooses to make this a parallel
  // batch, in which case the last parallel worker to finish will move
  // the leader to STATE_COMPLETED.
  // 通知一個writer現在變成了leader并且他需要創建一個write batch gorup 
  STATE_GROUP_LEADER = 2,

  // The state used to inform a waiting writer that it has become the
  // leader of memtable writer group. The leader will either write
  // memtable for the whole group, or launch a parallel group write
  // to memtable by calling LaunchParallelMemTableWrite.
  // 通知一個writer變成了一個memtable writer group的leader
  // leader要么將整個group寫到memtable
  // 要么調用LaunchParallelMemtableWrite發起一次并行寫memtable 
  STATE_MEMTABLE_WRITER_LEADER = 4,

  // The state used to inform a waiting writer that it has become a
  // parallel memtable writer. It can be the group leader who launch the
  // parallel writer group, or one of the followers. The writer should then
  // apply its batch to the memtable concurrently and call
  // CompleteParallelMemTableWriter.
  // 告知一個writer變成了一個parallel memtable writer
  // writer應該將其batch同步地應用到memtable并調用CompleteParallelMemtableWriter
  STATE_PARALLEL_MEMTABLE_WRITER = 8,

  // A follower whose writes have been applied, or a parallel leader
  // whose followers have all finished their work.  This is a terminal
  // state.
  // 已經成功寫入的writer
  STATE_COMPLETED = 16,

  // A state indicating that the thread may be waiting using StateMutex()
  // and StateCondVar()
  // 告知thread需要等待StateMutex或者StateCondVar
  STATE_LOCKED_WAITING = 32,
};

WriteBatch&WriteBatchInternal

WriteBatch主要是提供kv以及cf信息的封裝,WriteBatchInternal提供針對WriteBatch的相關操作接口

WriteBatchInternal::InsertInto

根據傳入的數據構造MemtableInserter,然后調用WriteBatch::Iterate,傳入inserter實現寫操作

如果是concurrent memtbale write還需要調用inserter的PostProcess(主要是與狀態信息的處理有關)

WriteBatch::Iterate

【作用】遍歷batch中的所有數據,并根據數據類型進行對應的操作

遍歷所有的input

首先通過ReadRecordFromWriteBatch讀取待插入的所有數據(input、tag、column_family、key、value、blob、xid),其中tag區分不同的寫入數據類型

根據tag確定不同寫入數據的不同操作,對于普通的寫tag為kTypeValue,此處調用MemtableInserter::PutCF

MemtableInserter

PutCF&&PutCFImpl

MemtableInserter的PutCF將傳入的kv數據寫入memtable,PutCF函數是調用PutCFImpl函數實現

其他基本操作在Inserter中也有,主要有DeleteCF、DeleteRangeCF、MergeCF、PutBlobIndexCF、SingleDeleteCF

【PutCFImpl】

首先SeekToColumnFamily,根據傳入的column_family_id,由ColumnFamilyMemtables::Seek查找對應的cf數據,如果沒找到會根據WriteOptions中的ignore_missing_column_family判斷是否返回錯誤(此時ColumnFamilySet中的Current已經定位到查找的這個cf)

獲取memtable,調用cf_mems->GetMemTable(已經由Seek定位到了對應的cf)

對于非inplace_update,調用memtable::Add將數據寫入即可,由Add函數將memtable寫入之后會調用Memtable::UpdateFlushState由memtable自己決定是不是要更新memtable的狀態為FLUSH_REQUESTED(memtable的狀態的這里變化)

【MaybeAdvanceSeq】

與sequence number有關

【CheckMemtableFull】

獲取當前插入的cfd,如果cfd的memtable的狀態變為FLUSH_REQUESTED,則將該memtable的狀態變為FLUSH_SCHEDULED并將該cfd加入flush_scheduler

相關函數過程分析

PreProcessWrite中涉及的一些過程

write_buffer_manager->ShouldFlush

首先write_buffer_manager這個功能必須是啟用的

返回true的條件二者滿足其一即可:

  • memtable占用內存超過memtable總size的限制
  • 內存使用超過了總的buffer size并且其中memtable占用了超過一半的buffer size

SwitchWAL

更換memtable并將舊的memtable加入flush隊列觸發flush

判斷條件之一GetMaxTotalWalSize定義于db/db_impl_write.cc,返回值為:

mutable_db_options.max_total_wal_size如果沒有設置(==0),則為4 * max_total_in_memory_state_

否則為設定值

即該函數作用為WAL size超過了設定的閾值需要釋放掉一部分log占用的空間,釋放log按照時間順序從最舊的開始然后遍歷所有的cfd,對包含了小于最舊的log number的cfd進行flush

DB中維護了一個存放目前正在使用中的log的vector:alive_log_files_,其中每一個元素記錄了一個log的number、size以及是否被flush的標志位,進行SwitchWAL的流程時首先獲取alive_log_files_中的第一個元素的log作為最老的一個log——oldest_alive_log。

先忽略2pc的情況

然后遍歷所有的cfd,對于包含了log_number小于等于oldest_alive_log的cfd都加入flush隊列中等待flush,具體實現為對該cfd調用SwitchMemtable并將其immutable_memtable列表imm標記為請求flush狀態,最后調用SchedulePendingFlush安排flush操作

最后調用MaybeScheduleFlushOrCompaction觸發Flush或者Compaction

HandleWriteBufferFull

更換memtable并將舊的memtable加入flush隊列觸發flush

遍歷所有的cfd,對所有的包含非空memtable的cfd,選擇其中CreationSeq最小的cfd(理解為創建時間最久的memtable?),對該cfd調用SwitchMemtable,如果成功則將該cfd的imm列表標記為請求flush并安排一次Flush(SchedulePendingFlush)同時觸發嘗試flush或者compaction任務(MaybeScgheduleFlushOrCompaction)

ScheduleFlush

對所有在FlushScheduler中的cfd調用SwitchMemtable并Unref(如果Unref之后引用數為0則delete掉該cfd)

涉及到的相關函數分析

SchedulePendingFlush

將傳入的cfd加入到flush_queue里(flush_queue是一個deque)

SwitchMemtable

SwitchMemtable的主要是為一個ColumnFamily更換Memtable同時新建一個WAL的過程

【處理log】

進入函數首先不考慮two_write_queue以及pipeline write的情況下,首先判斷是否能夠循環使用log,如果是則從log_recycle_files隊列中pop一個出來作為新的log使用

在需要創建新的log file的情況下調用VersionSet::NewFileNumber分配一個新的log number并創建的新的WritableFile,而對于recycle的情況,則是新建ReuseWritableFile。然后通過新的WritableFile創建新的log::Writer

獲取當前的seq,并以這個seq調用cfd的ConstructNewMemtable創建新的memtable,同時通過context創建新的SuperVersion

將新的log number添加到alive_log_files

遍歷所有的cfd,對于包含memtable還沒使用以及imm列表中沒有flush的imm為0的cfd,更新他們的log number以及memtable的seq(為什么別的cfd不更新log?)

將新的memtable替換到cfd內同時將舊的加入到imm列表

最后調用InstallSuperVersionAndScheduleWork,該函數構建新的SuperVersion并替換,同時觸發對當前cfd的flush以及compaction操作

WriteToWAL

獲取參數:

  • WriteGroup& write_group
  • log:Writer* log_writer
  • uint64_t* log_used
  • bool need_log_sync
  • bool need_log_dir_sync
  • SequenceNumber sequence

主要流程:

外部調用的WriteToWAL函數主要做的是對寫WAL這個過程的封裝,比如預處理以及后續清理工作之類的,真正完成寫WAL的函數在另一個WriteToWAL函數重載里面,另一個函數接收一個merged_batch結構,這個merged_batch就包含了write_group所有的batch的數據。

在外部的WriteToWAL,第一項任務就是生成merged_batch,這里通過函數MergeBatch實現,MergeBatch的操作邏輯十分簡單,如果write_group中只有一個writer,則merged_batch就是這個leader writer,否則遍歷所有的writer,將其batch追加到tmp_batch中,最后merged_batch即為tmp_batch。所以當這個函數返回的時候如果merged_batch == write_group的leader,則說明只有一個batch,只需要設置一個batch的log_number,否則就需要遍歷設置所有writer的log_number。

接下來就是調用真正的WriteToWAL,傳入merged_batch以及log_writer,實際寫入數據的操作是通過log_writer的AddRecord接口實現。

寫入完成之后,根據設置的need_log_sync以及need_log_dir_sync參數判斷是否對本次write進行sync操作

最后記錄狀態即完成(退出前tmp_batch手動清理)

其他put選項設置以及實現原理

pipeline write

【默認情況】

單一的write thread隊列,隊首writer成為leader,并負責寫WAL以及memtable

【pipeline write】

只有一個writer的情況下,要先寫WAL,再寫memtbale

如果有多個writer,默認情況就需要先寫完WAL,在寫memtable

啟用pipeline之后,前一個writer寫完WAL就可以寫memtbale,而后一個writer開始寫他的WAL

開啟方式:Options.enable_pipeline_write=true

提升:20%性能提升

two write queue

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容

  • # rocksdb engine 寫邏輯 ## 執行路徑 DB::Put(key, value)是一個寫操作簡單封...
    kenry閱讀 2,608評論 0 1
  • ??本文主要講解了RocksDB中二階段提交的實現。本文總結一下共有如下幾個要點: Modification of...
    薛少佳閱讀 3,856評論 0 3
  • 一、簡介 Hbase:全名Hadoop DataBase,是一種開源的,可伸縮的,嚴格一致性(并非最終一致性)的分...
    菜鳥小玄閱讀 2,400評論 0 12
  • 老翁沐陽怡自樂, 學童貪嘻歸家遲。 旅人步匆無行處, 亂問童叟徑何及。 投路怎懼川林險, 人蹤匿處多絕奇。 莫憐孤...
    閑看歲月流光閱讀 382評論 1 3
  • 對圖片進行任意變形都支持。只有非透明區域是可以點擊的。也可以反過來用,對透明區域可以點擊,比如用來做點擊遮罩。
    Babybus_Unity閱讀 1,962評論 0 1