@@ -18,6 +18,7 @@ extern "C" {
1818
1919#include " base/logging.h"
2020#include " core/page_usage/page_usage_stats.h"
21+ #include " core/tiering_types.h"
2122
2223using namespace std ;
2324
@@ -49,7 +50,7 @@ namespace dfly {
4950namespace {
5051
5152static_assert (sizeof (QList) == 48 );
52- static_assert (sizeof (QList::Node) == 40 );
53+ static_assert (sizeof (QList::Node) == 48 );
5354
5455enum IterDir : uint8_t { FWD = 1 , REV = 0 };
5556
@@ -167,6 +168,8 @@ QList::Node* CreateRAW(int container, uint8_t* entry, size_t sz) {
167168 node->recompress = 0 ;
168169 node->dont_compress = 0 ;
169170 node->offloaded = 0 ;
171+ node->io_pending = 0 ;
172+ node->fragment = nullptr ;
170173
171174 return node;
172175}
@@ -515,6 +518,14 @@ void QList::Clear() noexcept {
515518
516519 while (len_) {
517520 Node* next = current->next ;
521+
522+ // Clean up offloaded/pending nodes before freeing.
523+ if (current->offloaded || current->io_pending ) {
524+ if (tiering_params_ && tiering_params_->delete_cb ) {
525+ tiering_params_->delete_cb (current);
526+ }
527+ }
528+
518529 if (current->encoding != QUICKLIST_NODE_ENCODING_RAW) {
519530 quicklistLZF* lzf = (quicklistLZF*)current->entry ;
520531 stats.compressed_bytes -= lzf->sz ;
@@ -905,7 +916,7 @@ void QList::CoolOff(Node* node, uint32_t node_id) {
905916 // off due to merges (can be improved in future).
906917 if (node_id >= tiering_params_->node_depth_threshold &&
907918 node_id + tiering_params_->node_depth_threshold < len_) {
908- if (!node->offloaded ) {
919+ if (!node->offloaded && !node-> io_pending ) {
909920 OffloadNode (node);
910921 }
911922 } else if (num_offloaded_nodes_ * 2 + tiering_params_->node_depth_threshold * 2 < len_) {
@@ -921,12 +932,12 @@ void QList::CoolOff(Node* node, uint32_t node_id) {
921932 while (traverse_node_id <= len_ / 2 &&
922933 (num_offloaded_nodes_ + 2 * tiering_params_->node_depth_threshold ) < len_) {
923934 if (traverse_node_id >= tiering_params_->node_depth_threshold ) {
924- if (fw->offloaded == 0 ) {
935+ if (fw->offloaded == 0 && fw-> io_pending == 0 ) {
925936 OffloadNode (fw);
926937 }
927938
928939 // Avoid offloading the same node twice when fw and rev meet in the middle.
929- if (rev != fw && rev->offloaded == 0 ) {
940+ if (rev != fw && rev->offloaded == 0 && rev-> io_pending == 0 ) {
930941 OffloadNode (rev);
931942 }
932943 }
@@ -994,12 +1005,28 @@ void QList::CompressByDepth(Node* node) {
9941005void QList::AccessForReads (bool recompress, Node* node) {
9951006 DCHECK (node);
9961007 stats.total_node_reads ++;
1008+
1009+ if (node->io_pending ) {
1010+ // A stash is in flight — cancel it. The delete_cb handles cancellation.
1011+ DCHECK (tiering_params_);
1012+ if (tiering_params_->delete_cb ) {
1013+ tiering_params_->delete_cb (node);
1014+ }
1015+ DCHECK (!node->io_pending );
1016+ }
1017+
9971018 if (node->offloaded ) {
9981019 DCHECK (tiering_params_);
9991020 stats.onload_requests ++;
1021+ if (tiering_params_->onload_cb ) {
1022+ tiering_params_->onload_cb (node);
1023+ }
1024+ // After onload_cb returns, the node entry must be restored.
1025+ DCHECK (!node->offloaded );
1026+ DCHECK (node->entry != nullptr );
10001027 num_offloaded_nodes_--;
1001- node->offloaded = 0 ;
10021028 }
1029+
10031030 if (len_ > 2 && node != head_ && node->next != nullptr ) {
10041031 stats.interior_node_reads ++;
10051032 }
@@ -1121,8 +1148,16 @@ void QList::DelNode(Node* node) {
11211148 len_--;
11221149 count_ -= node->count ;
11231150 malloc_size_ -= node->sz ;
1124- if (node->offloaded ) {
1125- num_offloaded_nodes_--;
1151+
1152+ if (node->offloaded || node->io_pending ) {
1153+ if (node->offloaded )
1154+ num_offloaded_nodes_--;
1155+ else if (node->io_pending )
1156+ num_offloaded_nodes_--; // was pre-counted in OffloadNode
1157+ // Clean up disk segment and deregister fragment.
1158+ if (tiering_params_ && tiering_params_->delete_cb ) {
1159+ tiering_params_->delete_cb (node);
1160+ }
11261161 }
11271162
11281163 /* If we deleted a node within our compress depth, we
@@ -1158,9 +1193,16 @@ bool QList::DelPackedIndex(Node* node, uint8_t* p) {
11581193
11591194void QList::OffloadNode (Node* node) {
11601195 DCHECK (tiering_params_ && node->offloaded == 0 );
1196+ if (node->io_pending || node->IsCompressed ())
1197+ return ;
1198+
11611199 num_offloaded_nodes_++;
11621200 stats.offload_requests ++;
1163- node->offloaded = 1 ;
1201+ if (tiering_params_->offload_cb ) {
1202+ tiering_params_->offload_cb (node);
1203+ } else {
1204+ node->offloaded = 1 ;
1205+ }
11641206}
11651207
11661208void QList::InitIteratorEntry (Iterator* it) const {
@@ -1387,6 +1429,16 @@ uint8_t* QList::TryExtractListpack() {
13871429 return res;
13881430}
13891431
1432+ void QList::Node::SetExternal (tiering::Fragment* f) {
1433+ // Update malloc size for parent QList node
1434+ DCHECK (f->GetOpaque ());
1435+ reinterpret_cast <QList*>(f->GetOpaque ())->AdjustMallocSize (-sz);
1436+ zfree (entry);
1437+ entry = nullptr ;
1438+ fragment = f;
1439+ offloaded = 1 ;
1440+ }
1441+
13901442bool QList::Iterator::Next () {
13911443 if (!current_)
13921444 return false ;
0 commit comments