// UpdateEndPoints is part of the topo.Server interface func (zkts *Server) UpdateEndPoints(ctx context.Context, cell, keyspace, shard string, tabletType topodatapb.TabletType, addrs *topodatapb.EndPoints, existingVersion int64) error { path := zkPathForVtName(cell, keyspace, shard, tabletType) data, err := json.MarshalIndent(addrs, "", " ") if err != nil { return err } if existingVersion == -1 { // Update or create unconditionally. _, err := zk.CreateRecursive(zkts.zconn, path, string(data), 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { // Node already exists - just stomp away. Multiple writers shouldn't be here. // We use RetryChange here because it won't update the node unnecessarily. f := func(oldValue string, oldStat zk.Stat) (string, error) { return string(data), nil } err = zkts.zconn.RetryChange(path, 0, zookeeper.WorldACL(zookeeper.PERM_ALL), f) } } return err } // Compare And Set if _, err = zkts.zconn.Set(path, string(data), int(existingVersion)); err != nil { if zookeeper.IsError(err, zookeeper.ZBADVERSION) { err = topo.ErrBadVersion } else if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } } return err }
// Create implements Conn. func (conn *MetaConn) Create(path, value string, flags int, aclv []zookeeper.ACL) (pathCreated string, err error) { var zconn Conn for i := 0; i < maxAttempts; i++ { zconn, err = conn.connCache.ConnForPath(path) if err != nil { return } path = resolveZkPath(path) pathCreated, err = zconn.Create(path, value, flags, aclv) if err != nil && zookeeper.IsError(err, zookeeper.ZNONODE) { parts := strings.Split(path, "/") if len(parts) == 3 && parts[0] == "" && parts[1] == MagicPrefix { // We were asked to create a /zk/<cell> path, but /zk doesn't exist. // We should create /zk automatically in this case, because it's // impossible to create /zk via MetaConn, since there's no cell name. _, err = zconn.Create("/"+MagicPrefix, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if shouldRetry(err) { continue } if !zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { return "", err } } // Now try the original path again. pathCreated, err = zconn.Create(path, value, flags, aclv) } } if !shouldRetry(err) { return } } return }
func (conn *zconn) RetryChange(path string, flags int, acl []zookeeper.ACL, changeFunc zk.ChangeFunc) error { for { oldValue, oldStat, err := conn.Get(path) if err != nil && !zookeeper.IsError(err, zookeeper.ZNONODE) { return err } newValue, err := changeFunc(oldValue, oldStat) if err != nil { return err } if oldStat == nil { _, err := conn.Create(path, newValue, flags, acl) if err == nil || !zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { return err } continue } if newValue == oldValue { return nil // Nothing to do. } _, err = conn.Set(path, newValue, oldStat.Version()) if err == nil || !zookeeper.IsError(err, zookeeper.ZBADVERSION) && !zookeeper.IsError(err, zookeeper.ZNONODE) { return err } } }
func DeleteRecursive(zconn Conn, zkPath string, version int) error { // version: -1 delete any version of the node at path - only applies to the top node err := zconn.Delete(zkPath, version) if err == nil { return nil } if !zookeeper.IsError(err, zookeeper.ZNOTEMPTY) { return err } // Remove the ability for other nodes to get created while we are trying to delete. // Otherwise, you can enter a race condition, or get starved out from deleting. err = zconn.SetACL(zkPath, zookeeper.WorldACL(zookeeper.PERM_ADMIN|zookeeper.PERM_DELETE|zookeeper.PERM_READ), version) if err != nil { return err } children, _, err := zconn.Children(zkPath) if err != nil { return err } for _, child := range children { err := DeleteRecursive(zconn, path.Join(zkPath, child), -1) if err != nil && !zookeeper.IsError(err, zookeeper.ZNONODE) { return fmt.Errorf("zkutil: recursive delete failed: %v", err) } } err = zconn.Delete(zkPath, version) if err != nil && !zookeeper.IsError(err, zookeeper.ZNOTEMPTY) { err = fmt.Errorf("zkutil: nodes getting recreated underneath delete (app race condition): %v", zkPath) } return err }
func (zkts *Server) UpdateKeyspace(ki *topo.KeyspaceInfo) error { keyspacePath := path.Join(globalKeyspacesPath, ki.KeyspaceName()) data := jscfg.ToJson(ki.Keyspace) _, err := zkts.zconn.Set(keyspacePath, data, -1) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { // The code should be: // err = topo.ErrNoNode // Temporary code until we have Keyspace object // everywhere: _, err = zkts.zconn.Create(keyspacePath, data, 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { // the directory doesn't even exist err = topo.ErrNoNode } return err } event.Dispatch(&events.KeyspaceChange{ KeyspaceInfo: *ki, Status: "updated (had to create Keyspace object)", }) return nil } return err } event.Dispatch(&events.KeyspaceChange{ KeyspaceInfo: *ki, Status: "updated", }) return nil }
// Create the persistence node in zookeeper func (zk *ZK) Create(path string, node string) error { // create zk root path tpath := "" for _, str := range strings.Split(path, "/")[1:] { tpath += "/" + str Log.Debug("create zookeeper path:%s", tpath) _, err := zk.conn.Create(tpath, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { Log.Warn("zk.Create(\"%s\") exists", tpath) } else { Log.Error("zk.Create(\"%s\") failed (%s)", tpath, err.Error()) return err } } } // create node path fpath := path + "/" + node Log.Debug("create zookeeper path:%s", fpath) _, err := zk.conn.Create(fpath, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { Log.Warn("zk.Create(\"%s\") exists", fpath) } else { Log.Error("zk.Create(\"%s\") failed (%s)", fpath, err.Error()) return err } } return nil }
// PurgeActions removes all queued actions, leaving the action node // itself in place. // // This inherently breaks the locking mechanism of the action queue, // so this is a rare cleanup action, not a normal part of the flow. // // This can be used for tablets, shards and keyspaces. func (zkts *Server) PurgeActions(zkActionPath string, canBePurged func(data string) bool) error { if path.Base(zkActionPath) != "action" { return fmt.Errorf("not action path: %v", zkActionPath) } children, _, err := zkts.zconn.Children(zkActionPath) if err != nil { return err } sort.Strings(children) // Purge newer items first so the action queues don't try to process something. for i := len(children) - 1; i >= 0; i-- { actionPath := path.Join(zkActionPath, children[i]) data, _, err := zkts.zconn.Get(actionPath) if err != nil && !zookeeper.IsError(err, zookeeper.ZNONODE) { return fmt.Errorf("PurgeActions(%v) err: %v", zkActionPath, err) } if !canBePurged(data) { continue } err = zk.DeleteRecursive(zkts.zconn, actionPath, -1) if err != nil && !zookeeper.IsError(err, zookeeper.ZNONODE) { return fmt.Errorf("PurgeActions(%v) err: %v", zkActionPath, err) } } return nil }
// Create the persistence node in zookeeper func (zk *ZK) create() error { // create zk root path tpath := "" for _, str := range strings.Split(Conf.ZookeeperPath, "/")[1:] { tpath += "/" + str Log.Debug("create zookeeper path:%s", tpath) _, err := zk.conn.Create(tpath, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { Log.Warn("zk.create(\"%s\") exists", tpath) } else { Log.Error("zk.create(\"%s\") error(%v)", tpath, err) return err } } } // create node path fpath := fmt.Sprintf("%s/%s", Conf.ZookeeperPath, Conf.ZookeeperNode) Log.Debug("create zookeeper path:%s", fpath) _, err := zk.conn.Create(fpath, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { Log.Warn("zk.Create(\"%s\") exists", fpath) } else { Log.Error("zk.Create(\"%s\") error(%v)", fpath, err) return err } } return nil }
// return a few values that need to be refreshed func (zkc *ZkCache) refreshSomeValues(zconn zk.Conn, maxToRefresh int) { // build a list of a few values we want to refresh refreshThreshold := time.Now().Add(-10 * time.Minute) // range will randomize the traversal order, so we will not always try // the same entries in the same order dataEntries := make([]*zkCacheEntry, 0, maxToRefresh) childrenEntries := make([]*zkCacheEntry, 0, maxToRefresh) zkc.mutex.Lock() for _, entry := range zkc.Cache { shouldBeDataRefreshed, shouldBeChildrenRefreshed := entry.checkForRefresh(refreshThreshold) if shouldBeDataRefreshed { dataEntries = append(dataEntries, entry) } if shouldBeChildrenRefreshed { childrenEntries = append(childrenEntries, entry) } // check if we have enough work to do if len(dataEntries) == maxToRefresh || len(childrenEntries) == maxToRefresh { break } } zkc.mutex.Unlock() // now refresh the values for _, entry := range dataEntries { data, stat, watch, err := zconn.GetW(entry.node.Path) if err == nil { zkStat := &zk.ZkStat{} zkStat.FromZookeeperStat(stat) entry.updateData(data, zkStat, watch) } else if zookeeper.IsError(err, zookeeper.ZCLOSING) { // connection is closing, no point in asking for more relog.Warning("failed to refresh cache: %v (and stopping refresh)", err.Error()) return } else { // individual failure relog.Warning("failed to refresh cache: %v", err.Error()) } } for _, entry := range childrenEntries { children, stat, watch, err := zconn.ChildrenW(entry.node.Path) if err == nil { zkStat := &zk.ZkStat{} zkStat.FromZookeeperStat(stat) entry.updateChildren(children, zkStat, watch) } else if zookeeper.IsError(err, zookeeper.ZCLOSING) { // connection is closing, no point in asking for more relog.Warning("failed to refresh cache: %v (and stopping refresh)", err.Error()) return } else { // individual failure relog.Warning("failed to refresh cache: %v", err.Error()) } } }
func (zkd *Zkd) init(preserveData bool) error { log.Infof("zkd.Init") for _, path := range zkd.config.DirectoryList() { if err := os.MkdirAll(path, 0775); err != nil { log.Errorf(err.Error()) return err } // FIXME(msolomon) validate permissions? } configData, err := zkd.makeCfg() if err == nil { err = ioutil.WriteFile(zkd.config.ConfigFile(), []byte(configData), 0664) } if err != nil { log.Errorf("failed creating %v: %v", zkd.config.ConfigFile(), err) return err } err = zkd.config.WriteMyid() if err != nil { log.Errorf("failed creating %v: %v", zkd.config.MyidFile(), err) return err } if err = zkd.Start(); err != nil { log.Errorf("failed starting, check %v", zkd.config.LogDir()) return err } zkAddr := fmt.Sprintf("localhost:%v", zkd.config.ClientPort) zk, session, err := zookeeper.Dial(zkAddr, StartWaitTime*time.Second) if err != nil { return err } event := <-session if event.State != zookeeper.STATE_CONNECTED { return err } defer zk.Close() if !preserveData { _, err = zk.Create("/zk", "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil && !zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { return err } if zkd.config.Global { _, err = zk.Create("/zk/global", "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil && !zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { return err } } } return nil }
// DeleteEndPoints is part of the topo.Server interface func (zkts *Server) DeleteEndPoints(ctx context.Context, cell, keyspace, shard string, tabletType topodatapb.TabletType, existingVersion int64) error { path := zkPathForVtName(cell, keyspace, shard, tabletType) if err := zkts.zconn.Delete(path, int(existingVersion)); err != nil { switch { case zookeeper.IsError(err, zookeeper.ZNONODE): err = topo.ErrNoNode case zookeeper.IsError(err, zookeeper.ZBADVERSION): err = topo.ErrBadVersion } return err } return nil }
func (zkts *Server) DeleteReplicationPath(keyspace, shard, repPath string) error { replicationPath := path.Join(globalKeyspacesPath, keyspace, "shards", shard, repPath) err := zkts.zconn.Delete(replicationPath, -1) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } else if zookeeper.IsError(err, zookeeper.ZNOTEMPTY) { err = topo.ErrNotEmpty } return err } return nil }
func (entry *zkCacheEntry) checkForRefresh(refreshThreshold time.Time) (shouldBeDataRefreshed, shouldBeChildrenRefreshed bool) { entry.mutex.Lock() defer entry.mutex.Unlock() if entry.dataTime.IsZero() { // the entry was never set // if we had an error getting it, it means we asked for it, // see if we can get a good value if entry.dataError != nil { if zookeeper.IsError(entry.dataError, zookeeper.ZNONODE) { // we had no node, we can try next time a client asks entry.dataError = nil // at this point, we have both // dataTime.IsZero() and // entry.dataError = nil, as if we // never asked for it } else { // we had a valid error, let's try again shouldBeDataRefreshed = true } } } else { // 1. we got a value at some point, then it got stale // 2. we got a value a long time ago, refresh it shouldBeDataRefreshed = entry.dataError != nil || entry.dataTime.Before(refreshThreshold) } if entry.childrenTime.IsZero() { // the entry was never set // if we had an error getting it, it means we asked for it, // see if we can get a good value if entry.childrenError != nil { if zookeeper.IsError(entry.childrenError, zookeeper.ZNONODE) { // we had no node, we can try next time a client asks entry.childrenError = nil // at this point, we have both // childrenTime.IsZero() and // entry.childrenError = nil, as if we // never asked for it } else { shouldBeChildrenRefreshed = true // we had a valid error, let's try again } } } else { // 1. we got a value at some point, then it got stale // 2. we got a value a long time ago, refresh it shouldBeChildrenRefreshed = entry.childrenError != nil || entry.childrenTime.Before(refreshThreshold) } return }
func (zkts *Server) UpdateTablet(tablet *topo.TabletInfo, existingVersion int) (int, error) { zkTabletPath := TabletPathForAlias(tablet.Alias()) stat, err := zkts.zconn.Set(zkTabletPath, tablet.Json(), existingVersion) if err != nil { if zookeeper.IsError(err, zookeeper.ZBADVERSION) { err = topo.ErrBadVersion } else if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } return 0, err } return stat.Version(), nil }
// StaleActions returns a list of queued actions that have been // sitting for more than some amount of time. func (zkts *Server) StaleActions(zkActionPath string, maxStaleness time.Duration, isStale func(data string) bool) ([]string, error) { if path.Base(zkActionPath) != "action" { return nil, fmt.Errorf("not action path: %v", zkActionPath) } children, _, err := zkts.zconn.Children(zkActionPath) if err != nil { return nil, err } staleActions := make([]string, 0, 16) // Purge newer items first so the action queues don't try to process something. sort.Strings(children) for i := 0; i < len(children); i++ { actionPath := path.Join(zkActionPath, children[i]) data, stat, err := zkts.zconn.Get(actionPath) if err != nil && !zookeeper.IsError(err, zookeeper.ZNONODE) { return nil, fmt.Errorf("stale action err: %v", err) } if stat == nil || time.Since(stat.MTime()) <= maxStaleness { continue } if isStale(data) { staleActions = append(staleActions, data) } } return staleActions, nil }
func (zkts *Server) CreateKeyspace(keyspace string) error { keyspacePath := path.Join(globalKeyspacesPath, keyspace) pathList := []string{ keyspacePath, path.Join(keyspacePath, "action"), path.Join(keyspacePath, "actionlog"), path.Join(keyspacePath, "shards"), } alreadyExists := false for _, zkPath := range pathList { _, err := zk.CreateRecursive(zkts.zconn, zkPath, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { alreadyExists = true } else { return fmt.Errorf("error creating keyspace: %v %v", zkPath, err) } } } if alreadyExists { return topo.ErrNodeExists } return nil }
// DeleteKeyspaceShards is part of the topo.Server interface func (zkts *Server) DeleteKeyspaceShards(ctx context.Context, keyspace string) error { shardsPath := path.Join(globalKeyspacesPath, keyspace, "shards") if err := zk.DeleteRecursive(zkts.zconn, shardsPath, -1); err != nil && !zookeeper.IsError(err, zookeeper.ZNONODE) { return err } return nil }
func (zkts *Server) UpdateTabletFields(tabletAlias topo.TabletAlias, update func(*topo.Tablet) error) error { zkTabletPath := TabletPathForAlias(tabletAlias) f := func(oldValue string, oldStat zk.Stat) (string, error) { if oldValue == "" { return "", fmt.Errorf("no data for tablet addr update: %v", tabletAlias) } tablet, err := topo.TabletFromJson(oldValue) if err != nil { return "", err } if err := update(tablet); err != nil { return "", err } return jscfg.ToJson(tablet), nil } err := zkts.zconn.RetryChange(zkTabletPath, 0, zookeeper.WorldACL(zookeeper.PERM_ALL), f) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } return err } return nil }
// DeleteTablet is part of the topo.Server interface func (zkts *Server) DeleteTablet(ctx context.Context, alias topo.TabletAlias) error { // We need to find out the keyspace and shard names because // those are required in the TabletChange event. ti, tiErr := zkts.GetTablet(ctx, alias) zkTabletPath := TabletPathForAlias(alias) err := zk.DeleteRecursive(zkts.zconn, zkTabletPath, -1) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } return err } // Only try to log if we have the required information. if tiErr == nil { // We only want to copy the identity info for the tablet (alias, etc.). // The rest has just been deleted, so it should be blank. event.Dispatch(&events.TabletChange{ Tablet: topo.Tablet{ Alias: ti.Tablet.Alias, Keyspace: ti.Tablet.Keyspace, Shard: ti.Tablet.Shard, }, Status: "deleted", }) } return nil }
func getActions(wr *wrangler.Wrangler, zconn zk.Conn, actionPath string) ([]*actionnode.ActionNode, error) { actions, _, err := zconn.Children(actionPath) if err != nil { return nil, fmt.Errorf("getActions failed: %v %v", actionPath, err) } sort.Strings(actions) wg := sync.WaitGroup{} mu := sync.Mutex{} nodes := make([]*actionnode.ActionNode, 0, len(actions)) for _, action := range actions { wg.Add(1) go func(action string) { defer wg.Done() actionNodePath := path.Join(actionPath, action) data, _, err := zconn.Get(actionNodePath) if err != nil && !zookeeper.IsError(err, zookeeper.ZNONODE) { wr.Logger().Warningf("getActions: %v %v", actionNodePath, err) return } actionNode, err := actionnode.ActionNodeFromJson(data, actionNodePath) if err != nil { wr.Logger().Warningf("getActions: %v %v", actionNodePath, err) return } mu.Lock() nodes = append(nodes, actionNode) mu.Unlock() }(action) } wg.Wait() return nodes, nil }
// Create a path and any pieces required, think mkdir -p. // Intermediate znodes are always created empty. func CreateRecursive(zconn Conn, zkPath, value string, flags int, aclv []zookeeper.ACL) (pathCreated string, err error) { parts := strings.Split(zkPath, "/") if parts[1] != "zk" { return "", fmt.Errorf("zkutil: non zk path: %v", zkPath) } pathCreated, err = zconn.Create(zkPath, value, flags, aclv) if zookeeper.IsError(err, zookeeper.ZNONODE) { _, err = CreateRecursive(zconn, path.Dir(zkPath), "", flags, aclv) if err != nil && !zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { return "", err } pathCreated, err = zconn.Create(zkPath, value, flags, aclv) } return }
func (zkts *Server) CreateKeyspace(keyspace string, value *topo.Keyspace) error { keyspacePath := path.Join(globalKeyspacesPath, keyspace) pathList := []string{ keyspacePath, path.Join(keyspacePath, "action"), path.Join(keyspacePath, "actionlog"), path.Join(keyspacePath, "shards"), } alreadyExists := false for i, zkPath := range pathList { c := "" if i == 0 { c = jscfg.ToJson(value) } _, err := zk.CreateRecursive(zkts.zconn, zkPath, c, 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { alreadyExists = true } else { return fmt.Errorf("error creating keyspace: %v %v", zkPath, err) } } } if alreadyExists { return topo.ErrNodeExists } event.Dispatch(&events.KeyspaceChange{ KeyspaceInfo: *topo.NewKeyspaceInfo(keyspace, value), Status: "created", }) return nil }
// UpdateTabletFields is part of the topo.Server interface func (zkts *Server) UpdateTabletFields(ctx context.Context, tabletAlias *topodatapb.TabletAlias, update func(*topodatapb.Tablet) error) (*topodatapb.Tablet, error) { // Store the last tablet value so we can log it if the change succeeds. var lastTablet *topodatapb.Tablet zkTabletPath := TabletPathForAlias(tabletAlias) f := func(oldValue string, oldStat zk.Stat) (string, error) { if oldValue == "" { return "", fmt.Errorf("no data for tablet addr update: %v", tabletAlias) } tablet := &topodatapb.Tablet{} if err := json.Unmarshal([]byte(oldValue), tablet); err != nil { return "", err } if err := update(tablet); err != nil { return "", err } lastTablet = tablet data, err := json.MarshalIndent(tablet, "", " ") if err != nil { return "", err } return string(data), nil } err := zkts.zconn.RetryChange(zkTabletPath, 0, zookeeper.WorldACL(zookeeper.PERM_ALL), f) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } return nil, err } return lastTablet, nil }
// NewConnFromFile returns a fake zk.Conn implementation, that is seeded // with the json data extracted from the input file. func NewConnFromFile(filename string) zk.Conn { result := &zconn{ root: &node{ _stat: _stat{name: "/"}, children: make(map[string]*node), }, existWatches: make(map[string][]chan zookeeper.Event)} data, err := ioutil.ReadFile(filename) if err != nil { panic(fmt.Errorf("NewConnFromFile failed to read file %v: %v", filename, err)) } values := make(map[string]interface{}) if err := json.Unmarshal(data, &values); err != nil { panic(fmt.Errorf("NewConnFromFile failed to json.Unmarshal file %v: %v", filename, err)) } for k, v := range values { jv, err := json.Marshal(v) if err != nil { panic(fmt.Errorf("NewConnFromFile failed to json.Marshal value %v: %v", k, err)) } // CreateRecursive will work for a leaf node where the parent // doesn't exist, but not for a node in the middle of a tree // that already exists. So have to use 'Set' as a backup. if _, err := zk.CreateRecursive(result, k, string(jv), 0, nil); err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { _, err = result.Set(k, string(jv), -1) } if err != nil { panic(fmt.Errorf("NewConnFromFile failed to zk.CreateRecursive value %v: %v", k, err)) } } } return result }
// CreateShard is part of the topo.Server interface func (zkts *Server) CreateShard(ctx context.Context, keyspace, shard string, value *topodatapb.Shard) error { shardPath := path.Join(globalKeyspacesPath, keyspace, "shards", shard) pathList := []string{ shardPath, path.Join(shardPath, "action"), path.Join(shardPath, "actionlog"), } data, err := json.MarshalIndent(value, "", " ") if err != nil { return err } alreadyExists := false for i, zkPath := range pathList { c := "" if i == 0 { c = string(data) } _, err := zk.CreateRecursive(zkts.zconn, zkPath, c, 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { alreadyExists = true } else { return fmt.Errorf("error creating shard: %v %v", zkPath, err) } } } if alreadyExists { return topo.ErrNodeExists } return nil }
func cmdWait(args []string) { if len(args) != 1 { log.Fatalf("wait: can only wait for one path") } zkPath := args[0] isDir := zkPath[len(zkPath)-1] == '/' zkPath = fixZkPath(zkPath) var wait <-chan zookeeper.Event var err error if isDir { _, _, wait, err = zconn.ChildrenW(zkPath) } else { _, _, wait, err = zconn.GetW(zkPath) } if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { _, wait, err = zconn.ExistsW(zkPath) } else { log.Fatalf("wait: error %v: %v", zkPath, err) } } else { if *exitIfExists { fmt.Printf("already exists: %v\n", zkPath) return } } event := <-wait fmt.Printf("event: %v\n", event) }
// PubMIDLock public message mid lock, make sure that get the unique mid func PubMIDLock() (bool, string, error) { prefix := "p" splitSign := "@" pathCreated, err := zk.Create(fmt.Sprintf("%s/%s%s", Conf.ZKPIDPath, prefix, splitSign), "0", zookeeper.EPHEMERAL|zookeeper.SEQUENCE, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { return false, pathCreated, fmt.Errorf("zk.Create(%s/%s%s) error(%v)", Conf.ZKPIDPath, prefix, splitSign, err) } for { childrens, stat, err := zk.Children(Conf.ZKPIDPath) if err != nil { return false, pathCreated, fmt.Errorf("zk.Children(%s) error(%v)", Conf.ZKPIDPath, err) } // If node isn`t exist if childrens == nil || stat == nil { return false, pathCreated, fmt.Errorf("node(%s) is not existent", Conf.ZKPIDPath) } var realQueue []string for _, children := range childrens { tmp := strings.Split(children, splitSign) if prefix == tmp[0] { realQueue = append(realQueue, children) } } // Sort sequence nodes sort.Strings(realQueue) tmp := strings.Split(pathCreated, "/") posReal := sort.StringSlice(realQueue).Search(tmp[len(tmp)-1]) // If does not get lock if posReal > 0 { // Watch the last one watchPath := fmt.Sprintf("%s/%s", Conf.ZKPIDPath, realQueue[posReal-1]) _, watch, err := zk.ExistsW(watchPath) if err != nil || zookeeper.IsError(err, zookeeper.ZNONODE) { return false, pathCreated, fmt.Errorf("zk.ExistsW(%s) error(%v) or no node", watchPath, err) } // Watch the lower node watchNode := <-watch switch watchNode.Type { case zookeeper.EVENT_DELETED: default: return false, pathCreated, fmt.Errorf("zookeeper watch errCode:%d", watchNode.Type) } return false, pathCreated, nil } else { return true, pathCreated, nil } } // Never get here return false, pathCreated, fmt.Errorf("never get here") }
func (zkts *Server) CreateTablet(tablet *topo.Tablet) error { zkTabletPath := TabletPathForAlias(tablet.Alias()) // Create /zk/<cell>/vt/tablets/<uid> _, err := zk.CreateRecursive(zkts.zconn, zkTabletPath, tablet.Json(), 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { err = topo.ErrNodeExists } return err } // Create /zk/<cell>/vt/tablets/<uid>/action tap := path.Join(zkTabletPath, "action") _, err = zkts.zconn.Create(tap, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { return err } // Create /zk/<cell>/vt/tablets/<uid>/actionlog talp := path.Join(zkTabletPath, "actionlog") _, err = zkts.zconn.Create(talp, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { return err } return nil }
// CreateShard is part of the topo.Server interface func (zkts *Server) CreateShard(ctx context.Context, keyspace, shard string, value *pb.Shard) error { shardPath := path.Join(globalKeyspacesPath, keyspace, "shards", shard) pathList := []string{ shardPath, path.Join(shardPath, "action"), path.Join(shardPath, "actionlog"), } alreadyExists := false for i, zkPath := range pathList { c := "" if i == 0 { c = jscfg.ToJSON(value) } _, err := zk.CreateRecursive(zkts.zconn, zkPath, c, 0, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { if zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { alreadyExists = true } else { return fmt.Errorf("error creating shard: %v %v", zkPath, err) } } } if alreadyExists { return topo.ErrNodeExists } event.Dispatch(&events.ShardChange{ ShardInfo: *topo.NewShardInfo(keyspace, shard, value, -1), Status: "created", }) return nil }
// UpdateShardReplicationFields is part of the topo.Server interface func (zkts *Server) UpdateShardReplicationFields(ctx context.Context, cell, keyspace, shard string, update func(*pb.ShardReplication) error) error { // create the parent directory to be sure it's here zkDir := path.Join("/zk", cell, "vt", "replication", keyspace) if _, err := zk.CreateRecursive(zkts.zconn, zkDir, "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL)); err != nil && !zookeeper.IsError(err, zookeeper.ZNODEEXISTS) { return err } // now update the data zkPath := shardReplicationPath(cell, keyspace, shard) f := func(oldValue string, oldStat zk.Stat) (string, error) { sr := &pb.ShardReplication{} if oldValue != "" { if err := json.Unmarshal([]byte(oldValue), sr); err != nil { return "", err } } if err := update(sr); err != nil { return "", err } data, err := json.MarshalIndent(sr, "", " ") if err != nil { return "", err } return string(data), nil } err := zkts.zconn.RetryChange(zkPath, 0, zookeeper.WorldACL(zookeeper.PERM_ALL), f) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } return err } return nil }