diff --git a/integration/integration_test.go b/integration/integration_test.go index 9c2598c..4e41fcd 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -271,14 +271,20 @@ func TestSync(t *testing.T) { func TestExists(t *testing.T) { runTest(t, func(t *testing.T, c *zk.Conn) { + if ok, _, err := c.Exists("/"); err != nil || !ok { + t.Errorf("expected /, got err=%v, ok=%v", err, ok) + } if _, err := c.Create("/abc", []byte(""), 0, acl); err != nil { t.Fatal(err) } + if ok, _, err := c.Exists("/"); err != nil || !ok { + t.Errorf("expected /, got err=%v, ok=%v", err, ok) + } if ok, _, err := c.Exists("/abc"); err != nil || !ok { - t.Fatalf("expected it to exist %v %v", err, ok) + t.Errorf("expected it to exist %v %v", err, ok) } if ok, _, err := c.Exists("/ab"); ok { - t.Fatalf("expected it to not exist %v %v", err, ok) + t.Errorf("expected it to not exist %v %v", err, ok) } }) } diff --git a/stat.go b/stat.go index c353cde..d54e9a7 100644 --- a/stat.go +++ b/stat.go @@ -33,7 +33,7 @@ func statGetsRev(p string, rev int64) []etcd.Op { func statGets(p string) []etcd.Op { return statGetsRev(p, 0) } -func statTxn(txnresp *etcd.TxnResponse) (s Stat) { +func statTxn(p string, txnresp *etcd.TxnResponse) (s Stat, err error) { ctime := txnresp.Responses[0].GetResponseRange() mtime := txnresp.Responses[1].GetResponseRange() node := txnresp.Responses[2].GetResponseRange() @@ -64,5 +64,21 @@ func statTxn(txnresp *etcd.TxnResponse) (s Stat) { s.DataLength = int32(len(node.Kvs[0].Value)) } s.NumChildren = int32(len(children.Kvs)) - return s + + if p != "/" { + if s.Ctime == 0 { + return s, ErrNoNode + } + return s, nil + } + + // fix ups for special root node + + // lie about having the quota dir so stat on "/" xchks OK + s.NumChildren++ + // Cversion for root begins at -1, then 0 on first child + if len(cver.Kvs) == 0 { + s.Cversion = -1 + } + return s, nil } diff --git a/zketcd.go b/zketcd.go index 4577fe4..7fcc113 100644 --- a/zketcd.go +++ b/zketcd.go @@ -140,9 +140,8 @@ func (z *zkEtcd) GetChildren2(xid Xid, op *GetChildren2Request) ZKResponse { return mkErr(err) } - resp.Stat = statTxn(txnresp) - if op.Path != "/" && resp.Stat.Ctime == 0 { - return mkZKErr(xid, ZXid(txnresp.Header.Revision), errNoNode) + if resp.Stat, err = statTxn(op.Path, txnresp); err != nil { + return apiErrToZKErr(xid, ZXid(txnresp.Header.Revision), err) } children := txnresp.Responses[5].GetResponseRange() @@ -258,7 +257,7 @@ func (z *zkEtcd) Exists(xid Xid, op *ExistsRequest) ZKResponse { } exResp := &ExistsResponse{} - exResp.Stat = statTxn(txnresp) + exResp.Stat, err = statTxn(op.Path, txnresp) zxid := ZXid(txnresp.Header.Revision) z.s.Wait(exResp.Stat.Czxid, p, EventNodeCreated) @@ -279,8 +278,8 @@ func (z *zkEtcd) Exists(xid Xid, op *ExistsRequest) ZKResponse { z.s.Watch(zxid, xid, p, ev, f) } - if exResp.Stat.Mtime == 0 { - return mkZKErr(xid, zxid, errNoNode) + if err != nil { + return apiErrToZKErr(xid, zxid, err) } glog.V(7).Infof("Exists(%v) = (zxid=%v, resp=%+v)", xid, zxid, *exResp) @@ -298,9 +297,8 @@ func (z *zkEtcd) GetData(xid Xid, op *GetDataRequest) ZKResponse { zxid := ZXid(txnresp.Header.Revision) datResp := &GetDataResponse{} - datResp.Stat = statTxn(txnresp) - if datResp.Stat.Mtime == 0 { - return mkZKErr(xid, zxid, errNoNode) + if datResp.Stat, err = statTxn(op.Path, txnresp); err != nil { + return apiErrToZKErr(xid, zxid, err) } z.s.Wait(datResp.Stat.Mzxid, p, EventNodeDataChanged) @@ -362,7 +360,8 @@ func (z *zkEtcd) mkSetDataTxnOp(op *SetDataRequest) opBundle { glog.Warningf("set data failed (%v)", err) return mkZKErr(xid, zxid, errSystemError) } - return mkZKResp(xid, zxid, &SetDataResponse{Stat: statTxn(statResp)}) + st, _ := statTxn(op.Path, statResp) + return mkZKResp(xid, zxid, &SetDataResponse{Stat: st}) } return opBundle{apply, reply} @@ -382,9 +381,8 @@ func (z *zkEtcd) GetAcl(xid Xid, op *GetAclRequest) ZKResponse { zxid := ZXid(txnresp.Header.Revision) resps := txnresp.Responses txnresp.Responses = resps[1:] - resp.Stat = statTxn(txnresp) - if resp.Stat.Ctime == 0 { - return mkZKErr(xid, zxid, errNoNode) + if resp.Stat, err = statTxn(op.Path, txnresp); err != nil { + return apiErrToZKErr(xid, zxid, err) } resp.Acl = decodeACLs(resps[0].GetResponseRange().Kvs[0].Value) @@ -410,9 +408,8 @@ func (z *zkEtcd) GetChildren(xid Xid, op *GetChildrenRequest) ZKResponse { return mkErr(err) } - s := statTxn(txnresp) - if op.Path != "/" && s.Ctime == 0 { - return mkZKErr(xid, ZXid(txnresp.Header.Revision), errNoNode) + if _, err := statTxn(op.Path, txnresp); err != nil { + return apiErrToZKErr(xid, ZXid(txnresp.Header.Revision), err) } children := txnresp.Responses[5].GetResponseRange()