Saturday, March 27, 2010

Catching Up

‹prev | My Chain | next›

Having messed around with node.js and CouchDB replication a bit, I head back to the comfortable lands of Ruby to touch up a gem or two. One of the things that I learned in my exploration what that, although it can go either way, CouchDB optimizes pull replication. That is, when posting to the replication resource on a CouchDB server, the replication will perform better if the target DB is on the same server (and the source is on another server).

When I wrote the couch-replicate gem, I had not know there was a difference. I got the 50-50 chance wrong. So first up, an RSpec example:
  it "should default to local target (pull) replicate" do
RestClient.
should_receive(:post).
with("#{@target_host}/_replicate",
%Q|{"source":"#{@src_host}/#{@db}", "target":"#{@db}", "continuous":true}|)

CouchReplicate.replicate(@src_host, @target_host, @db)
end
That fails with:
cstrom@whitefall:~/repos/couch-replicate$ spec ./spec/couch_replicate_spec.rb 
F..........

1)
Spec::Mocks::MockExpectationError in 'CouchReplicate should default to local target (pull) replicate'
RestClient received :post with unexpected arguments
expected: ("http://couch02.example.org:5984/_replicate", "{\"source\":\"http://couch01.example.org:5984/test\", \"target\":\"test\", \"continuous\":true}")
got: ("http://couch01.example.org:5984/_replicate", "{\"source\":\"test\", \"target\":\"http://couch02.example.org:5984/test\", \"continuous\":true}")
./spec/couch_replicate_spec.rb:16:

Finished in 0.060957 seconds

11 examples, 1 failure
Yup, got it exactly wrong. To fix, I update the CouchReplicate.replicate method:
  def self.replicate(source_host, target_host, db)
source = hostify(source_host)
target = hostify(target_host)
RestClient.post("#{target}/_replicate",
%Q|{"source":"#{source}/#{db}", "target":"#{db}", "continuous":true}|)
end
I have to update a few specs, but now have couch-replicate "doing it right". I have a few things I'd like to do in couch_docs, but I will stick to couch-replicate tonight. Specifically, I like the create_target attribute. I am not sure if that is a replicate-or-create-then-replicate option.

To find out I edit a document on a previously replicated server:



Then, I add create_target to the couch-replicate gem:
  def self.replicate(source_host, target_host, db)
source = hostify(source_host)
target = hostify(target_host)
RestClient.post("#{target}/_replicate",
%Q|{"source":"#{source}/#{db}", "target":"#{db}", "continuous":true, "create_target":true}|)
end
Finally, I set replication in motion:
cstrom@whitefall:~/repos/couch-replicate$ couch-replicate test couch-011a.local couch-011b.local couch-011c.local
Linking replication hosts...
If CouchDB replicate-with-create_target is non-destructive, then the document on server B will not be overwritten and will make it onto server A. That is exactly what happens:



Since this is undocumented, I will not include that in couch-replicate for the time being. I do release 0.0.3 of the gem with the default pull replication.

Day #55

No comments:

Post a Comment