@@ -59,6 +59,8 @@ rocksdb::Status TopK::IncrBy(engine::Context &ctx, const Slice &user_key, const
5959 s = getTopKData (ctx, ns_key, topk_metadata, &topk);
6060 if (!s.ok ()) return s;
6161
62+ std::vector<bool > is_dirty_buckets (topk_metadata.width * topk_metadata.depth , false );
63+ std::vector<bool > is_dirty_heaps (topk_metadata.top_k , false );
6264 topk.Add (items.data_ , incr);
6365
6466 s = setTopkData (ctx, ns_key, topk_metadata, topk);
@@ -96,7 +98,7 @@ rocksdb::Status TopK::List(engine::Context &ctx, const Slice &user_key, std::vec
9698
9799 auto heap_buckets = topk.List ();
98100 for (auto &bucket : heap_buckets) {
99- items.emplace_back (bucket.item , bucket. itemlen );
101+ items.emplace_back (bucket.item );
100102 }
101103
102104 return rocksdb::Status::OK ();
@@ -140,7 +142,10 @@ rocksdb::Status TopK::createTopK(engine::Context &ctx, const Slice &ns_key, uint
140142 s = batch->Put (metadata_cf_handle_, ns_key, top_k_meta_bytes);
141143 if (!s.ok ()) return s;
142144
143- s = setTopkData (ctx, ns_key, *metadata, block_split_top_k);
145+ // is dirty vector to optimize writes
146+ std::vector<bool > is_dirty_buckets (width * depth, true );
147+ std::vector<bool > is_dirty_heaps (k, true );
148+ s = setTopkData (ctx, ns_key, *metadata, block_split_top_k, is_dirty_buckets, is_dirty_heaps);
144149 if (!s.ok ()) return s;
145150
146151 return storage_->Write (ctx, storage_->DefaultWriteOptions (), batch->GetWriteBatch ());
@@ -154,25 +159,40 @@ rocksdb::Status TopK::getTopKData(engine::Context &ctx, const Slice &ns_key, con
154159 rocksdb::Status s = storage_->Get (ctx, ctx.GetReadOptions (), tk_key, &pinnable_value);
155160 if (!s.ok ()) return s;
156161 if (i == 0 ) {
157- if (pinnable_value.size () != metadata.width * metadata.depth * sizeof (Bucket)) {
158- return rocksdb::Status::Corruption (" TopK data corrupted: buckets size mismatch" );
162+ // get buckets of topk structure
163+ for (uint32_t j = 0 ; j < metadata.width * metadata.depth ; j++) {
164+ for (uint8_t k = 0 ; k < 2 ; k++) {
165+ std::string bk_key = getSubKey (ns_key, metadata, i, j, k);
166+ rocksdb::PinnableSlice bk_value;
167+ rocksdb::Status s = storage_->Get (ctx, ctx.GetReadOptions (), bk_key, &bk_value);
168+ if (!s.ok ()) return s;
169+
170+ int dep = j / metadata.width ;
171+ int wid = j % metadata.width ;
172+ if (k == 0 ) {
173+ topk->buckets [dep][wid].fp = static_cast <uint32_t >(std::stoul (pinnable_value.data ()));
174+ } else {
175+ topk->buckets [dep][wid].count = static_cast <uint32_t >(std::stoul (pinnable_value.data ()));
176+ }
177+ }
159178 }
160- memcpy (topk->buckets , pinnable_value.data (), pinnable_value.size ());
161179 } else if (i == 1 ) {
162- if (pinnable_value.size () != metadata.top_k * sizeof (HeapBucket)) {
163- return rocksdb::Status::Corruption (" TopK data corrupted: heap size mismatch" );
164- }
165- memcpy (topk->heap , pinnable_value.data (), pinnable_value.size ());
180+ // get heapbucket of topk structure
166181 for (uint32_t j = 0 ; j < metadata.top_k ; j++) {
167- std::string hb_key = getHBKey (ns_key, metadata, i, j);
168- rocksdb::PinnableSlice hb_value;
169- rocksdb::Status s = storage_->Get (ctx, ctx.GetReadOptions (), hb_key, &hb_value);
170- if (!s.ok ()) return s;
171- if (hb_value.size () != topk->heap [j].itemlen ) {
172- return rocksdb::Status::Corruption (" TopK data corrupted: heap bucket size mismatch" );
182+ for (uint8_t k = 0 ; k < 3 ; k++) {
183+ std::string hb_key = getSubKey (ns_key, metadata, i, j, k);
184+ rocksdb::PinnableSlice hb_value;
185+ rocksdb::Status s = storage_->Get (ctx, ctx.GetReadOptions (), hb_key, &hb_value);
186+ if (!s.ok ()) return s;
187+
188+ if (k == 0 ) {
189+ topk->heap [j].count = static_cast <uint32_t >(std::stoul (pinnable_value.data ()));
190+ } else if (k == 1 ) {
191+ topk->heap [j].fp = static_cast <uint32_t >(std::stoul (pinnable_value.data ()));
192+ } else {
193+ topk->heap [j].item = hb_value.data ();
194+ }
173195 }
174- topk->heap [j].item = new char [topk->heap [j].itemlen ];
175- memcpy (topk->heap [j].item , hb_value.data (), hb_value.size ());
176196 }
177197 } else {
178198 topk->heap_size = static_cast <int >(std::stoul (pinnable_value.data ()));
@@ -182,30 +202,56 @@ rocksdb::Status TopK::getTopKData(engine::Context &ctx, const Slice &ns_key, con
182202}
183203
184204rocksdb::Status TopK::setTopkData (engine::Context &ctx, const Slice &ns_key, const TopKMetadata &metadata,
185- const BlockSplitTopK &topk) {
205+ const BlockSplitTopK &topk, const std::vector<bool > &is_dirty_buckets,
206+ const std::vector<bool > &is_dirty_heaps) {
186207 auto batch = storage_->GetWriteBatchBase ();
187- WriteBatchLogData log_data (kRedisTopK , {" setTopkData" });
188- rocksdb::Status s = batch->PutLogData (log_data.Encode ());
189- if (!s.ok ()) return s;
190208
191209 for (uint8_t i = 0 ; i < 3 ; i++) {
192- std::string tk_key = getTKKey (ns_key, metadata, i);
193- std::string tk_value;
194210 if (i == 0 ) {
195- tk_value.assign (reinterpret_cast <const char *>(topk.buckets ), metadata.width * metadata.depth * sizeof (Bucket));
211+ for (uint32_t j = 0 ; j < metadata.width * metadata.depth ; j++) {
212+ if (!is_dirty_buckets[j]) {
213+ continue ;
214+ }
215+ for (uint32_t k = 0 ; k < 2 ; k++) {
216+ std::string sub_key = getSubKey (ns_key, metadata, i, j, k);
217+ std::string sub_value;
218+ int dep = j / metadata.width ;
219+ int wid = j % metadata.width ;
220+ if (k == 0 ) {
221+ sub_value = std::to_string (topk.buckets [dep][wid].fp );
222+ } else {
223+ sub_value = std::to_string (topk.buckets [dep][wid].count );
224+ }
225+ rocksdb::Status s = batch->Put (sub_key, sub_value);
226+ if (!s.ok ()) return s;
227+ }
228+ }
196229 } else if (i == 1 ) {
197- tk_value.assign (reinterpret_cast <const char *>(topk.heap ), metadata.top_k * sizeof (HeapBucket));
198230 for (uint32_t j = 0 ; j < metadata.top_k ; j++) {
199- std::string hb_key = getHBKey (ns_key, metadata, i, j);
200- std::string hb_value (topk.heap [j].item , topk.heap [j].itemlen );
201- s = batch->Put (hb_key, hb_value);
202- if (!s.ok ()) return s;
231+ if (!is_dirty_heaps[j]) {
232+ continue ;
233+ }
234+ for (uint8_t k = 0 ; k < 3 ; k++) {
235+ std::string sub_key = getSubKey (ns_key, metadata, i, j, k);
236+ std::string sub_value;
237+ if (k == 0 ) {
238+ sub_value = std::to_string (topk.heap [j].count );
239+ } else if (k == 1 ) {
240+ sub_value = std::to_string (topk.heap [j].fp );
241+ } else {
242+ sub_value = topk.heap [j].item ;
243+ }
244+ rocksdb::Status s = batch->Put (sub_key, sub_value);
245+ if (!s.ok ()) return s;
246+ }
203247 }
204248 } else {
249+ std::string tk_key = getTKKey (ns_key, metadata, i);
250+ std::string tk_value;
205251 tk_value = std::to_string (topk.heap_size );
252+ rocksdb::Status s = batch->Put (tk_key, tk_value);
253+ if (!s.ok ()) return s;
206254 }
207- rocksdb::Status s = batch->Put (tk_key, tk_value);
208- if (!s.ok ()) return s;
209255 }
210256
211257 return storage_->Write (ctx, storage_->DefaultWriteOptions (), batch->GetWriteBatch ());
@@ -218,10 +264,11 @@ std::string TopK::getTKKey(const Slice &ns_key, const TopKMetadata &metadata, ui
218264 return bf_key;
219265}
220266
221- std::string TopK::getHBKey (const Slice &ns_key, const TopKMetadata &metadata, uint8_t topk_index, uint32_t hp_index ) {
267+ std::string TopK::getSubKey (const Slice &ns_key, const TopKMetadata &metadata, uint8_t topk_index, uint32_t sub_index, uint8_t index ) {
222268 std::string sub_key;
223269 PutFixed8 (&sub_key, topk_index);
224- PutFixed32 (&sub_key, hp_index);
270+ PutFixed32 (&sub_key, sub_index);
271+ PutFixed8 (&sub_key, index);
225272 return InternalKey (ns_key, sub_key, metadata.version , storage_->IsSlotIdEncoded ()).Encode ();
226273}
227274
0 commit comments