日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

TitanDB GC详细实现原理 及其 引入的问题

發布時間:2023/11/27 生活经验 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TitanDB GC详细实现原理 及其 引入的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

      • 1. 為什么要有GC
      • 2. GC的觸發條件
      • 3. GC的核心邏輯
        • 1. blob file形態
        • 2. GC Prepare
        • 3. GC pick file
        • 4. GC run
      • 4. GC 引入的問題
      • 5. Titan的測試代碼

通過本篇,能夠從TitanDB的源代碼中看到 key/value 分離之后引入的一些復雜性,這個復雜性很難避免。

主要從如下幾點展開描述:

  1. GC 觸發條件
  2. GC 的 核心邏輯
  3. GC 引入的問題

希望通過對Titan源代碼的分析能夠加深各位對key-value分離策略優劣的理解,為今后自己的業務選型提供參考。

1. 為什么要有GC

Titan 從 Wisckey 中借鑒的key-value分離思想來降低LSM-tree的寫放大 以及LSM-tree的 Compaction 中I/O帶寬的占用。這對于引擎層很薄且大value場景 來說 還是比較適用的,比較薄的引擎層能夠讓應用的性能盡可能能接近引擎,而大value場景中傳統的LSM-tree會攜帶著value進行compaction,這對于傳統的NVME-ssd / SATA-ssd 來說簡直是災難,sst的讀寫I/O隊列是共享的,而帶著大value compaction 場景下的I/O很容易達到帶寬瓶頸,從而讓應用的讀長尾不忍直視。。。

跑偏了,以上是titan或者說key-value分離出現的緣由。而引入了key-value分離,也就是僅僅讓較小數據量的key存放在LSM-tree中,并參與LSM-tree的compaction調度,而大value則單獨存放在另一個地方,所以需要對大value的存放文件進行GC,保正compaction對key的清理 能夠同步到大value中,清理對應的過期value,這是titan正確性保障的基本功能,也是基于lsm-tree的key-value分離系統必須要實現的。

接下來我們詳細看看Titan的實踐過程。

2. GC的觸發條件

前面提到了GC 的作用是清理因為compaction而過期的key的value,所以GC的觸發肯定和compaction同步或者先后順序的;而且compaction 的過程才能知道具體的sst文件的變動情況。

所以titan 的GC通過rocksdb的EventListener 來觸發的。

這里又要說一下Rocksdb的靈活擴展性,為用戶提供了多種多樣能夠操作引擎內部核心邏輯的接口,來讓熟悉的用戶更好得使用引擎。

就像titan GC這里用到的EventListener中,titan只需要在OnCompactionCompleted實現觸發GC的邏輯,就能在compaction完成之后嘗試調度GC,這個時候能夠看到comapction的一些內部信息,非常之方便。

rocksdb compaction中調度EventListener 邏輯如下:

