syncbase/vsync: SyncGroup and DAG changes for SG syncing

* Change SyncGroup storage to support their versioning and being tracked
  in DAG and log records.
* Update the SyncGroup join & publish calls to support the asynchronous
  transition from known-but-pending SyncGroup to caught-up after sync.
* Add a SyncGroup local state info to track the number of local peer
  joiners, and the watchability, remote publishing, and sync pending
  states of the SyncGroup.
* Add the retry loop for the SyncGroup publishing to the remote peer.
* Improve error checking of SyncGroup prefixes passed in the Spec.
* Add a 1st-cut HasKey() store util API to bypass the VOM decode.  This
  will be later further optimized for leveldb to avoid a copy of the
  value from the C buffer to the Go buffer.
* Add DAG support to fully prune all nodes for an object including its
  current head node.
* Remove temporay solution of the responder adding the initiator to the
  SyncGroup joiner list.
* Improve unittest coverage.

Change-Id: I4585e248bd9e15b8b9585ec7b1830f8225686b2a
diff --git a/services/syncbase/server/watchable/transaction.go b/services/syncbase/server/watchable/transaction.go
index 22b53f4..3178cb7 100644
--- a/services/syncbase/server/watchable/transaction.go
+++ b/services/syncbase/server/watchable/transaction.go
@@ -8,6 +8,7 @@
 	"fmt"
 	"math"
 	"sync"
+	"time"
 
 	"v.io/v23/context"
 	"v.io/v23/verror"
@@ -173,6 +174,12 @@
 	return tx.itx.Abort()
 }
 
+// GetStoreTime returns the current time from the given transaction store.
+func GetStoreTime(ctx *context.T, tx store.Transaction) time.Time {
+	wtx := tx.(*transaction)
+	return wtx.st.clock.Now(ctx)
+}
+
 // AddSyncGroupOp injects a SyncGroup operation notification in the log entries
 // that the transaction writes when it is committed.  It allows the SyncGroup
 // operations (create, join, leave, destroy) to notify the sync watcher of the