Skip to content

Prevent SENT bucket GC until bucket_send() is done with the bucket #433

@Gerold103

Description

@Gerold103

Bucket GC procedure drops SENT buckets as soon as it sees them. The problem is that bucket_send() might still be in progress and expects the SENT bucket to stay until the sending is fully finished.

GC should take into account rebalancer_transfering_buckets.

Here is a patch which fixes it, but it lacks a test:

diff --git a/vshard/storage/init.lua b/vshard/storage/init.lua
index 5f34410..e6d3ec0 100644
--- a/vshard/storage/init.lua
+++ b/vshard/storage/init.lua
@@ -1766,6 +1766,7 @@ local function bucket_recv(bucket_id, from, data, opts)
     M.rebalancer_transfering_buckets[bucket_id] = true
     local status, ret, err = pcall(bucket_recv_xc, bucket_id, from, data, opts)
     M.rebalancer_transfering_buckets[bucket_id] = nil
+    bucket_generation_increment()
     if status then
         if ret then
             return ret
@@ -1790,6 +1791,9 @@ local function bucket_test_gc(bids)
     local _bucket = box.space._bucket
     local ref, bucket, status
     for i, bid in ipairs(bids) do
+        if M.rebalancer_transfering_buckets[bid] then
+            goto not_ok_bid
+        end
         bucket = _bucket:get(bid)
         status = bucket ~= nil and bucket.status or consts.BUCKET.GARBAGE
         if status ~= consts.BUCKET.GARBAGE and status ~= consts.BUCKET.SENT then
@@ -2163,6 +2167,7 @@ local function bucket_send(bucket_id, destination, opts)
         exception_guard.ref.rw_lock = false
     end
     M.rebalancer_transfering_buckets[bucket_id] = nil
+    bucket_generation_increment()
     if status then
         if ret then
             return ret
@@ -2393,10 +2398,15 @@ local function gc_bucket_process_sent_xc()
     local batch = table.new(limit, 0)
     local i = 0
     local is_done = true
+    local ref
     for _, b in _bucket.index.status:pairs(consts.BUCKET.SENT) do
         i = i + 1
         local bid = b.id
-        local ref = M.bucket_refs[bid]
+        if M.rebalancer_transfering_buckets[bid] then
+            goto continue
+        end
+        ref = M.bucket_refs[bid]
         if ref ~= nil then
             assert(ref.rw == 0)
             if ref.ro ~= 0 then

Note that is_done = false is not needed in gc_bucket_process_sent_xc(). Bucket GC won't freeze, because bucket generation is updated when a bucket transfer ends.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingstorage

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions