@@ -426,6 +426,14 @@ void QList::Node::SetExternal(size_t offset, uint32_t size) {
426426 ext_size = size;
427427}
428428
429+ void QList::Node::Upload (QList* ql, std::string_view val) {
430+ entry = static_cast <unsigned char *>(zmalloc (val.size ()));
431+ memcpy (entry, val.data (), val.size ());
432+ ql->AdjustMallocSize (val.size ());
433+ ql->AdjustOffloadNodeCount (-1 );
434+ offloaded = 0 ;
435+ }
436+
429437void QList::SetPackedThreshold (unsigned threshold) {
430438 packed_threshold = threshold;
431439}
@@ -480,10 +488,9 @@ QList::QList(QList&& other) noexcept
480488 tiering_enabled_(other.tiering_enabled_),
481489 compress_(other.compress_),
482490 bookmark_count_(other.bookmark_count_),
483- num_offloaded_nodes_( other.num_offloaded_nodes_ ) {
491+ tiering_params_(std::move( other.tiering_params_) ) {
484492 other.head_ = nullptr ;
485493 other.len_ = other.count_ = 0 ;
486- other.num_offloaded_nodes_ = 0 ;
487494}
488495
489496QList::~QList () {
@@ -503,9 +510,9 @@ QList& QList::operator=(QList&& other) noexcept {
503510 tiering_enabled_ = other.tiering_enabled_ ;
504511 compress_ = other.compress_ ;
505512 bookmark_count_ = other.bookmark_count_ ;
506- num_offloaded_nodes_ = other.num_offloaded_nodes_ ;
507513 other.head_ = nullptr ;
508- other.len_ = other.count_ = other.num_offloaded_nodes_ = 0 ;
514+ other.len_ = other.count_ = 0 ;
515+ tiering_params_ = std::move (other.tiering_params_ );
509516 }
510517 return *this ;
511518}
@@ -519,7 +526,7 @@ void QList::Clear() noexcept {
519526 // If entry is offloaded we should skip freeing its memory.
520527 bool free_entry = current->offloaded == 0 ;
521528 if (tiering_enabled_ && (current->offloaded || current->io_pending )) {
522- CleanupOffloadedNode ( current);
529+ tiering_params_-> cleanup ( this , current);
523530 } else {
524531 if (current->encoding != QUICKLIST_NODE_ENCODING_RAW) {
525532 quicklistLZF* lzf = (quicklistLZF*)current->entry ;
@@ -540,7 +547,6 @@ void QList::Clear() noexcept {
540547 head_ = nullptr ;
541548 count_ = 0 ;
542549 malloc_size_ = 0 ;
543- num_offloaded_nodes_ = 0 ;
544550}
545551
546552void QList::Push (string_view value, Where where) {
@@ -915,6 +921,9 @@ void QList::Replace(Iterator it, std::string_view elem) {
915921
916922void QList::CoolOff (Node* node, uint32_t node_id) {
917923 if (tiering_enabled_) {
924+ uint32_t threshold = tiering_params_->node_depth_threshold ;
925+ uint32_t num_offloaded_nodes = tiering_params_->num_offloaded_nodes ;
926+
918927 // Dry run for offloading decision.
919928 // a. Node id is withing the offloadable depth - offload it if not already offloaded.
920929 // b. Node id is outside the offloadable depth - but we have too many nodes that are not
@@ -925,12 +934,11 @@ void QList::CoolOff(Node* node, uint32_t node_id) {
925934 // we won't need to traverse them again for "trivial" access patterns unless they
926935 // get accessed again. Another reason for missing offloaded nodes is that node_id can be
927936 // off due to merges (can be improved in future).
928- if (node_id >= tiering_node_depth_threshold_ &&
929- node_id + tiering_node_depth_threshold_ < len_) {
937+ if (node_id >= threshold && node_id + threshold < len_) {
930938 if (!node->offloaded && !node->io_pending ) {
931- OffloadNode ( node);
939+ tiering_params_-> offload ( this , node);
932940 }
933- } else if (num_offloaded_nodes_ * 2 + tiering_node_depth_threshold_ * 2 < len_) {
941+ } else if (num_offloaded_nodes * 2 + threshold * 2 < len_) {
934942 // We check `num_offloaded_nodes_ * 2` above to avoid frequent traversals.
935943 // So only when the gap between offloaded and non-offloaded nodes is large enough,
936944 // we do a traversal to offload more nodes.
@@ -940,16 +948,15 @@ void QList::CoolOff(Node* node, uint32_t node_id) {
940948
941949 // Traverse from both ends towards the middle as we expect more offloads towards the ends
942950 // due to usual access patterns of adding items via lpush/rpush.
943- while (traverse_node_id <= len_ / 2 &&
944- (num_offloaded_nodes_ + 2 * tiering_node_depth_threshold_) < len_) {
945- if (traverse_node_id >= tiering_node_depth_threshold_) {
951+ while (traverse_node_id <= len_ / 2 && (num_offloaded_nodes + 2 * threshold) < len_) {
952+ if (traverse_node_id >= threshold) {
946953 if (fw->offloaded == 0 && fw->io_pending == 0 ) {
947- OffloadNode ( fw);
954+ tiering_params_-> offload ( this , fw);
948955 }
949956
950957 // Avoid offloading the same node twice when fw and rev meet in the middle.
951958 if (rev != fw && rev->offloaded == 0 && rev->io_pending == 0 ) {
952- OffloadNode ( rev);
959+ tiering_params_-> offload ( this , rev);
953960 }
954961 }
955962 fw = fw->next ;
@@ -1047,12 +1054,12 @@ void QList::Materialize(Node* node) {
10471054
10481055 // Cancel stash in progress before loading.
10491056 if (node->io_pending ) {
1050- CleanupOffloadedNode ( node);
1057+ tiering_params_-> cleanup ( this , node);
10511058 }
10521059
10531060 // Load the offloaded node data back into memory.
10541061 if (node->offloaded ) {
1055- ReadOffloadedNode ( node);
1062+ tiering_params_-> load ( this , node);
10561063 }
10571064
10581065 DCHECK (!node->offloaded );
@@ -1193,7 +1200,7 @@ void QList::DelNode(Node* node) {
11931200 }
11941201
11951202 if (tiering_enabled_ && (node->offloaded || node->io_pending )) {
1196- CleanupOffloadedNode ( node);
1203+ tiering_params_-> cleanup ( this , node);
11971204 }
11981205
11991206 /* If we deleted a node within our compress depth, we
@@ -1241,18 +1248,20 @@ bool QList::DelPackedIndex(Node* node, uint8_t* p) {
12411248 return false ;
12421249}
12431250
1244- void QList::OffloadNode (Node* node) const {
1245- DCHECK (tiering_enabled_ && node->offloaded == 0 && node->io_pending == 0 );
1246- stats.offload_requests ++;
1247- node->io_pending = 1 ;
1248- }
1249-
1250- void QList::ReadOffloadedNode (QList::Node* node) const {
1251- stats.onload_requests ++;
1252- }
1253-
1254- void QList::CleanupOffloadedNode (QList::Node* node) const {
1255- node->io_pending = 0 ;
1251+ void QList::SetDbIndex (DbIndex db_id) {
1252+ if (db_id_ == db_id) {
1253+ return ;
1254+ }
1255+ // Materialize all offloaded nodes before changing db_id
1256+ if (tiering_enabled_ && tiering_params_->num_offloaded_nodes > 0 ) {
1257+ Node* node = head_;
1258+ while (node) {
1259+ Node* next = node->next ;
1260+ Materialize (node);
1261+ node = (next == head_) ? nullptr : next;
1262+ }
1263+ }
1264+ db_id_ = db_id;
12561265}
12571266
12581267void QList::InitIteratorEntry (Iterator* it) const {
0 commit comments