func readDatabase() (Database, error) { kvdb := kvdb.Instance() db := Database{ Status: api.Status_STATUS_INIT, NodeEntries: make(map[string]NodeEntry), } kv, err := kvdb.Get(ClusterDBKey) if err != nil && !strings.Contains(err.Error(), "Key not found") { dlog.Warnln("Warning, could not read cluster database") return db, err } if kv == nil || bytes.Compare(kv.Value, []byte("{}")) == 0 { dlog.Infoln("Cluster is uninitialized...") return db, nil } if err := json.Unmarshal(kv.Value, &db); err != nil { dlog.Warnln("Fatal, Could not parse cluster database ", kv) return db, err } return db, nil }
func writeDatabase(db *Database) error { kvdb := kvdb.Instance() b, err := json.Marshal(db) if err != nil { dlog.Warnf("Fatal, Could not marshal cluster database to JSON: %v", err) return err } if _, err := kvdb.Put(ClusterDBKey, b, 0); err != nil { dlog.Warnf("Fatal, Could not marshal cluster database to JSON: %v", err) return err } dlog.Infoln("Cluster database updated.") return nil }
func (c *ClusterManager) Start() error { dlog.Infoln("Cluster manager starting...") c.gEnabled = true c.selfNode = api.Node{} c.selfNode.GenNumber = uint64(time.Now().UnixNano()) c.selfNode.Id = c.config.NodeId c.selfNode.Status = api.Status_STATUS_OK c.selfNode.MgmtIp, c.selfNode.DataIp, _ = ExternalIp(&c.config) c.selfNode.NodeData = make(map[string]interface{}) c.system = systemutils.New() // Start the gossip protocol. // XXX Make the port configurable. gob.Register(api.Node{}) c.gossip = gossip.New("0.0.0.0:9002", types.NodeId(c.config.NodeId), c.selfNode.GenNumber) c.gossip.SetGossipInterval(2 * time.Second) kvdb := kvdb.Instance() kvlock, err := kvdb.Lock(clusterLockKey, 60) if err != nil { dlog.Panicln("Fatal, Unable to obtain cluster lock.", err) } defer kvdb.Unlock(kvlock) db, err := readDatabase() if err != nil { dlog.Panicln(err) } // Cluster database max size... 0 if unlimited. c.size = db.Size if db.Status == api.Status_STATUS_INIT { dlog.Infoln("Will initialize a new cluster.") c.status = api.Status_STATUS_OK db.Status = api.Status_STATUS_OK self, _ := c.initNode(&db) err = c.initCluster(&db, self, false) if err != nil { dlog.Errorln("Failed to initialize the cluster.", err) return err } // Update the new state of the cluster in the KV Database err := writeDatabase(&db) if err != nil { dlog.Errorln("Failed to save the database.", err) return err } } else if db.Status&api.Status_STATUS_OK > 0 { dlog.Infoln("Cluster state is OK... Joining the cluster.") c.status = api.Status_STATUS_OK self, exist := c.initNode(&db) err = c.joinCluster(&db, self, exist) if err != nil { dlog.Errorln("Failed to join cluster.", err) return err } err := writeDatabase(&db) if err != nil { return err } } else { return errors.New("Fatal, Cluster is in an unexpected state.") } // Start heartbeating to other nodes. go c.startHeartBeat() go c.updateClusterStatus() kvdb.WatchKey(ClusterDBKey, 0, nil, c.watchDB) return nil }