CouchDB レプリケーションにおける衝突を再現するスクリプト

CouchDB におけるレプリケーション。
衝突しているドキュメントを取得するまでを地道に試してみた。

やってみて分かったこと。
- push、pull レプリケーションタスクが完了するまで待つ、という処理を書かなければならない。

```
% # --------------------------- 
% # --------------------------- 
% # db の初期化。
% # --------------------------- 
% # --------------------------- 
% curl -X DELETE -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.57.2:5984/business_card
% # response ---> {"ok":true}
% # status ---> 200

% curl -X DELETE -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.58.2:5984/business_card
% # response ---> {"ok":true}
% # status ---> 200

% curl -X PUT -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.57.2:5984/business_card
% # response ---> {"ok":true}
% # status ---> 201

% curl -X PUT -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.58.2:5984/business_card
% # response ---> {"ok":true}
% # status ---> 201

% # --------------------------- 
% # --------------------------- 
% # ドキュメント bob を作成する。
% # --------------------------- 
% # --------------------------- 
% curl -X PUT -H 'Accept: application/json' -H 'Content-Type: application/json' -d {"number":"000-0000-0000","email":"bob@hoge.com"} http://192.168.57.2:5984/business_card/bob
% # response ---> {"ok":true,"id":"bob","rev":"1-67a3d3f4e49023faf4865a65fb2157ad"}
% # status ---> 201

% # --------------------------- 
% # --------------------------- 
% # bob をレプリケーションする。
% # --------------------------- 
% # --------------------------- 
% curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d {"source":"business_card","target":"http://192.168.58.2:5984/business_card","create_target":true} http://192.168.57.2:5984/_replicator
% # response ---> {"ok":true,"id":"e59d9a9247a97492e1ca9ae04801d971","rev":"1-5d0e76b1f0a1e4e0973c3e225d65b3be"}
% # status ---> 201

% curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d {"source":"http://192.168.58.2:5984/business_card","target":"business_card","create_target":true} http://192.168.57.2:5984/_replicator
% # response ---> {"ok":true,"id":"e59d9a9247a97492e1ca9ae04801e7b9","rev":"1-0d931d3c5e54ea24fefc380994a5f4d3"}
% # status ---> 201

% # --------------------------- 
% # --------------------------- 
% # 現在の状態を確認する。
% # --------------------------- 
% # --------------------------- 
% curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.57.2:5984/business_card/bob?a=b&c=d
{"_id":"bob","_rev":"1-67a3d3f4e49023faf4865a65fb2157ad","number":"000-0000-0000","email":"bob@hoge.com"}
% # status ---> 200

% # この時点で以下のようなリビジョンツリーである。
% # 
% # 192.168.57.2/business_card/bob
% # 1-67a3d3f4e49023faf4865a65fb2157ad
% # 
% # 192.168.58.2/business_card/bob
% # 1-67a3d3f4e49023faf4865a65fb2157ad
% # --------------------------- 
% # --------------------------- 
% # ドキュメント bob の v2a リビジョンを作成する。
% # --------------------------- 
% # --------------------------- 
% curl -X PUT -H 'Accept: application/json' -H 'Content-Type: application/json' -d {"_id":"bob","_rev":"1-67a3d3f4e49023faf4865a65fb2157ad","number":"111-1111-1111","email":"bob@hoge.com"} http://192.168.57.2:5984/business_card/bob
% # response ---> {"ok":true,"id":"bob","rev":"2-b941314df69d8fe88067373460759e59"}
% # status ---> 201

% # --------------------------- 
% # --------------------------- 
% # 現在の状態を確認する。
% # --------------------------- 
% # --------------------------- 
% curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.57.2:5984/business_card/bob?a=b&c=d
% # response ---> {"_id":"bob","_rev":"2-b941314df69d8fe88067373460759e59","number":"111-1111-1111","email":"bob@hoge.com"}
% # status ---> 200

% # --------------------------- 
% # --------------------------- 
% # ドキュメント bob の v2b リビジョンを作成する。
% # --------------------------- 
% # --------------------------- 
% curl -X PUT -H 'Accept: application/json' -H 'Content-Type: application/json' -d {"_id":"bob","_rev":"1-67a3d3f4e49023faf4865a65fb2157ad","number":"000-0000-0000","email":"bob@fuga.com"} http://192.168.58.2:5984/business_card/bob
% # response ---> {"ok":true,"id":"bob","rev":"2-3b416dfe57b51349bdacbc654efcfadc"}
% # status ---> 201

% # --------------------------- 
% # --------------------------- 
% # 現在の状態を確認する。
% # --------------------------- 
% # --------------------------- 
% curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.58.2:5984/business_card/bob?a=b&c=d
% # response ---> {"_id":"bob","_rev":"2-3b416dfe57b51349bdacbc654efcfadc","number":"000-0000-0000","email":"bob@fuga.com"}
% # status ---> 200

% # この時点で以下のようなリビジョンツリーである。
% # 
% # 192.168.57.2/business_card/bob
% # 1-67a3d3f4e49023faf4865a65fb2157ad --- 2-b941314df69d8fe88067373460759e59
% # 
% # 192.168.58.2/business_card/bob
% # 1-67a3d3f4e49023faf4865a65fb2157ad --- 2-3b416dfe57b51349bdacbc654efcfadc
% # --------------------------- 
% # --------------------------- 
% # 以下のレプリケーション処理において衝突が発生する。
% # --------------------------- 
% # --------------------------- 
% curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d {"source":"business_card","target":"http://192.168.58.2:5984/business_card","create_target":true} http://192.168.57.2:5984/_replicator
% # response ---> {"ok":true,"id":"e59d9a9247a97492e1ca9ae04801f1fd","rev":"1-5d0e76b1f0a1e4e0973c3e225d65b3be"}
% # status ---> 201

% curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d {"source":"http://192.168.58.2:5984/business_card","target":"business_card","create_target":true} http://192.168.57.2:5984/_replicator
% # response ---> {"ok":true,"id":"e59d9a9247a97492e1ca9ae04801fad3","rev":"1-0d931d3c5e54ea24fefc380994a5f4d3"}
% # status ---> 201

% # --------------------------- 
% # --------------------------- 
% # 衝突しているリビジョン情報を含めて、ドキュメントを取得する。
% # --------------------------- 
% # --------------------------- 
% curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.57.2:5984/business_card/bob?conflicts=true
% # response ---> {"_id":"bob","_rev":"2-b941314df69d8fe88067373460759e59","number":"111-1111-1111","email":"bob@hoge.com"}
% # status ---> 200

% # 衝突が発生したとしても、ドキュメントの最新版は、CouchDB 内の決定的なアルゴリズムにより一意に定まる。
% # 最新版(winner)はこちら:2-b941314df69d8fe88067373460759e59
% # しかし、実際には 最新版(winner) ではない、隠されたリビジョン(losers)が存在する。
% # 隠されたリビジョン(losers)が存在する。
% # 隠されたリビジョン(losers)はこちら:undefined
% # --------------------------- 
% # --------------------------- 
% # もうかたほうのインスタンスでもまったく同じ結果となる。 
% # --------------------------- 
% # --------------------------- 
% curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.58.2:5984/business_card/bob?conflicts=true
% # response ---> {"_id":"bob","_rev":"2-b941314df69d8fe88067373460759e59","number":"111-1111-1111","email":"bob@hoge.com","_conflicts":["2-3b416dfe57b51349bdacbc654efcfadc"]}
% # status ---> 200

% # 最新版(winner)はこちら:2-b941314df69d8fe88067373460759e59
% # 隠されたリビジョン(losers)はこちら:["2-3b416dfe57b51349bdacbc654efcfadc"]
% # この時点で以下のようなリビジョンツリーである。
% # 
% # 192.168.57.2/business_cardbob
% # 1-67a3d3f4e49023faf4865a65fb2157ad -+- 2-b941314df69d8fe88067373460759e59
% #                                     |  
% #                                     +- 2-3b416dfe57b51349bdacbc654efcfadc
% # 
% # 192.168.58.2/business_cardbob
% # 1-67a3d3f4e49023faf4865a65fb2157ad -+- 2-b941314df69d8fe88067373460759e59
% #                                     |  
% #                                     +- 2-3b416dfe57b51349bdacbc654efcfadc
% # 
% # --------------------------- 
% # --------------------------- 
% # リビジョンツリーの葉ノードだけを取得することができる。
% # --------------------------- 
% # --------------------------- 
% # open_revs オプションは、他のオプションと併用できない。
% curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.57.2:5984/business_card/bob?open_revs=all
% # response ---> [{"ok":{"_id":"bob","_rev":"2-b941314df69d8fe88067373460759e59","number":"111-1111-1111","email":"bob@hoge.com"}}]
% # status ---> 200

% curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' http://192.168.58.2:5984/business_card/bob?open_revs=all
% # response ---> [{"ok":{"_id":"bob","_rev":"2-3b416dfe57b51349bdacbc654efcfadc","number":"000-0000-0000","email":"bob@fuga.com"}},{"ok":{"_id":"bob","_rev":"2-b941314df69d8fe88067373460759e59","number":"111-1111-1111","email":"bob@hoge.com"}}]
% # status ---> 200
```