// open opens the the in-memory or file-based database. func (s *Store) open() (*sql.DB, error) { var db *sql.DB var err error if !s.dbConf.Memory { // as it will be rebuilt from (possibly) a snapshot and committed log entries. if err := os.Remove(s.dbPath); err != nil && !os.IsNotExist(err) { return nil, err } db, err = sql.OpenWithDSN(s.dbPath, s.dbConf.DSN) if err != nil { return nil, err } s.logger.Println("SQLite database opened at", s.dbPath) } else { db, err = sql.OpenInMemoryWithDSN(s.dbConf.DSN) if err != nil { return nil, err } s.logger.Println("SQLite in-memory database opened") } return db, nil }
// Restore restores the node to a previous state. func (s *Store) Restore(rc io.ReadCloser) error { if err := s.db.Close(); err != nil { return err } // Get size of database. var sz uint64 if err := binary.Read(rc, binary.LittleEndian, &sz); err != nil { return err } // Now read in the database file data and restore. database := make([]byte, sz) if _, err := io.ReadFull(rc, database); err != nil { return err } var db *sql.DB var err error if !s.dbConf.Memory { // Write snapshot over any existing database file. if err := ioutil.WriteFile(s.dbPath, database, 0660); err != nil { return err } // Re-open it. db, err = sql.OpenWithDSN(s.dbPath, s.dbConf.DSN) if err != nil { return err } } else { // In memory. Copy to temporary file, and then load memory from file. f, err := ioutil.TempFile("", "rqlilte-snap-") if err != nil { return err } f.Close() defer os.Remove(f.Name()) if err := ioutil.WriteFile(f.Name(), database, 0660); err != nil { return err } // Load an in-memory database from the snapshot now on disk. db, err = sql.LoadInMemoryWithDSN(f.Name(), s.dbConf.DSN) if err != nil { return err } } s.db = db // Read remaining bytes, and set to cluster meta. b, err := ioutil.ReadAll(rc) if err != nil { return err } return func() error { s.metaMu.Lock() defer s.metaMu.Unlock() return json.Unmarshal(b, &s.meta) }() }
// Open opens the store. If enableSingle is set, and there are no existing peers, // then this node becomes the first node, and therefore leader, of the cluster. func (s *Store) Open(enableSingle bool) error { if err := os.MkdirAll(s.raftDir, 0755); err != nil { return err } // Create the database. Unless it's a memory-based database, it must be deleted var db *sql.DB var err error if !s.dbConf.Memory { // as it will be rebuilt from (possibly) a snapshot and committed log entries. if err := os.Remove(s.dbPath); err != nil && !os.IsNotExist(err) { return err } db, err = sql.OpenWithDSN(s.dbPath, s.dbConf.DSN) if err != nil { return err } s.logger.Println("SQLite database opened at", s.dbPath) } else { db, err = sql.OpenInMemoryWithDSN(s.dbConf.DSN) if err != nil { return err } s.logger.Println("SQLite in-memory database opened") } s.db = db // Setup Raft configuration. config := raft.DefaultConfig() // Check for any existing peers. peers, err := readPeersJSON(filepath.Join(s.raftDir, "peers.json")) if err != nil { return err } s.joinRequired = len(peers) <= 1 // Allow the node to entry single-mode, potentially electing itself, if // explicitly enabled and there is only 1 node in the cluster already. if enableSingle && len(peers) <= 1 { s.logger.Println("enabling single-node mode") config.EnableSingleNode = true config.DisableBootstrapAfterElect = false } // Setup Raft communication. transport := raft.NewNetworkTransport(s.raftTransport, 3, 10*time.Second, os.Stderr) // Create peer storage. peerStore := raft.NewJSONPeers(s.raftDir, transport) // Create the snapshot store. This allows Raft to truncate the log. snapshots, err := raft.NewFileSnapshotStore(s.raftDir, retainSnapshotCount, os.Stderr) if err != nil { return fmt.Errorf("file snapshot store: %s", err) } // Create the log store and stable store. logStore, err := raftboltdb.NewBoltStore(filepath.Join(s.raftDir, "raft.db")) if err != nil { return fmt.Errorf("new bolt store: %s", err) } // Instantiate the Raft system. ra, err := raft.NewRaft(config, s, logStore, logStore, snapshots, peerStore, transport) if err != nil { return fmt.Errorf("new raft: %s", err) } s.raft = ra return nil }