// snapshot reads all of a watcher; returns compaction revision if incomplete // TODO: stabilize snapshot format func snapshot(w io.Writer, c *clientv3.Client, rev int64) int64 { s := sync.NewSyncer(c, "", rev) rc, errc := s.SyncBase(context.TODO()) for r := range rc { for _, kv := range r.Kvs { fmt.Fprintln(w, kv) } } err := <-errc if err != nil { if err == v3rpc.ErrCompacted { // will get correct compact revision on retry return rev + 1 } // failed for some unknown reason, retry on same revision return rev } wc := s.SyncUpdates(context.TODO()) for wr := range wc { if len(wr.Events) == 0 { return wr.CompactRevision } for _, ev := range wr.Events { fmt.Fprintln(w, ev) } rev := wr.Events[len(wr.Events)-1].Kv.ModRevision if rev >= wr.Header.Revision { break } } return 0 }
func makeMirror(ctx context.Context, c *clientv3.Client, dc *clientv3.Client) error { // TODO: remove the prefix of the destination cluster? dkv := clientv3.NewKV(dc) s := sync.NewSyncer(c, mmprefix, 0) rc, errc := s.SyncBase(ctx) for r := range rc { for _, kv := range r.Kvs { _, err := dkv.Put(ctx, string(kv.Key), string(kv.Value)) if err != nil { return err } } } err := <-errc if err != nil { return err } wc := s.SyncUpdates(ctx) for wr := range wc { if wr.CompactRevision != 0 { return v3rpc.ErrCompacted } var rev int64 ops := []clientv3.Op{} for _, ev := range wr.Events { nrev := ev.Kv.ModRevision if rev != 0 && nrev > rev { _, err := dkv.Txn(ctx).Then(ops...).Commit() if err != nil { return err } ops = []clientv3.Op{} } switch ev.Type { case storagepb.PUT: ops = append(ops, clientv3.OpPut(string(ev.Kv.Key), string(ev.Kv.Value))) case storagepb.DELETE, storagepb.EXPIRE: ops = append(ops, clientv3.OpDelete(string(ev.Kv.Key))) default: panic("unexpected event type") } } if len(ops) != 0 { _, err := dkv.Txn(ctx).Then(ops...).Commit() if err != nil { return err } } } return nil }