Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RCBC-410: Support get all/any replicas in couchbase2 #127

Merged
merged 3 commits into from Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions lib/couchbase/protostellar/collection.rb
Expand Up @@ -132,12 +132,16 @@ def mutate_in(id, specs, options = Couchbase::Options::MutateIn::DEFAULT)
ResponseConverter::KV.to_mutate_in_result(resp, specs, options)
end

def get_any_replica(_id, _options = Couchbase::Options::GetAnyReplica::DEFAULT)
raise Couchbase::Error::FeatureNotAvailable, "The #{Protostellar::NAME} protocol does not support get any replica"
def get_any_replica(id, options = Couchbase::Options::GetAnyReplica::DEFAULT)
req = @kv_request_generator.get_any_replica_request(id, options)
resp = @client.send_request(req)
ResponseConverter::KV.to_get_any_replica_result(resp, options)
end

def get_all_replicas(_id, _options = Couchbase::Options::GetAllReplicas::DEFAULT)
raise Couchbase::Error::FeatureNotAvailable, "The #{Protostellar::NAME} protocol does not support get all replicas"
def get_all_replicas(id, options = Couchbase::Options::GetAllReplicas::DEFAULT)
req = @kv_request_generator.get_all_replicas_request(id, options)
resp = @client.send_request(req)
ResponseConverter::KV.to_get_all_replicas_result(resp, options)
end

def scan(_scan_type, _options = Options::Scan::DEFAULT)
Expand Down
14 changes: 14 additions & 0 deletions lib/couchbase/protostellar/request_generator/kv.rb
Expand Up @@ -341,6 +341,20 @@ def prepend_request(id, content, options)
create_kv_request(proto_req, :prepend, options)
end

def get_all_replicas_request(id, options)
proto_req = Generated::KV::V1::GetAllReplicasRequest.new(
key: id,
**location
)

create_kv_request(proto_req, :get_all_replicas, options, idempotent: true)
end

def get_any_replica_request(id, options)
# Uses the GetAllReplicas request and returns the first item from the result
get_all_replicas_request(id, options)
end

private

def create_kv_request(proto_request, rpc, options, idempotent: false)
Expand Down
27 changes: 27 additions & 0 deletions lib/couchbase/protostellar/response_converter/kv.rb
Expand Up @@ -75,6 +75,33 @@ def self.to_lookup_in_result(resp, specs, options, request)
end
end

def self.to_get_any_replica_result(resps, options)
begin
entry = resps.next
rescue StopIteration
raise Couchbase::Error::DocumentIrretrievable, "unable to get replica of the document"
end
Couchbase::Collection::GetReplicaResult.new do |res|
res.transcoder = options.transcoder
res.cas = entry.cas
res.flags = entry.content_flags
res.encoded = entry.content
res.is_replica = entry.is_replica
end
end

def self.to_get_all_replicas_result(resps, options)
resps.map do |entry|
Couchbase::Collection::GetReplicaResult.new do |res|
res.transcoder = options.transcoder
res.cas = entry.cas
res.flags = entry.content_flags
res.encoded = entry.content
res.is_replica = entry.is_replica
end
end
end

def self.to_mutate_in_result(resp, specs, options)
Couchbase::Collection::MutateInResult.new do |res|
res.cas = resp.cas
Expand Down
18 changes: 16 additions & 2 deletions test/crud_test.rb
Expand Up @@ -52,8 +52,6 @@ def test_removes_documents
end

def test_reads_from_replica
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support replica reads yet") if env.protostellar?

doc_id = uniq_id(:foo)
document = {"value" => 42}
options =
Expand All @@ -78,6 +76,22 @@ def test_reads_from_replica
end
end

def test_reads_from_replica_does_not_exist
doc_id = uniq_id(:foo)

assert_raises(Couchbase::Error::DocumentIrretrievable) do
@collection.get_any_replica(doc_id)
end

if env.protostellar?
assert_empty @collection.get_all_replicas(doc_id)
else
assert_raises(Couchbase::Error::DocumentNotFound) do
@collection.get_all_replicas(doc_id)
end
end
end

def test_touch_sets_expiration
document = {"value" => 42}
doc_id = uniq_id(:foo)
Expand Down