Status DBImpl::BackgroundCompaction(bool* made_progress,JobContext* job_context,LogBuffer* log_buffer,PrepickedCompaction* prepicked_compaction,Env::Priority thread_pri) {...if (c != nullptr) {c->ReleaseCompactionFiles(status);*made_progress = true;#ifndef ROCKSDB_LITE// Need to make sure SstFileManager does its bookkeepingauto sfm = static_cast<SstFileManagerImpl*>(immutable_db_options_.sst_file_manager.get());if (sfm && sfm_reserved_compact_space) {sfm->OnCompactionCompletion(c.get());}
#endif  // ROCKSDB_LITE// 調度用戶態實現的 OnCompactionCompletedNotifyOnCompactionCompleted(c->column_family_data(), c.get(), status,compaction_job_stats, job_context->job_id);}...
}

其中NotifyOnCompactionCompleted會執行具體的OnCompactionCompleted的邏輯

void DBImpl::NotifyOnCompactionCompleted(ColumnFamilyData* cfd, Compaction* c, const Status& st,const CompactionJobStats& compaction_job_stats, const int job_id) {...TEST_SYNC_POINT("DBImpl::NotifyOnCompactionCompleted::UnlockMutex");{CompactionJobInfo info{};BuildCompactionJobInfo(cfd, c, st, compaction_job_stats, job_id, current,&info);//執行for (auto listener : immutable_db_options_.listeners) {listener->OnCompactionCompleted(this, info);}}...
}

到現在基本就已經進入了GC的邏輯了,也就是titan實現的void TitanDBImpl::OnCompactionCompleted

3. GC的核心邏輯

講解詳細的GC邏輯之前先整體看看titan的blobfile形態。

1. blob file形態

看看基本的blobfile的內部存儲結構

相關的所有block信息都在blob_format.h

大體結構和我們rocksdb的sst文件結構類似的,只不過value的存儲上使用的是record,一個record是一個key-value的記錄,而sst中則是一個data-block。

  • blob file header: 整個blob file的header 字段,用來標識當前file的version信息和魔數, 實現了兩個版本,用來兼容rocksdb的blobdb

    // Format of blob file header for version 1 (8 bytes):
    //
    //    +--------------+---------+
    //    | magic number | version |
    //    +--------------+---------+
    //    |   Fixed32    | Fixed32 |
    //    +--------------+---------+
    //
    // For version 2, there are another 4 bytes for flags:
    //
    //    +--------------+---------+---------+
    //    | magic number | version |  flags  |
    //    +--------------+---------+---------+
    //    |   Fixed32    | Fixed32 | Fixed32 |
    //    +--------------+---------+---------+
    
  • blob record: 整個blob file存放 key-value的區域
    主要包括兩部分:record head 和 record

    其中 record head 主要保存的是當前 record 內key+value的總大小,還有一個字節標識當前record是否開啟了壓縮

    // Format of blob head (9 bytes):
    //
    //    +---------+---------+-------------+
    //    |   crc   |  size   | compression |
    //    +---------+---------+-------------+
    //    | Fixed32 | Fixed32 |    char     |
    //    +---------+---------+-------------+
    //
    

    這個record head 字段的添加是在 encode recod 的時候寫入的

    void BlobEncoder::EncodeRecord(const BlobRecord& record) {record_buffer_.clear();compressed_buffer_.clear();// encode recordCompressionType compression;record.EncodeTo(&record_buffer_);record_ = Compress(compression_info_, record_buffer_, &compressed_buffer_,&compression);// encode record headassert(record_.size() < std::numeric_limits<uint32_t>::max());EncodeFixed32(header_ + 4, static_cast<uint32_t>(record_.size()));header_[8] = compression;// 生成src,并ecode 到頭部字段uint32_t crc = crc32c::Value(header_ + 4, sizeof(header_) - 4);crc = crc32c::Extend(crc, record_.data(), record_.size());EncodeFixed32(header_, crc);
    }
    

    第二部分的record 是主體,存放key-value,是的,沒錯,這里會存放一個key的備份,來所以value。也就是titan相比于rocksdb這里會多存放一份key。

    struct BlobRecord {Slice key;Slice value;void EncodeTo(std::string* dst) const;Status DecodeFrom(Slice* src);size_t size() const { return key.size() + value.size(); }friend bool operator==(const BlobRecord& lhs, const BlobRecord& rhs);
    };
    
  • blob file meta 這里存放當前blobfile的一些元信息,類似于sst的 properties block(存放當前sst的大小,datablock個數,每個datablock大小,處于哪個層 ,最大最小key等)/filter block(bloom filter)/ compress block/range del block 。blob file這里也是為了方便擴展,也允許加入很多meta block。

    // Format of blob file meta (not fixed size):
    //
    //    +-------------+-----------+--------------+------------+
    //    | file number | file size | file entries | file level |
    //    +-------------+-----------+--------------+------------+
    //    |  Varint64   | Varint64  |   Varint64   |  Varint32  |
    //    +-------------+-----------+--------------+------------+
    //    +--------------------+--------------------+
    //    |    smallest key    |    largest key     |
    //    +--------------------+--------------------+
    //    | Varint32 + key_len | Varint32 + key_len |
    //    +--------------------+--------------------+
    //
    // The blob file meta is stored in Titan's manifest for quick constructing of
    // meta infomations of all the blob files in memory.
    //
    // Legacy format:
    //
    //    +-------------+-----------+
    //    | file number | file size |
    //    +-------------+-----------+
    //    |  Varint64   | Varint64  |
    //    +-------------+-----------+
    
  • Blob index block,報錯record所處當前blobfile的offset和整個record的size,用來在seek的過程中快速找到對應的blob record

    // Format of blob index (not fixed size):
    //
    //    +------+-------------+------------------------------------+
    //    | type | file number |            blob handle             |
    //    +------+-------------+------------------------------------+
    //    | char |  Varint64   | Varint64(offsest) + Varint64(size) |
    //    +------+-------------+------------------------------------+
    //
    // It is stored in LSM-Tree as the value of key, then Titan can use this blob
    // index to locate actual value from blob file.
    
  • Blob file footer 這是最后一個block,目前只是保存了一個空的index handle 以及 kEncodedLength{kBlobFooterSize} size。
    讀blobfile的時候減去kEncodedLength{kBlobFooterSize};之后的偏移地址就是index record的部分。

    因為現在的實現是沒有meta block的,這里應該是為了預留meta block的index的,所以實際encode到footer的meta_index_handle內容是空的。

這里說的有點啰嗦了,總之知道底層文件的組織形態,那上層的讀寫細節就很容易把控了。

接下來看看底層的核心設計細節。

2. GC Prepare

前面說了,compaction結束之后會通過OnCompactionCompleted 來觸發。

這個時候正常的GC邏輯中是 要知道 接下來清理哪一些blob,以及清理blob中多少的數據。如果這個時候inplace update,那還需要大量的隨機讀,并且是隨機寫入,后續文件的清理也比較麻煩,哪怕只有一條record也不能清理;所以整體GC的核心讀寫都是和compaction的思想類似的,從文件中讀取record、丟掉過期的record,只保留新寫入到新的blobfile中。勢必消耗較少的cpu,還能保證GC的效率。

這里看一下GC pick file的邏輯,選擇需要參與GC的 blob file。

在Titan中key 從用戶下發,到形成sst/blob file的過程如下:

Flush的過程會根據min_blob_size來區分value的存儲,如果會存放在blobfile中,則它會生成一個上圖中的key-key-index 準備寫入sst文件,這個key-index 包括三列

  • 第一列:這個key的value所屬blobfile的filenumber
  • 第二列:這個key在blobfile中的record的偏移地址
  • 第三列:這個key所在blobfile的record的大小

也就是通過key-index,能夠索引到這個key在blobfile中的record,當這個key-index要被寫入到sst中時 titan為了收集GC需要的信息,會實現一個Rocksdb的TablePropertiesCollector,在flush/compaction形成sst時,將當前sst中key的index信息做一個匯總寫入到table properties block中。這里的匯總信息包括上圖中最左側的部分,當然實際上當前sst中對應多少個blobfile就會有多少條(一個map數據結構,以blob file number為key,對應的record size為value)。

有了properties的信息之后,就能夠知道compaction完成之后輸入的sst文件的properties和輸出的sst文件的blob file中key的變動情況(blob record也存儲了對應的key-value),這樣就能決策哪一些blobfile是否達到GC的觸發條件(關于GC的觸發條件后面會說)。

大體就是輸入的sst文件總的properties信息 和 輸出的propertis的blobfile信息做差值,就知道最后每個blobfile會被丟棄多少的數據。

這個數據會存放在 blob_file_size_diff變量中, 對應的處理代碼如下:

void TitanDBImpl::OnCompactionCompleted(const CompactionJobInfo& compaction_job_info) {...// lamda 表達式,處理inputs 時 to_add為false,ExtractGCStatsFromTableProperty 僅僅是累積// 處理outputs時,會將to_add置為true,則會和之前的做diff,這樣就知道每個blobfile丟棄的record大小情況auto update_diff = [&](const std::vector<std::string>& files, bool to_add) {for (const auto& file_name : files) {auto prop_iter = prop_collection.find(file_name);if (prop_iter == prop_collection.end()) {ROCKS_LOG_WARN(db_options_.info_log,"OnCompactionCompleted[%d]: No table properties for file %s.",compaction_job_info.job_id, file_name.c_str());continue;}Status gc_stats_status = ExtractGCStatsFromTableProperty(prop_iter->second, to_add, &blob_file_size_diff);if (!gc_stats_status.ok()) {// TODO: Should treat it as background error and make DB read-only.ROCKS_LOG_ERROR(db_options_.info_log,"OnCompactionCompleted[%d]: failed to extract GC stats from table ""property: compaction file: %s, error: %s",compaction_job_info.job_id, file_name.c_str(),gc_stats_status.ToString().c_str());assert(false);}}};update_diff(compaction_job_info.input_files, false /*to_add*/);update_diff(compaction_job_info.output_files, true /*to_add*/);...
}

有了每次compaction前后 每個 blobfile中過期數據量的情況,接下來titan會為上面blob_file_size_diff map中的每一個blob file 維護一個state,用來標識這個文件中的“垃圾”數據的比例,計算方式很簡單 ,大體就是1 - live_data_size / file_size:

double GetDiscardableRatio() const {if (file_size_ == 0) {return 0;}// TODO: Exclude meta blocks from file sizereturn 1 - (static_cast<double>(live_data_size_) /(file_size_ - kBlobMaxHeaderSize - kBlobFooterSize));
}

而這個數據則會被當作當前blobfile 是否會被選擇參與GC的score 標準。

計算每個blobfile的gc score 邏輯如下:

需要注意的是如果一個blobfile 過小(默認小于8M),會為其設置0.5的core,從而加快小文件的回收。

gc_score_ 會從大到小排個序,后續的GC過程中的blobfile文件挑選會優先挑選gc_score較高的。

void BlobStorage::ComputeGCScore() {// TODO: no need to recompute all everytimeMutexLock l(&mutex_);gc_score_.clear();for (auto& file : files_) {if (file.second->is_obsolete()) {continue;}gc_score_.push_back({});auto& gcs = gc_score_.back();gcs.file_number = file.first;if (file.second->file_size() < cf_options_.merge_small_file_threshold) {// for the small file or file with gc mark (usually the file that just// recovered) we want gc these file but more hope to gc other file with// more invalid datagcs.score = cf_options_.blob_file_discardable_ratio;} else {gcs.score = file.second->GetDiscardableRatio();}}// gc_score會從大到小排序std::sort(gc_score_.begin(), gc_score_.end(),[](const GCScore& first, const GCScore& second) {return first.score > second.score;});
}

接下來有了每個文件的gc_sore信息就可以正式調度一個gc job 了,默認只能調度一個GCjob。

設置一個的目的并不是說有數據沖突/一致性問題,而是GC的I/O代價太高,需要限制I/O,保證應用的延時

void TitanDBImpl::MaybeScheduleGC() {mutex_.AssertHeld();if (db_options_.disable_background_gc) return;if (shuting_down_.load(std::memory_order_acquire)) return;while (unscheduled_gc_ > 0 &&bg_gc_scheduled_ < db_options_.max_background_gc) {unscheduled_gc_--;bg_gc_scheduled_++;// 調度gc job 開始異步GCthread_pool_->SubmitJob(std::bind(&TitanDBImpl::BGWorkGC, this));}
}

3. GC pick file

接下來順著代碼,會進入到GC 入口函數 TitanDBImpl::BackgroundGC,首先會挑選當前需要參與GC 的blob file。

  1. 首先根據上面prepare過程中維護的 gc_socre 來確認當前文件是否符合gc的基本條件。即要求每一個core都大于等于cf_options_.blob_file_discardable_ratio,默認是0.5
  2. 滿足的話 找到這個文件的標識,并添加到GC文件 數組 blob_files
  3. 如果累積的gc file總文件大小超過 gc batch size: cf_options_.max_gc_batch_size(默認1G) 或者 有效總數據超過cf_options_.blob_file_target_size(默認256M) ,則認為當前job文件挑選夠了
std::unique_ptr<BlobGC> BasicBlobGCPicker::PickBlobGC(BlobStorage* blob_storage) {Status s;std::vector<std::shared_ptr<BlobFileMeta>> blob_files;...for (auto& gc_score : blob_storage->gc_score()) {// score 是否滿足GC 最低score的要求if (gc_score.score < cf_options_.blob_file_discardable_ratio) {break;}// 確認這個文件存在auto blob_file = blob_storage->FindFile(gc_score.file_number).lock();if (!CheckBlobFile(blob_file.get())) {// Skip this file id this file is being GCed// or this file had been GCedROCKS_LOG_INFO(db_options_.info_log, "Blob file %" PRIu64 " no need gc",blob_file->file_number());continue;}// 繼續挑選當前job參與GC的文件if (!stop_picking) {blob_files.emplace_back(blob_file);batch_size += blob_file->file_size();estimate_output_size += blob_file->live_data_size();// 是否達到了GC的batch大小以及 有效數據量大小閾值的要求,滿足則停止挑選文件if (batch_size >= cf_options_.max_gc_batch_size ||estimate_output_size >= cf_options_.blob_file_target_size) {// Stop pick file for this gc, but still check file for whether need// trigger gc after thisstop_picking = true;}} else { // 完成挑選,將剩下的文件放在下一個job中。next_gc_size += blob_file->file_size();if (next_gc_size > cf_options_.min_gc_batch_size) {maybe_continue_next_time = true;RecordTick(statistics(stats_), TITAN_GC_REMAIN, 1);ROCKS_LOG_INFO(db_options_.info_log,"remain more than %" PRIu64" bytes to be gc and trigger after this gc",next_gc_size);break;}}}...return std::unique_ptr<BlobGC>(new BlobGC(std::move(blob_files), std::move(cf_options_), maybe_continue_next_time));
}

4. GC run

實際函數主體的入口是DoRunGC(), 這一部分就是類似于comapction的調度邏輯了。

  1. 構造一個最小堆 迭代器,并為參與GC的所有文件也都維護一個迭代器, 每次迭代器的移動(next)都會從 多個blobfile中取一個record,將key 按照compartor放在最小堆里。

  2. 從迭代器直接取key(最小堆里的堆頂,讀上來的最小的key),去sst中反查key是否存在

    1. 存在則認為是不可丟棄的,會寫入到新的blob文件中。
    2. 否則就會被丟棄,迭代器直接跳過這個key的處理。
  3. 一邊通過迭代器讀取,一邊將從最小堆中取出的key 確認不會被丟棄就寫入到新的blobfile中

  4. 通過write callback ,將寫入到新的blobfile的key再回寫到lsm-tree中。因為 value已經放到了新的blobfile中了,但是lsm-tree中的key并不知道這一點。所以還需要重寫一次。

其中迭代器處理構造一個最小堆的過程如下:

void BlobFileMergeIterator::SeekToFirst() {for (auto& iter : blob_file_iterators_) {iter->SeekToFirst();// 將每一個blobfile問的迭代器添加到最小堆中if (iter->status().ok() && iter->Valid()) min_heap_.push(iter.get());}if (!min_heap_.empty()) {current_ = min_heap_.top();min_heap_.pop();} else {status_ = Status::Aborted("No iterator is valid");}
}

判斷一個key是否能夠被丟棄,邏輯如下:

Status BlobGCJob::DiscardEntry(const Slice& key, const BlobIndex& blob_index,bool* discardable) {TitanStopWatch sw(env_, metrics_.gc_read_lsm_micros);assert(discardable != nullptr);PinnableSlice index_entry;bool is_blob_index = false;// 從SST文件先讀一次,確認是否存在Status s = base_db_impl_->GetImpl(ReadOptions(), blob_gc_->column_family_handle(), key, &index_entry,nullptr /*value_found*/, nullptr /*read_callback*/, &is_blob_index);if (!s.ok() && !s.IsNotFound()) {return s;}// count read bytes for checking LSM entrymetrics_.gc_bytes_read += key.size() + index_entry.size();// 找不到,則確認可以丟棄,更新丟棄標記。if (s.IsNotFound() || !is_blob_index) {// Either the key is deleted or updated with a newer version which is// inlined in LSM.*discardable = true;return Status::OK();}......return Status::OK();
}

寫入到新的blobfile邏輯如下:

void BlobFileBuilder::Add(const BlobRecord& record, BlobHandle* handle) {if (!ok()) return;encoder_.EncodeRecord(record);handle->offset = file_->GetFileSize();handle->size = encoder_.GetEncodedSize();live_data_size_ += handle->size;// 追加寫入,先寫每個record的head// 每個record的內容前面已經描述過了。status_ = file_->Append(encoder_.GetHeader());if (ok()) {// 再寫recordstatus_ = file_->Append(encoder_.GetRecord());num_entries_++;// The keys added into blob files are in order.if (smallest_key_.empty()) {smallest_key_.assign(record.key.data(), record.key.size());}assert(cf_options_.comparator->Compare(record.key, Slice(smallest_key_)) >=0);assert(cf_options_.comparator->Compare(record.key, Slice(largest_key_)) >=0);largest_key_.assign(record.key.data(), record.key.size());}
}

重寫回寫key到lsm-tree中的邏輯如下:

new_blob_index.EncodeToBase(&index_entry);
// Store WriteBatch for rewriting new Key-Index pairs to LSM
// 通過writecallback來回寫
GarbageCollectionWriteCallback callback(cfh, blob_record.key.ToString(),std::move(blob_index));
callback.value = index_entry;
rewrite_batches_.emplace_back(std::make_pair(WriteBatch(), std::move(callback)));
auto& wb = rewrite_batches_.back().first;
s = WriteBatchInternal::PutBlobIndex(&wb, cfh->GetID(), blob_record.key,index_entry);

4. GC 引入的問題

從上面的GC核心處理邏輯中,我們能夠看到GC的實現相比于compaction還是很簡單的,可能是因為blobfile的各種meta block功能沒有上全,所以gc過程并不會特別復雜。

需要注意的是GC 的處理細節:

  1. 從blobfile中取到的record,還需要拿著key再去lsm-tree中讀一下。因為不確定這個key是存在還是不存在,需要額外的一次讀。
  2. 寫完blobfile之后還需要對lsm-tree中的key進行一次更新,因為lsm-tree中的key不知道它的value已經寫入到了新的blobfile中。又需要一次額外的寫。
  3. 更嚴重的是GC會帶著大value讀寫,這對于當下 共享讀寫隊列 的硬件來說,是一個長尾災難。寫入延時的增大會造成讀的長尾。

    這有錢的可以用intel optane ssd p5800,據說讀寫隊列分離,互不影響;沒錢的加限速唄。。。。

假如我們僅僅是使用titan,并不想改動/優化 一下titan的話,那很簡單,讓value-size : key-size 差異足夠大,這個時候GC的這兩個額外讀和額外寫相比于GC本身的value讀寫,都降低很多了。lsm-tree中key的密度大了,文件個數相對較少。

假如我們key-size:10B ,value size: 64KB,有一塊6T的SSD,不考慮寫放大的情況,整個盤都寫滿,key+key-index形成的sst所占用的空間也還不到2G,LSM-tree也就2層。。。。即使考慮上寫放大, 也就最多到第三層。且寫放大完全可以通過level_compaction_dynamic_level_bytes降低到最小。這樣的LSM-tree中的查找基本不會消耗太多的I/O,很快的。

而如果想要改進Titan,讓它的性能進一步提升,需要對源代碼有足夠深入的了解和思考。

歡迎一起討論!!!

5. Titan的測試代碼

使用如下代碼可以測試使用titan和不使用titan的一些性能對比,使用titan的話-use_titan=true即可

#include <unistd.h>
#include <atomic>
#include <iostream>
#include <random>
#include <string>
#include <thread>#include <sys/time.h>#include "rocksdb/db.h"
#include "rocksdb/table.h"
#include "rocksdb/cache.h"
#include "rocksdb/slice_transform.h"
#include "rocksdb/filter_policy.h"
#include "rocksdb/write_batch.h"
#include "rocksdb/rate_limiter.h"
#include "rocksdb/perf_context.h"
#include "rocksdb/iostats_context.h"
#include "gflags/gflags.h"#include "titan/db.h"
#include "titan/options.h"using namespace google;DEFINE_int64(read_ratio,0,"read threads' num");
DEFINE_int64(time,1200,"read threads' ratio");
DEFINE_int64(thread_num,64,"total threads ");
DEFINE_bool(rate_limiter,false,"use rocksdb ratelimiter");
DEFINE_bool(use_dynamic,false,"use dynamic level size");
DEFINE_int64(limit_size, 512, "rate limiter size");
DEFINE_string(db_dir,"./rocksdb_data","rocksdb data's directory");
DEFINE_int64(multidb_nums,1,"the number of multidb");
DEFINE_int64(value_len, 1024, "value size");
DEFINE_bool(use_titan, false, "use titandb");
DEFINE_bool(disable_wal, false, "disable wal");std::atomic<long> g_op_W;
std::atomic<long> g_op_R;// 這里測試過程中為了區分兩種db,聲明了兩個
// 實際的話可以只用一種std::vector<rocksdb::DB*> src_db;
// 實例化完成一個titandb之后 可以將該titandb 賦值給src_db,
// 即 src_db[0] = titan_db;
std::vector<rocksdb::DB*> src_db;
std::vector<rocksdb::titandb::TitanDB*> titan_db;
rocksdb::Options options;
rocksdb::titandb::TitanOptions titan_options;
std::mt19937 generator_; // 生成偽隨機數static double now()
{struct timeval t;gettimeofday(&t, NULL);return t.tv_sec + t.tv_usec / 1e6;
}void SetOptions() {options.create_if_missing = true;options.compression = rocksdb::kNoCompression;options.statistics = rocksdb::CreateDBStatistics();options.stats_persist_period_sec = 10;options.stats_dump_period_sec = 10;std::shared_ptr<rocksdb::Cache> cache = rocksdb::NewLRUCache(10737418240);rocksdb::BlockBasedTableOptions bbto;bbto.whole_key_filtering = true;bbto.cache_index_and_filter_blocks = true;bbto.filter_policy.reset(rocksdb::NewBloomFilterPolicy(16,false));bbto.block_cache = cache;options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(bbto));options.max_background_compactions = 32;if(FLAGS_rate_limiter) {options.strict_bytes_per_sync = true;options.bytes_per_sync = 1024*1024;options.rate_limiter.reset(rocksdb::NewGenericRateLimiter(FLAGS_limit_size*1024*1024,100*1000,10,rocksdb::RateLimiter::Mode::kWritesOnly,true));}if(FLAGS_use_titan) {titan_options = options;}
}
void OpenDB() {SetOptions();for (int i = 1;i <= FLAGS_multidb_nums; i ++) {if (FLAGS_use_titan) {rocksdb::titandb::TitanDB* tmp_db;auto s = rocksdb::titandb::TitanDB::Open(titan_options, FLAGS_db_dir+std::to_string(i), &tmp_db);if (!s.ok()) {std::cout << "open failed :" <<  s.ToString() << std::endl;}titan_db.push_back(tmp_db);} else {rocksdb::DB* tmp_db;auto s = rocksdb::DB::Open(options, FLAGS_db_dir+std::to_string(i), &tmp_db);if (!s.ok()) {std::cout << "open failed :" <<  s.ToString() << std::endl;}src_db.push_back(tmp_db);}}
}void DBWrite(int num) {double ts = now();int db_num = num % FLAGS_multidb_nums;while (true) {std::string key = std::to_string(generator_());std::string value(FLAGS_value_len, 'x');if(num == 0) {rocksdb::SetPerfLevel(rocksdb::PerfLevel::kEnableTimeExceptForMutex);rocksdb::get_perf_context()->Reset();rocksdb::get_iostats_context()->Reset();}rocksdb::WriteOptions wo;wo.disableWAL = FLAGS_disable_wal;if(FLAGS_use_titan) {titan_db[db_num]->Put(wo, "test_graph_"+key, value);} else {src_db[db_num]->Put(wo, "test_graph_"+key, value);}++g_op_W;if(num == 0 && now() - ts >= 1) { // 每隔一秒,打印一次0號線程的延時數據rocksdb::SetPerfLevel(rocksdb::PerfLevel::kDisable);std::cout<< "\nwrite_wal_time "<< rocksdb::get_perf_context()->write_wal_time<< "\nwrite_memtable_time "<< rocksdb::get_perf_context()->write_memtable_time<< "\nwrite_delay_time "<< rocksdb::get_perf_context()->write_delay_time<< std::endl;ts = now();}}
}void DBRead(int num) {std::string value;double ts = now();int db_num = num % FLAGS_multidb_nums;while (true) {std::string key = std::to_string(generator_());if(num == 0) { // 為0號線程開啟 perfrocksdb::SetPerfLevel(rocksdb::PerfLevel::kEnableTimeExceptForMutex);rocksdb::get_perf_context()->Reset();rocksdb::get_iostats_context()->Reset();}if(FLAGS_use_titan) {titan_db[db_num]->Get(rocksdb::ReadOptions(), key, &value);} else {src_db[db_num]->Get(rocksdb::ReadOptions(), key, &value);}++g_op_R;if(num == 0 && now() - ts >= 1) {rocksdb::SetPerfLevel(rocksdb::PerfLevel::kDisable);std::cout<< "\nget_from_memtable_time: " << rocksdb::get_perf_context()->get_from_memtable_time<< "\nget_from_output_files_time: " << rocksdb::get_perf_context()->get_from_output_files_time<< "\nread_nanos "<< rocksdb::get_iostats_context()-> read_nanos<< std::endl;ts = now();}}
}int main(int argc, char** argv) {ParseCommandLineFlags(&argc,&argv, true);OpenDB();if (FLAGS_multidb_nums > FLAGS_thread_num) {std::cout << "multidb nums bigger than thread num, invalid" << std::endl;return -1;}int write_threads = (int)(FLAGS_thread_num - (double)FLAGS_read_ratio / 100.0 * FLAGS_thread_num);for (int i = 0;i < FLAGS_thread_num - write_threads ; i++) {new std::thread(DBRead, i);}for(int i = 0;i < write_threads; ++i) {new std::thread(DBWrite, i);}long last_opn_R = 0;long last_opn_W = 0;int count = FLAGS_time;while(count > 0) {sleep(1);long nopn_R = g_op_R;long nopn_W = g_op_W;std::cout << "read_speed : " << nopn_R - last_opn_R << std::endl;std::cout << "write_speed : " << nopn_W - last_opn_W << std::endl;last_opn_R = nopn_R;last_opn_W = nopn_W;count --;std::string out;// src_db[0]->GetProperty("rocksdb.stats", &out); // 每一層的延時信息// fprintf(stdout, "rocksdb.stats: %s\n", out.c_str());}return 0;
}

總結

以上是生活随笔為你收集整理的TitanDB GC详细实现原理 及其 引入的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

国内精品美女在线观看 | 亚洲精品动漫成人3d无尽在线 | 国产不卡视频在线播放 | 日韩在线观看免费 | 欧美精品日韩 | 免费69视频| 在线观看亚洲视频 | 亚洲综合在线播放 | 国产传媒一区在线 | 亚洲日本欧美在线 | 狠狠色噜噜狠狠狠合久 | 欧美日韩高清一区 | 99久久精品免费看国产一区二区三区 | 五月激情亚洲 | 国产精品123 | 黄色片视频免费 | 黄网站色视频免费观看 | 伊人午夜 | 天天插综合网 | 日韩xxxx视频 | 91 中文字幕 | 一区二区三区在线不卡 | 在线观看网站av | 免费视频网 | 国产91电影在线观看 | 91免费黄视频 | 伊人在线视频 | 亚洲天堂网在线视频 | 久久久一本精品99久久精品66 | 亚洲aⅴ一区二区三区 | 亚洲视频精品在线 | 日韩在线小视频 | 国产午夜三级一区二区三 | 久久高清毛片 | a视频免费 | 日韩电影在线观看一区二区 | 久久手机免费观看 | 日本久久影视 | 日日爱av| 欧美综合色在线图区 | 国产精品久久久久久久电影 | 久久精品www人人爽人人 | 懂色av一区二区在线播放 | 粉嫩高清一区二区三区 | 国产精品三级视频 | 国产福利91精品 | 伊人天天综合 | 97在线观 | 午夜精品久久久久久久久久久久久久 | 18做爰免费视频网站 | 国产中文字幕一区二区三区 | 美女久久一区 | 免费网站黄 | 亚洲精品在线观看的 | 天天鲁一鲁摸一摸爽一爽 | 97视频免费看| 色av色av色av | 91精品国产成人观看 | 久久婷婷一区二区三区 | 成人精品久久久 | 亚洲精品视频在线播放 | 婷婷丁香六月天 | a精品视频| 日日夜夜免费精品视频 | www.伊人色.com | 99精品国产在热久久 | 三级av在线免费观看 | 免费日韩电影 | 日日日天天天 | 五月婷婷丁香激情 | 久久精品国产一区二区电影 | 在线观看色网站 | 人人干干人人 | 久草在线综合网 | 国产精品白浆视频 | 久久亚洲欧美日韩精品专区 | 欧美夫妻性生活电影 | 看av免费 | 一区二区三区观看 | www.com久久 | 91精品资源 | 久久综合九色 | 国产97碰免费视频 | 国产精品一区二区三区在线免费观看 | 国产精品99久久久久人中文网介绍 | 国产原创中文在线 | 天天射天天爱天天干 | a v在线观看 | 六月丁香在线视频 | 国产精品va在线观看入 | 五月色丁香 | 国产中文字幕在线免费观看 | 精产嫩模国品一二三区 | 亚洲视频在线观看免费 | 亚洲精品乱码久久久久久 | 狠狠色狠狠综合久久 | 亚洲国产影院av久久久久 | 日本久久久久久 | 黄色www| 免费日韩一区二区三区 | 久草在线综合网 | 五月婷亚洲 | 久久在线观看 | .国产精品成人自产拍在线观看6 | 久久国产成人午夜av影院宅 | 国产精品一区免费在线观看 | 国产小视频在线播放 | 欧美日韩在线观看一区二区三区 | 97视频在线观看成人 | 美女久久久久久久久久久 | 久久免费国产精品 | 国产精品露脸在线 | 国产一区二区在线看 | 亚洲精品视频久久 | 国产v在线播放 | 色狠狠婷婷 | 最近最新中文字幕 | 天天摸天天舔天天操 | 久久这里只有精品首页 | 亚洲国产人午在线一二区 | 成年人免费在线 | 日韩欧美精品在线 | 亚洲国产精品va在线看黑人 | 亚洲激情综合 | 天天摸天天舔 | www.夜夜草 | 亚洲成人黄 | 91av官网 | 色午夜影院 | 国产一区二区不卡视频 | 日韩一区二区免费在线观看 | 中文字幕资源在线观看 | 国产伦精品一区二区三区在线 | 激情六月婷婷久久 | 麻花天美星空视频 | 91黄色小网站 | 99久久精品国产亚洲 | 一区二区视频在线看 | 日韩特黄一级欧美毛片特黄 | 成人在线网站观看 | 国产精品久久久久高潮 | 精品一区二区在线观看 | 亚洲精品麻豆视频 | 狠狠色丁香婷婷综合视频 | 欧美有色 | 欧美日韩天堂 | 玖玖玖在线观看 | 91精品国产成 | 国产成人av | 97视频在线观看视频免费视频 | 五月天婷亚洲天综合网精品偷 | 国产在线自 | 91福利在线导航 | 国产视频69 | 91观看视频 | 97免费视频在线 | 91在线91| 久久精品一二三区白丝高潮 | 日韩在线观看视频中文字幕 | 欧美九九视频 | 日韩一区二区免费播放 | 黄网站免费大全入口 | 人人擦 | 综合在线观看色 | 人人草天天草 | 992tv成人免费看片 | www.久草.com| 亚洲人成网站精品片在线观看 | 国产1区2区3区在线 亚洲自拍偷拍色图 | 亚洲精品女人久久久 | 亚洲国产精品va在线看黑人动漫 | 一区二区三区不卡在线 | www久久| 亚洲午夜久久久久久久久 | 亚洲久久视频 | 免费在线观看成人av | 超碰国产人人 | 91在线播 | 黄色影院在线免费观看 | 99国产成+人+综合+亚洲 欧美 | 丁香六月久久综合狠狠色 | 免费在线观看视频一区 | 一级片免费观看 | 精品人人人 | 久久高清免费视频 | 99久久精品视频免费 | 国产高清在线一区 | 精品国产理论片 | 在线观av| 国产精品毛片一区视频播 | 午夜性生活片 | 少妇搡bbbb搡bbb搡忠贞 | 精品国产99国产精品 | 亚洲波多野结衣 | 国产精品丝袜在线 | 中文字幕 国产 一区 | av免费电影在线 | 欧美日韩大片在线观看 | 国产精品理论片在线观看 | 91精品人成在线观看 | 国产精品久久一区二区三区不卡 | 99视频精品视频高清免费 | 久草久热 | 蜜臀久久99精品久久久无需会员 | 日韩成人邪恶影片 | 成人av一区二区在线观看 | 国产日韩欧美在线观看视频 | 91九色蝌蚪国产 | 一区在线免费观看 | 欧美一区二区日韩一区二区 | 欧美激情片在线观看 | 国产精品麻豆三级一区视频 | 国产精品久久久久久久久久99 | 久久久久五月天 | 懂色av懂色av粉嫩av分享吧 | 日韩在线视频网 | 91福利专区| 日韩av快播电影网 | 不卡国产视频 | 久草在线视频网站 | 免费在线观看毛片网站 | 久久av中文字幕片 | 色视频在线免费观看 | 日日碰夜夜爽 | 免费av免费观看 | 精品国产一区在线观看 | 视频 国产区 | 日日综合网 | 国产精品久久久久久久久久久久久 | 国产精品美乳一区二区免费 | 亚洲免费在线 | 91麻豆视频| 日韩三级av | 久久精品一区二区三区视频 | 97香蕉久久国产在线观看 | 中文字幕观看av | 美女视频黄免费的 | 91在线欧美| 亚洲精品久久久久58 | 亚洲乱码中文字幕综合 | 国产精品美女免费看 | 久久99精品国产麻豆宅宅 | 亚洲激情综合网 | 视频在线99re | 91夜夜夜| 9999在线视频| 三级黄色网址 | 日韩在线观看第一页 | 成年人视频在线免费播放 | 黄网站色欧美视频 | 国产黄色片久久 | 久久久免费毛片 | 蜜臀91丨九色丨蝌蚪老版 | 最近中文字幕mv免费高清在线 | 国产aa免费视频 | 福利视频区 | 午夜天天操 | 欧美色婷| 亚洲高清在线观看视频 | 在线观看视频一区二区 | 国产精品国产毛片 | 精品99久久久久久 | 婷婷六月天在线 | 韩日av一区二区 | 国产99久久精品一区二区永久免费 | 麻豆极品 | 国产精品一区二区三区视频免费 | 色吊丝在线永久观看最新版本 | 中文字幕免费高清 | 久久成人精品视频 | 最新av网站在线观看 | 亚洲在线免费视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久视频免费观看 | 久久亚洲私人国产精品 | 色婷婷av国产精品 | 日韩大片在线播放 | 国产色视频一区二区三区qq号 | 免费亚洲一区二区 | 免费激情在线电影 | 亚洲成熟女人毛片在线 | 8x成人免费视频 | 欧洲精品码一区二区三区免费看 | 手机av永久免费 | 天天综合区 | 91亚洲国产成人久久精品网站 | 色婷婷激婷婷情综天天 | 久久狠狠干 | 九九视频网站 | 在线视频免费观看 | 亚洲日本一区二区在线 | 国产亚洲精品久久久久久久久久 | 999久久久免费视频 午夜国产在线观看 | www.com久久久 | 97日日 | 亚洲情婷婷 | 日韩高清免费在线观看 | 午夜精品久久久久久久久久久久久久 | 国产亚洲精品久久网站 | 国产九九九精品视频 | 久久成人免费 | 亚洲成人精品国产 | 手机在线永久免费观看av片 | 一个色综合网站 | 香蕉视频日本 | 亚洲激情中文 | 在线精品视频免费播放 | 欧美午夜精品久久久久久孕妇 | 蜜桃av观看 | 国产精品1024| 日韩中文字幕网站 | 久久精品国产亚洲精品2020 | 国产精品一区二区吃奶在线观看 | 天天鲁一鲁摸一摸爽一爽 | 免费av在 | 狠狠操.com | 最新动作电影 | 免费a视频在线观看 | 四虎最新域名 | 欧美久久久久久久久久久久 | 精品久久久久国产免费第一页 | 97在线观看免费高清完整版在线观看 | 久久美女高清视频 | 日韩高清免费电影 | www.黄色片网站 | 97免费中文视频在线观看 | 超碰夜夜 | 久草在线最新 | 欧美日韩视频免费 | 欧美91片 | 91精品视频在线看 | 国内精品福利视频 | 国产麻豆视频 | 亚洲欧美激情插 | 美州a亚洲一视本频v色道 | 人人爱人人添 | 久草精品在线 | 免费看的黄网站 | 天天操天天干天天爽 | 日韩精品久久久久久久电影99爱 | 超碰人人射 | 久久综合精品一区 | 亚洲欧洲av | 天天摸天天弄 | www视频在线免费观看 | 91免费视频黄 | 久久久久久福利 | 综合色婷婷 | av不卡免费看 | 午夜色影院 | 97超碰免费在线观看 | 久久国产成人午夜av影院宅 | 97视频入口免费观看 | 久久免费激情视频 | 精品久久99 | 亚洲国产97在线精品一区 | 亚洲精品美女在线观看播放 | 亚洲一级免费电影 | 色鬼综合网 | 精品国产诱惑 | 国产啊v在线 | 欧美aaa视频| 中文字幕在线视频第一页 | 最近最新中文字幕 | 国产999久久久 | 中文字幕在线看视频国产中文版 | 欧美一级黄大片 | 国产精品久久久免费 | 国产欧美精品一区二区三区 | 99久久婷婷国产一区二区三区 | 精品一区 精品二区 | 美女网站在线看 | 99国产情侣在线播放 | 久久丁香| 精品国产1区二区 | 久久国产一区二区 | www.久久久久 | 久草在线 | 欧美激情视频免费看 | 男女免费视频观看 | 超碰人人舔 | 国产91精品在线观看 | 国产麻豆视频免费观看 | 国内精品免费 | 中文字幕在线视频一区二区三区 | 久久一区二区免费视频 | av在线播放观看 | 在线观看网站黄 | 24小时日本在线www免费的 | 丁香婷婷综合色啪 | 日日狠狠 | 久久久精品国产一区二区电影四季 | 久草在线资源免费 | 亚洲一级国产 | 在线视频婷婷 | 国产精品a久久久久 | 特级西西444www大胆高清无视频 | 91九色在线观看视频 | 亚洲日本精品视频 | 中文字幕免费高 | 亚洲在线视频免费 | 久久精品国产v日韩v亚洲 | 丰满少妇对白在线偷拍 | 免费成人黄色片 | 中文字幕视频观看 | 精品毛片一区二区免费看 | 国产97免费 | 国产视频精品久久 | 毛片网在线 | 国产小视频91 | 免费高清在线观看成人 | 天天舔夜夜操 | 亚洲成人免费在线观看 | 国产美女黄网站免费 | 亚洲精品国产精品国自 | 二区视频在线 | 日本精品免费看 | 国产精品久久久久9999 | 在线看成人片 | 欧美日韩一区二区三区在线观看视频 | 国产成人一区二区三区在线观看 | 人人玩人人添人人澡97 | 亚洲 成人 欧美 | 中文字幕乱码亚洲精品一区 | 超碰99人人 | 91九色成人 | 欧美精品xx | 综合成人在线 | 日本系列中文字幕 | 韩日精品在线 | 最新不卡av | 中文字幕有码在线 | 日韩在线电影 | 成人国产综合 | www.97色.com | 人人狠狠综合久久亚洲婷 | 97人人射| av在线电影网站 | 狠狠躁夜夜a产精品视频 | 久久精品一区二区三区国产主播 | 视频三区在线 | 国产视频精品久久 | 91免费在线| 91在线看片 | 99久热在线精品视频成人一区 | 西西444www大胆高清图片 | 一区二区电影网 | 国精产品满18岁在线 | 中文字幕av在线电影 | www夜夜操com | 免费毛片一区二区三区久久久 | 91porny九色在线播放 | 日本久久中文字幕 | 成人黄色大片在线免费观看 | 2024国产精品视频 | 高清av网| 日韩特级毛片 | 亚洲成人中文在线 | 久久精彩免费视频 | 国色天香在线 | 中文字幕免费高清av | 国产黄在线看 | 久久tv视频 | 亚洲视频2 | 欧美色图东方 | 又黄又爽的视频在线观看网站 | 亚洲第一区精品 | 国产亚洲精品美女久久 | 亚洲乱码在线 | 日韩精品久久一区二区三区 | 91人人网| 97看片| 深爱激情五月婷婷 | 久久不射网站 | 中文免费在线观看 | 亚洲电影一区二区 | 97超碰色偷偷 | 国产色中涩 | 日韩精品欧美专区 | 一区二区高清在线 | 西西4444www大胆无视频 | 在线播放av网址 | 欧美成人影音 | 亚洲极色| 久久久久久久久久影院 | 五月天亚洲婷婷 | 久久久久久久久久久久久9999 | av中文字幕不卡 | 亚洲精品国产精品国自产观看 | 欧美精品被| 国产精品自在线 | 男女激情免费网站 | 玖玖爱国产在线 | 91精品免费在线观看 | 少妇搡bbb| 香蕉久草 | 五月天亚洲激情 | 狠狠的日日| 天天干,夜夜操 | 欧美日韩免费观看一区二区三区 | 日韩理论在线 | 免费看的黄网站 | 91mv.cool在线观看 | 怡红院av| 日韩乱码在线 | 色网免费观看 | 激情综合网色播五月 | 超碰人人在线观看 | 久久精品国产一区二区三 | 人人草在线视频 | av片子在线观看 | 久久久亚洲网站 | 亚洲伊人色| 久久精品一区二区三区国产主播 | 国产精品爽爽爽 | 欧美性生活久久 | 免费av在线| 亚洲视频一 | 亚洲一级二级三级 | 亚洲国产精品小视频 | 亚洲国产精久久久久久久 | 亚在线播放中文视频 | 国产精品一区免费看8c0m | 中文字幕色站 | 五月天欧美精品 | 不卡的av电影 | 九九精品毛片 | 美女久久久久久久久久久 | 久久tv| 成年人黄色免费看 | 久久国产亚洲视频 | 亚洲日韩欧美视频 | 又黄又爽的视频在线观看网站 | 久久这里 | 久久精品一二区 | 99c视频在线 | 美女视频黄在线观看 | 亚洲经典中文字幕 | 久久九九视频 | a午夜电影 | 亚洲免费不卡 | 国产精品a级 | 在线之家免费在线观看电影 | 国产麻豆果冻传媒在线观看 | av成人在线电影 | 天天天天射 | 婷婷久操 | 91精品国产自产在线观看永久 | 国产美女精品 | 天天综合色天天综合 | 日韩欧美视频在线免费观看 | 国产精品成人免费 | 亚洲 欧洲av| 欧美久久久一区二区三区 | 久久黄色网址 | 欧美性做爰猛烈叫床潮 | 黄色国产成人 | 日韩三区在线观看 | 久久艹艹 | av一区在线 | 亚洲欧美在线视频免费 | a在线播放 | 视频一区二区在线 | 五月婷婷,六月丁香 | 黄色精品网站 | 激情综合站 | 精品久久久久免费极品大片 | 久久久久国产精品一区 | 在线视频欧美日韩 | 国产精品中文久久久久久久 | 国产69久久精品成人看 | 国产91学生粉嫩喷水 | 黄污网站在线 | 91污在线| 午夜狠狠操 | 98涩涩国产露脸精品国产网 | 欧美黑人性爽 | 一区二区日韩av | 日韩啪视频 | 888av| 五月天色中色 | 精品免费久久久久久 | 999电影免费在线观看2020 | 欧美日本在线观看视频 | 欧美在线a视频 | 日韩久久精品 | 精品99久久久久久 | 国产综合香蕉五月婷在线 | 最新色站| 夜夜摸夜夜爽 | 亚洲h在线播放在线观看h | 亚洲精品国产精品国自产在线 | 中文字幕观看在线 | 狠狠操电影网 | 亚洲综合五月 | 国产精品久久免费看 | 中文字幕精品一区二区三区电影 | 亚洲精品美女久久 | 欧美欧美 | 久久久久9999亚洲精品 | 国产不卡免费 | 黄色毛片在线看 | 国内精品在线观看视频 | 婷婷亚洲五月 | 五月婷婷一级片 | 亚洲综合在线一区二区三区 | 久草在线在线精品观看 | 婷婷丁香花 | 成年人网站免费在线观看 | 日韩久久电影 | 国产破处视频在线播放 | 国产 一区二区三区 在线 | 欧美老人xxxx18 | 国产成人精品一区二区三区网站观看 | 91麻豆精品国产午夜天堂 | 国产高清福利在线 | 精品国精品自拍自在线 | 国产午夜精品一区二区三区嫩草 | 精品伊人久久久 | 免费观看一区二区三区视频 | 日韩欧美在线综合网 | 中文字幕人成人 | 天天色综合1 | 在线亚洲欧美视频 | 亚洲国产精品500在线观看 | 97人人视频| 亚洲精品女人 | 91精品日韩 | 欧美精品一区二区三区一线天视频 | 久久99精品久久久久久清纯直播 | 色欲综合视频天天天 | 欧美aaa一级 | 久久99操| 91香蕉视频黄色 | 日韩欧美视频在线观看免费 | 97在线观看视频免费 | 不卡在线一区 | 欧美性大战久久久久 | 日韩sese | 日日干天天射 | 日本精品一 | 九九av | 在线电影中文字幕 | 国产色视频网站2 | 精品国偷自产国产一区 | 免费在线播放 | 韩国一区二区av | 一区二区三区免费在线观看 | 性色av香蕉一区二区 | 天天曰天天爽 | 久草观看| 操一草 | 欧美激情一区不卡 | 五月婷婷网站 | 日韩久久久 | 精品国产伦一区二区三区免费 | 91精品国产高清自在线观看 | 在线观看亚洲a | 国产特级毛片 | 欧美精品v国产精品 | 国产一区视频在线播放 | 日韩美女高潮 | 天天干天天弄 | 操操日| 97碰碰视频| 国产无遮挡猛进猛出免费软件 | 日日夜夜狠狠操 | 久草在线免费看视频 | 婷婷色资源| 国产精品福利无圣光在线一区 | 亚洲 欧美 另类人妖 | 国产成人亚洲精品自产在线 | 天天舔天天搞 | 日日精品 | 久久久久国产精品免费免费搜索 | 国产真实精品久久二三区 | 伊甸园永久入口www 99热 精品在线 | 久久精品99国产精品酒店日本 | 99久久久国产精品 | 天天干国产| 久久看片| 玖玖爱免费视频 | 国产一级黄色电影 | 亚洲视频精选 | 日韩精品一区不卡 | 欧美日韩国产精品一区二区 | 国产一区二区三精品久久久无广告 | av在线a| 日日干日日| 欧美日韩三级 | 国内精品美女在线观看 | 国产精品美女久久久久久久久久久 | 丁香九月激情 | 中文字幕刺激在线 | 中文字幕在线一二 | 免费视频在线观看网站 | 三上悠亚一区二区在线观看 | av大片免费| 久久免费国产电影 | 91免费网址 | 成人精品国产 | 日韩在线观看av | 天天射天 | 国产成人精品综合久久久久99 | 久久在线影院 | 欧美一级黄色片 | 亚洲最大免费成人网 | 美女黄网站视频免费 | 午夜性生活| 综合色伊人 | 日本久久高清视频 | 国产亚洲va综合人人澡精品 | 日本久久成人中文字幕电影 | 99riav1国产精品视频 | 在线观看一区视频 | 天天操天天操一操 | 久久精品视频4 | 黄色美女免费网站 | 国产一区二区成人 | 香蕉久草在线 | 国产精品美女www爽爽爽视频 | 国产区av在线 | 免费特级黄色片 | 五月婷婷丁香激情 | 亚洲九九九在线观看 | 免费看短 | 97成人在线 | 亚洲精品久久久久中文字幕m男 | 911免费视频 | 欧日韩在线视频 | 天天综合视频在线观看 | 久久精品久久国产 | 亚洲精品乱码久久 | 久久久精品网站 | 日韩二区三区在线 | 婷婷午夜天 | 天天干天天操天天爱 | 欧美嫩草影院 | 免费看的黄色的网站 | 色偷偷av男人天堂 | 91九色pron| 色综合久久中文综合久久牛 | 亚洲片在线 | 精品在线视频一区二区三区 | 国产一区二区高清视频 | 国产网站av | 天天看天天干 | 狠狠色丁香婷婷综合久久片 | 国产日产高清dvd碟片 | 国产婷婷精品av在线 | 狠狠干成人 | 国产裸体bbb视频 | 亚洲精品久久久久中文字幕二区 | 片黄色毛片黄色毛片 | 99产精品成人啪免费网站 | 色视频网址 | 久久夜靖品 | 亚洲女人天堂成人av在线 | 亚州精品天堂中文字幕 | 欧美在线观看视频免费 | 久久只有精品 | 在线观看片 | 99视频在线观看一区三区 | 97精品久久人人爽人人爽 | 片网址| www亚洲一区| 在线日韩一区 | 九七在线视频 | 欧美精品一区二区蜜臀亚洲 | 91av蜜桃| 国产精品免费小视频 | av福利在线导航 | 2024国产精品视频 | 中文字幕在线影院 | 精品久久久国产 | 婷婷九月激情 | 天天操天天色综合 | 久久极品 | 国产高清在线不卡 | 18做爰免费视频网站 | 日韩三区在线 | 精品久久久久久国产 | 亚洲精品网页 | 久99久精品 | 国产中文在线播放 | 91在线观看欧美日韩 | 激情偷乱人伦小说视频在线观看 | 国产精品999久久久 久产久精国产品 | 婷色在线 | 国产一区二区影院 | a电影免费看 | 国产流白浆高潮在线观看 | 免费看片网址 | av丝袜美腿| 国产你懂的在线 | 日韩理论电影在线观看 | 久久精品a| 91精品国产91久久久久 | 色偷偷男人的天堂av | 992tv在线观看 | 国产在线视频一区 | 久久久久久久久久久影视 | 日韩av影视在线观看 | 久久国产二区 | 13日本xxxxxⅹxxx20| 亚洲资源 | 免费av网址在线观看 | 在线观看中文字幕亚洲 | 欧美日韩一区二区三区不卡 | 日日夜夜网 | 精品在线观看国产 | 国产一区二区三区黄 | 九九热精品国产 | 欧美福利视频一区 | 国产精品久久久av | 日韩欧美视频一区二区 | 久久精品国产一区二区 | 手机看国产毛片 | 久热国产视频 | 久久超级碰 | 婷婷视频在线观看 | 91人人澡人人爽人人精品 | 久久久久久国产精品久久 | 婷婷五综合| 香蕉视频免费在线播放 | 午夜色场| 亚洲在线a | 日韩欧美在线观看一区 | 欧美一级日韩免费不卡 | 久久综合天天 | 日韩 精品 一区 国产 麻豆 | 麻豆视频在线 | 97超碰人| 99免费在线观看视频 | 精品亚洲视频在线 | 国产一级片视频 | 在线免费中文字幕 | 蜜臀av网址 | 激情在线网址 | 久久久片 | 国产免费资源 | 五月婷婷综合激情网 | 亚洲综合视频在线播放 | 精品美女久久 | 91丨九色丨国产女 | 久久久一本精品99久久精品66 | 精品久久1 | 国产精品久一 | 中文字幕在线视频一区 | 国产精品一区二区三区在线看 | 五月婷网站 | 日本中出在线观看 | 久久人人干 | 91av看片| 日韩免费一区二区 | 国内精品久久久久久久久久清纯 | 欧美激情视频一区 | 欧美日韩国产二区三区 | 国产成人久久av免费高清密臂 | 偷拍精偷拍精品欧洲亚洲网站 | 91尤物国产尤物福利在线播放 | 国产特级毛片aaaaaa毛片 | 日韩欧美视频免费看 | 久久精品日产第一区二区三区乱码 | 国产精品日韩高清 | 天堂av在线免费观看 | 99精品视频在线看 | 美女网站视频免费都是黄 | 2020天天干夜夜爽 | 免费在线播放视频 | 五月婷婷中文网 | 久久精品香蕉 | 亚洲视频 一区 | 国产成人精品一区一区一区 | 国产99一区二区 | 国产特级毛片aaaaaa毛片 | 狠狠激情中文字幕 | 在线观av | 日韩在线看片 | 97色在线视频| 免费视频成人 | 国产视频在线一区二区 | 亚洲精品视频免费在线 | 日韩在线观看a | 日韩高清在线不卡 | 欧美精品久久久久久久 | 精品福利视频在线 | 97在线精品国自产拍中文 | 亚洲综合色激情五月 | 午夜在线看| 国产免费叼嘿网站免费 | 日日干日日操 | japanesefreesexvideo高潮 | 91精品对白一区国产伦 | 亚洲国产精品成人女人久久 | 成年人在线免费视频观看 | 国产日本高清 | 国产精品国产三级国产不产一地 | 欧美日韩性生活 | 欧美日韩性生活 | 综合在线亚洲 | 久久9999久久免费精品国产 | 91视频 - 88av| 国产高清精品在线观看 | 色视频成人在线观看免 | 波多野结衣精品视频 | 亚洲在线视频播放 | 久久久久久久久久久久久国产精品 | 久久国产精品免费看 | 久久精品中文字幕少妇 | 久久一区二区三区日韩 | 在线免费高清视频 | 美女网站在线观看 | 久久成人在线视频 | 免费在线一区二区 | 欧美夫妻生活视频 | 亚洲精品视频免费看 | 91亚洲精品乱码久久久久久蜜桃 | 涩涩成人在线 | 狠狠色噜噜狠狠狠合久 | 国产成人av网站 | 91精品伦理 | 久久久久99精品成人片三人毛片 | 天天综合在线观看 | 国产一级黄色免费看 | 色网站免费在线观看 | 久香蕉| 色五月激情五月 | 欧美成人免费在线 | 欧美亚洲国产精品久久高清浪潮 | 久久露脸国产精品 | 亚洲一级片 | 日韩一级电影在线 | 蜜桃视频精品 | 久久久久欠精品国产毛片国产毛生 | 国产亚洲视频在线 | 成人av地址 | av一级网站 | 精品亚洲视频在线观看 | 欧美一区,二区 | 伊人看片 | 中文字幕av有码 | 国产91综合一区在线观看 | 国产精品久久99综合免费观看尤物 | 国产乱码精品一区二区三区介绍 | 一区二区三区视频在线 | 黄色电影网站在线观看 | 久久久久久国产精品亚洲78 | 成人h电影在线观看 | 久久夜色精品国产欧美乱 | 97电影院网| 中文理论片 | 久久久精品一区二区三区 | 九九热免费观看 | 亚洲成人影音 | 人人看黄色 | 久久精品国产美女 | 在线亚洲成人 | 亚洲综合国产精品 | 最新影院 | 日韩一区二区三区高清免费看看 | 久草视频在线新免费 | wwwwww国产 | 亚洲成av人电影 | 亚洲综合精品视频 | 国产福利91精品一区二区三区 | 夜夜婷婷 | 五月婷婷网站 | 天天操天天色天天射 | 国产一区观看 | sesese图片 | 国产精品video| 高清国产午夜精品久久久久久 | 国产 精品 资源 | 国产精品久久久久一区二区三区共 | 午夜神马福利 | 五月天婷婷在线播放 | 精品久久久免费 | 日韩精品偷拍 | 成人av免费在线看 | 去看片| 国产一区二区三区在线免费观看 | 久久久久麻豆 | 精品麻豆入口免费 | 久久久久区 | 日韩视频免费观看高清完整版在线 | 亚洲码国产日韩欧美高潮在线播放 | 亚洲激情婷婷 | 天天综合视频在线观看 | 日操操| 99久久综合国产精品二区 | 日韩精品专区 | 中文在线a天堂 | 久久久 精品 | 久久无码精品一区二区三区 | 精品国产欧美一区二区三区不卡 | 欧美人体xx | 香蕉在线播放 |