{"action":"created","comment":{"url":"https://api.github.com/repos/coreos/etcd/pulls/comments/51198384","id":51198384,"diff_hunk":"@@ -183,3 +185,96 @@ func (kv *kv) do(op Op) (*pb.ResponseUnion, error) {\n \t\tkv.remote = pb.NewKVClient(kv.conn)\n \t}\n }\n+\n+type txn struct {\n+\tkv *kv\n+\n+\tmu    sync.Mutex\n+\tcif   bool\n+\tcthen bool\n+\tcelse bool\n+\n+\tcmps []*pb.Compare\n+\n+\tsus []*pb.RequestUnion\n+\tfas []*pb.RequestUnion\n+}\n+\n+func (txn *txn) If(cs ...Cmp) *txn {\n+\ttxn.mu.Lock()\n+\tdefer txn.mu.Unlock()\n+\n+\tif txn.cif {\n+\t\tpanic(\"cannot call If twice!\")\n+\t}\n+\n+\tif txn.cthen {\n+\t\tpanic(\"cannot call If after Then!\")\n+\t}\n+\n+\tif txn.celse {\n+\t\tpanic(\"cannot call If after Else!\")\n+\t}\n+\n+\tfor _, cmp := range cs {\n+\t\ttxn.cmps = append(txn.cmps, (*pb.Compare)(&cmp))\n+\t}\n+\n+\treturn txn\n+}\n+\n+func (txn *txn) Then(ops ...Op) *txn {\n+\ttxn.mu.Lock()\n+\tdefer txn.mu.Unlock()\n+\n+\tif txn.cif {\n+\t\tpanic(\"cannot call Then twice!\")\n+\t}\n+\tif txn.celse {\n+\t\tpanic(\"cannot call Then after Else!\")\n+\t}\n+\n+\ttxn.cthen = true\n+\n+\tfor _, op := range ops {\n+\t\ttxn.sus = append(txn.sus, op.toRequestUnion())\n+\t}\n+\n+\treturn txn\n+}\n+\n+func (txn *txn) Else(ops ...Op) *txn {\n+\ttxn.mu.Lock()\n+\tdefer txn.mu.Unlock()\n+\n+\tif txn.celse {\n+\t\tpanic(\"cannot call Else twice!\")\n+\t}\n+\n+\ttxn.celse = true\n+\n+\tfor _, op := range ops {\n+\t\ttxn.fas = append(txn.fas, op.toRequestUnion())\n+\t}\n+\n+\treturn txn\n+}\n+\n+func (txn *txn) Commit() (*TxnResponse, error) {\n+\tkv := txn.kv\n+\tfor {\n+\t\tr := &pb.TxnRequest{Compare: txn.cmps, Success: txn.sus, Failure: txn.fas}\n+\t\tresp, err := kv.remote.Txn(context.TODO(), r)\n+\t\tif err == nil {\n+\t\t\treturn (*TxnResponse)(resp), nil\n+\t\t}\n+\n+\t\tnewConn, cerr := kv.c.retryConnection(kv.conn, err)\n+\t\tif cerr != nil {\n+\t\t\t// TODO: return client lib defined connection error\n+\t\t\treturn nil, cerr\n+\t\t}\n+\t\tkv.conn = newConn","path":"clientv3/kv.go","position":null,"original_position":122,"commit_id":"92653dcbfbf33691d998537d02737d0bf5d80e0e","original_commit_id":"115f421ef4eeda43b1cb5835806790daef7b4130","user":{"login":"xiang90","id":4479947,"avatar_url":"https://avatars.githubusercontent.com/u/4479947?v=3","gravatar_id":"","url":"https://api.github.com/users/xiang90","html_url":"https://github.com/xiang90","followers_url":"https://api.github.com/users/xiang90/followers","following_url":"https://api.github.com/users/xiang90/following{/other_user}","gists_url":"https://api.github.com/users/xiang90/gists{/gist_id}","starred_url":"https://api.github.com/users/xiang90/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xiang90/subscriptions","organizations_url":"https://api.github.com/users/xiang90/orgs","repos_url":"https://api.github.com/users/xiang90/repos","events_url":"https://api.github.com/users/xiang90/events{/privacy}","received_events_url":"https://api.github.com/users/xiang90/received_events","type":"User","site_admin":false},"body":"added.","created_at":"2016-01-28T22:28:04Z","updated_at":"2016-01-28T22:28:04Z","html_url":"https://github.com/coreos/etcd/pull/4329#discussion_r51198384","pull_request_url":"https://api.github.com/repos/coreos/etcd/pulls/4329","_links":{"self":{"href":"https://api.github.com/repos/coreos/etcd/pulls/comments/51198384"},"html":{"href":"https://github.com/coreos/etcd/pull/4329#discussion_r51198384"},"pull_request":{"href":"https://api.github.com/repos/coreos/etcd/pulls/4329"}}},"pull_request":{"url":"https://api.github.com/repos/coreos/etcd/pulls/4329","id":57572820,"html_url":"https://github.com/coreos/etcd/pull/4329","diff_url":"https://github.com/coreos/etcd/pull/4329.diff","patch_url":"https://github.com/coreos/etcd/pull/4329.patch","issue_url":"https://api.github.com/repos/coreos/etcd/issues/4329","number":4329,"state":"open","locked":false,"title":"clientv3: initial txn","user":{"login":"xiang90","id":4479947,"avatar_url":"https://avatars.githubusercontent.com/u/4479947?v=3","gravatar_id":"","url":"https://api.github.com/users/xiang90","html_url":"https://github.com/xiang90","followers_url":"https://api.github.com/users/xiang90/followers","following_url":"https://api.github.com/users/xiang90/following{/other_user}","gists_url":"https://api.github.com/users/xiang90/gists{/gist_id}","starred_url":"https://api.github.com/users/xiang90/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xiang90/subscriptions","organizations_url":"https://api.github.com/users/xiang90/orgs","repos_url":"https://api.github.com/users/xiang90/repos","events_url":"https://api.github.com/users/xiang90/events{/privacy}","received_events_url":"https://api.github.com/users/xiang90/received_events","type":"User","site_admin":false},"body":"/cc @heyitsanthony @gyuho @barakmich @mitake ","created_at":"2016-01-28T21:58:38Z","updated_at":"2016-01-28T22:28:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"932c02db37d1b8ff5c1e8b80bcddd089224bfa2c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/coreos/etcd/pulls/4329/commits","review_comments_url":"https://api.github.com/repos/coreos/etcd/pulls/4329/comments","review_comment_url":"https://api.github.com/repos/coreos/etcd/pulls/comments{/number}","comments_url":"https://api.github.com/repos/coreos/etcd/issues/4329/comments","statuses_url":"https://api.github.com/repos/coreos/etcd/statuses/92653dcbfbf33691d998537d02737d0bf5d80e0e","head":{"label":"xiang90:client_txn","ref":"client_txn","sha":"92653dcbfbf33691d998537d02737d0bf5d80e0e","user":{"login":"xiang90","id":4479947,"avatar_url":"https://avatars.githubusercontent.com/u/4479947?v=3","gravatar_id":"","url":"https://api.github.com/users/xiang90","html_url":"https://github.com/xiang90","followers_url":"https://api.github.com/users/xiang90/followers","following_url":"https://api.github.com/users/xiang90/following{/other_user}","gists_url":"https://api.github.com/users/xiang90/gists{/gist_id}","starred_url":"https://api.github.com/users/xiang90/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xiang90/subscriptions","organizations_url":"https://api.github.com/users/xiang90/orgs","repos_url":"https://api.github.com/users/xiang90/repos","events_url":"https://api.github.com/users/xiang90/events{/privacy}","received_events_url":"https://api.github.com/users/xiang90/received_events","type":"User","site_admin":false},"repo":{"id":11245678,"name":"etcd","full_name":"xiang90/etcd","owner":{"login":"xiang90","id":4479947,"avatar_url":"https://avatars.githubusercontent.com/u/4479947?v=3","gravatar_id":"","url":"https://api.github.com/users/xiang90","html_url":"https://github.com/xiang90","followers_url":"https://api.github.com/users/xiang90/followers","following_url":"https://api.github.com/users/xiang90/following{/other_user}","gists_url":"https://api.github.com/users/xiang90/gists{/gist_id}","starred_url":"https://api.github.com/users/xiang90/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xiang90/subscriptions","organizations_url":"https://api.github.com/users/xiang90/orgs","repos_url":"https://api.github.com/users/xiang90/repos","events_url":"https://api.github.com/users/xiang90/events{/privacy}","received_events_url":"https://api.github.com/users/xiang90/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/xiang90/etcd","description":null,"fork":true,"url":"https://api.github.com/repos/xiang90/etcd","forks_url":"https://api.github.com/repos/xiang90/etcd/forks","keys_url":"https://api.github.com/repos/xiang90/etcd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/xiang90/etcd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/xiang90/etcd/teams","hooks_url":"https://api.github.com/repos/xiang90/etcd/hooks","issue_events_url":"https://api.github.com/repos/xiang90/etcd/issues/events{/number}","events_url":"https://api.github.com/repos/xiang90/etcd/events","assignees_url":"https://api.github.com/repos/xiang90/etcd/assignees{/user}","branches_url":"https://api.github.com/repos/xiang90/etcd/branches{/branch}","tags_url":"https://api.github.com/repos/xiang90/etcd/tags","blobs_url":"https://api.github.com/repos/xiang90/etcd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/xiang90/etcd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/xiang90/etcd/git/refs{/sha}","trees_url":"https://api.github.com/repos/xiang90/etcd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/xiang90/etcd/statuses/{sha}","languages_url":"https://api.github.com/repos/xiang90/etcd/languages","stargazers_url":"https://api.github.com/repos/xiang90/etcd/stargazers","contributors_url":"https://api.github.com/repos/xiang90/etcd/contributors","subscribers_url":"https://api.github.com/repos/xiang90/etcd/subscribers","subscription_url":"https://api.github.com/repos/xiang90/etcd/subscription","commits_url":"https://api.github.com/repos/xiang90/etcd/commits{/sha}","git_commits_url":"https://api.github.com/repos/xiang90/etcd/git/commits{/sha}","comments_url":"https://api.github.com/repos/xiang90/etcd/comments{/number}","issue_comment_url":"https://api.github.com/repos/xiang90/etcd/issues/comments{/number}","contents_url":"https://api.github.com/repos/xiang90/etcd/contents/{+path}","compare_url":"https://api.github.com/repos/xiang90/etcd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/xiang90/etcd/merges","archive_url":"https://api.github.com/repos/xiang90/etcd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/xiang90/etcd/downloads","issues_url":"https://api.github.com/repos/xiang90/etcd/issues{/number}","pulls_url":"https://api.github.com/repos/xiang90/etcd/pulls{/number}","milestones_url":"https://api.github.com/repos/xiang90/etcd/milestones{/number}","notifications_url":"https://api.github.com/repos/xiang90/etcd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/xiang90/etcd/labels{/name}","releases_url":"https://api.github.com/repos/xiang90/etcd/releases{/id}","deployments_url":"https://api.github.com/repos/xiang90/etcd/deployments","created_at":"2013-07-08T04:17:14Z","updated_at":"2015-06-09T18:06:32Z","pushed_at":"2016-01-28T22:27:52Z","git_url":"git://github.com/xiang90/etcd.git","ssh_url":"git@github.com:xiang90/etcd.git","clone_url":"https://github.com/xiang90/etcd.git","svn_url":"https://github.com/xiang90/etcd","homepage":null,"size":20485,"stargazers_count":3,"watchers_count":3,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":3,"default_branch":"master"}},"base":{"label":"coreos:master","ref":"master","sha":"9842a3b84a11aa0485f845130a1e4fefbb04812d","user":{"login":"coreos","id":3730757,"avatar_url":"https://avatars.githubusercontent.com/u/3730757?v=3","gravatar_id":"","url":"https://api.github.com/users/coreos","html_url":"https://github.com/coreos","followers_url":"https://api.github.com/users/coreos/followers","following_url":"https://api.github.com/users/coreos/following{/other_user}","gists_url":"https://api.github.com/users/coreos/gists{/gist_id}","starred_url":"https://api.github.com/users/coreos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coreos/subscriptions","organizations_url":"https://api.github.com/users/coreos/orgs","repos_url":"https://api.github.com/users/coreos/repos","events_url":"https://api.github.com/users/coreos/events{/privacy}","received_events_url":"https://api.github.com/users/coreos/received_events","type":"Organization","site_admin":false},"repo":{"id":11225014,"name":"etcd","full_name":"coreos/etcd","owner":{"login":"coreos","id":3730757,"avatar_url":"https://avatars.githubusercontent.com/u/3730757?v=3","gravatar_id":"","url":"https://api.github.com/users/coreos","html_url":"https://github.com/coreos","followers_url":"https://api.github.com/users/coreos/followers","following_url":"https://api.github.com/users/coreos/following{/other_user}","gists_url":"https://api.github.com/users/coreos/gists{/gist_id}","starred_url":"https://api.github.com/users/coreos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coreos/subscriptions","organizations_url":"https://api.github.com/users/coreos/orgs","repos_url":"https://api.github.com/users/coreos/repos","events_url":"https://api.github.com/users/coreos/events{/privacy}","received_events_url":"https://api.github.com/users/coreos/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/coreos/etcd","description":"Distributed reliable key-value store for the most critical data of a distributed system","fork":false,"url":"https://api.github.com/repos/coreos/etcd","forks_url":"https://api.github.com/repos/coreos/etcd/forks","keys_url":"https://api.github.com/repos/coreos/etcd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/coreos/etcd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/coreos/etcd/teams","hooks_url":"https://api.github.com/repos/coreos/etcd/hooks","issue_events_url":"https://api.github.com/repos/coreos/etcd/issues/events{/number}","events_url":"https://api.github.com/repos/coreos/etcd/events","assignees_url":"https://api.github.com/repos/coreos/etcd/assignees{/user}","branches_url":"https://api.github.com/repos/coreos/etcd/branches{/branch}","tags_url":"https://api.github.com/repos/coreos/etcd/tags","blobs_url":"https://api.github.com/repos/coreos/etcd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/coreos/etcd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/coreos/etcd/git/refs{/sha}","trees_url":"https://api.github.com/repos/coreos/etcd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/coreos/etcd/statuses/{sha}","languages_url":"https://api.github.com/repos/coreos/etcd/languages","stargazers_url":"https://api.github.com/repos/coreos/etcd/stargazers","contributors_url":"https://api.github.com/repos/coreos/etcd/contributors","subscribers_url":"https://api.github.com/repos/coreos/etcd/subscribers","subscription_url":"https://api.github.com/repos/coreos/etcd/subscription","commits_url":"https://api.github.com/repos/coreos/etcd/commits{/sha}","git_commits_url":"https://api.github.com/repos/coreos/etcd/git/commits{/sha}","comments_url":"https://api.github.com/repos/coreos/etcd/comments{/number}","issue_comment_url":"https://api.github.com/repos/coreos/etcd/issues/comments{/number}","contents_url":"https://api.github.com/repos/coreos/etcd/contents/{+path}","compare_url":"https://api.github.com/repos/coreos/etcd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/coreos/etcd/merges","archive_url":"https://api.github.com/repos/coreos/etcd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/coreos/etcd/downloads","issues_url":"https://api.github.com/repos/coreos/etcd/issues{/number}","pulls_url":"https://api.github.com/repos/coreos/etcd/pulls{/number}","milestones_url":"https://api.github.com/repos/coreos/etcd/milestones{/number}","notifications_url":"https://api.github.com/repos/coreos/etcd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/coreos/etcd/labels{/name}","releases_url":"https://api.github.com/repos/coreos/etcd/releases{/id}","deployments_url":"https://api.github.com/repos/coreos/etcd/deployments","created_at":"2013-07-06T21:57:21Z","updated_at":"2016-01-28T20:10:53Z","pushed_at":"2016-01-28T22:27:53Z","git_url":"git://github.com/coreos/etcd.git","ssh_url":"git@github.com:coreos/etcd.git","clone_url":"https://github.com/coreos/etcd.git","svn_url":"https://github.com/coreos/etcd","homepage":"https://coreos.com/etcd/docs/latest/","size":23268,"stargazers_count":8584,"watchers_count":8584,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1387,"mirror_url":null,"open_issues_count":156,"forks":1387,"open_issues":156,"watchers":8584,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/coreos/etcd/pulls/4329"},"html":{"href":"https://github.com/coreos/etcd/pull/4329"},"issue":{"href":"https://api.github.com/repos/coreos/etcd/issues/4329"},"comments":{"href":"https://api.github.com/repos/coreos/etcd/issues/4329/comments"},"review_comments":{"href":"https://api.github.com/repos/coreos/etcd/pulls/4329/comments"},"review_comment":{"href":"https://api.github.com/repos/coreos/etcd/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/coreos/etcd/pulls/4329/commits"},"statuses":{"href":"https://api.github.com/repos/coreos/etcd/statuses/92653dcbfbf33691d998537d02737d0bf5d80e0e"}}}}