@@ -85,6 +85,7 @@ class TieredStorage::ShardOpManager : public tiering::OpManager {
8585
8686 // Clear IO pending flag for entry
8787 void ClearIoPending (OpManager::KeyRef key) {
88+ FlagBackpressure (key, false );
8889 if (auto pv = Find (key); pv) {
8990 pv->SetStashPending (false );
9091 stats_.total_cancels ++;
@@ -143,6 +144,7 @@ class TieredStorage::ShardOpManager : public tiering::OpManager {
143144 // Find entry by key in db_slice and store external segment in place of original value.
144145 // Update memory stats
145146 void SetExternal (OpManager::KeyRef key, tiering::DiskSegment segment) {
147+ FlagBackpressure (key, true );
146148 if (auto * pv = Find (key); pv) {
147149 auto * stats = GetDbTableStats (key.first );
148150
@@ -169,6 +171,14 @@ class TieredStorage::ShardOpManager : public tiering::OpManager {
169171 SetExternal ({sub_dbid, sub_key}, sub_segment);
170172 }
171173
174+ void FlagBackpressure (OpManager::KeyRef id, bool result) {
175+ const auto & [dbid, key] = id;
176+ if (auto it = ts_->backpressure_ .find ({dbid, string{key}}); it != ts_->backpressure_ .end ()) {
177+ it->second .Resolve (result);
178+ ts_->backpressure_ .erase (it);
179+ }
180+ }
181+
172182 struct {
173183 uint64_t total_stashes = 0 , total_cancels = 0 , total_fetches = 0 ;
174184 uint64_t total_defrags = 0 ;
@@ -309,6 +319,8 @@ error_code TieredStorage::Open(string_view base_path) {
309319}
310320
311321void TieredStorage::Close () {
322+ for (auto & [_, f] : backpressure_)
323+ f.Resolve (false );
312324 op_manager_->Close ();
313325}
314326
@@ -350,9 +362,10 @@ template TieredStorage::TResult<size_t> TieredStorage::Modify(
350362 DbIndex dbid, std::string_view key, const PrimeValue& value,
351363 std::function<size_t (std::string*)> modf);
352364
353- bool TieredStorage::TryStash (DbIndex dbid, string_view key, PrimeValue* value) {
365+ std::optional<util::fb2::Future<bool >> TieredStorage::TryStash (DbIndex dbid, string_view key,
366+ PrimeValue* value) {
354367 if (!ShouldStash (*value))
355- return false ;
368+ return {} ;
356369
357370 // This invariant should always hold because ShouldStash tests for IoPending flag.
358371 CHECK (!bins_->IsPending (dbid, key));
@@ -361,7 +374,7 @@ bool TieredStorage::TryStash(DbIndex dbid, string_view key, PrimeValue* value) {
361374 // with a lot of underutilized disk space.
362375 if (op_manager_->GetStats ().pending_stash_cnt >= config_.write_depth_limit ) {
363376 ++stats_.stash_overflow_cnt ;
364- return false ;
377+ return {} ;
365378 }
366379
367380 StringOrView raw_string = value->GetRawString ();
@@ -375,15 +388,24 @@ bool TieredStorage::TryStash(DbIndex dbid, string_view key, PrimeValue* value) {
375388 } else if (auto bin = bins_->Stash (dbid, key, raw_string.view ()); bin) {
376389 id = bin->first ;
377390 ec = op_manager_->Stash (id, bin->second );
391+ } else {
392+ return {}; // Silently added to bin
378393 }
379394
380395 if (ec) {
381396 LOG_IF (ERROR, ec != errc::file_too_large) << " Stash failed immediately" << ec.message ();
382397 visit ([this ](auto id) { op_manager_->ClearIoPending (id); }, id);
383- return false ;
398+ return {};
399+ }
400+
401+ // Throttle stashes over the offload boundary
402+ if (ShouldOffload ()) {
403+ util::fb2::Future<bool > fut;
404+ backpressure_[{dbid, string{key}}] = fut;
405+ return fut;
384406 }
385407
386- return true ;
408+ return {} ;
387409}
388410
389411void TieredStorage::Delete (DbIndex dbid, PrimeValue* value) {
@@ -405,6 +427,11 @@ void TieredStorage::Delete(DbIndex dbid, PrimeValue* value) {
405427
406428void TieredStorage::CancelStash (DbIndex dbid, std::string_view key, PrimeValue* value) {
407429 DCHECK (value->HasStashPending ());
430+
431+ // If any previous write was happening, it has been cancelled
432+ if (auto node = backpressure_.extract ({dbid, string{key}}); !node.empty ())
433+ std::move (node.mapped ()).Resolve (false );
434+
408435 if (OccupiesWholePages (value->Size ())) {
409436 op_manager_->Delete (KeyRef (dbid, key));
410437 } else if (auto bin = bins_->Delete (dbid, key); bin) {
0 commit comments