diff --git a/log/log.go b/log/log.go index 189b2585..5e8d7781 100644 --- a/log/log.go +++ b/log/log.go @@ -12,10 +12,6 @@ const ( rqliteAppliedIndex = "rqlite_applied_index" ) -var ( - ErrKeyNotFound = raftboltdb.ErrKeyNotFound -) - // Log is an object that can return information about the Raft log. type Log struct { *raftboltdb.BoltStore @@ -105,17 +101,6 @@ func (l *Log) GetAppliedIndex() (uint64, error) { return i, nil } -// Get returns the value for the given key. -func (l *Log) Get(key []byte) (val []byte, err error) { - defer func() { - if err != raftboltdb.ErrKeyNotFound { - err = ErrKeyNotFound - } - }() - val, err = l.BoltStore.Get(key) - return -} - // Stats returns stats about the BBoltDB database. func (l *Log) Stats() bbolt.Stats { return l.BoltStore.Stats() diff --git a/store/store.go b/store/store.go index 6b23b84f..aec9c3fe 100644 --- a/store/store.go +++ b/store/store.go @@ -742,6 +742,16 @@ func (s *Store) State() ClusterState { } } +// LastVacuumTime returns the time of the last automatic VACUUM. +func (s *Store) LastVacuumTime() (time.Time, error) { + vt, err := s.boltStore.Get([]byte(lastVacuumTimeKey)) + if err != nil { + return time.Time{}, fmt.Errorf("failed to get last vacuum time: %s", err) + } + n := int64(binary.LittleEndian.Uint64(vt)) + return time.Unix(0, n), nil +} + // Path returns the path to the store's storage directory. func (s *Store) Path() string { return s.raftDir @@ -1007,7 +1017,7 @@ func (s *Store) Stats() (map[string]interface{}, error) { "sqlite3": dbStatus, "db_conf": s.dbConf, } - if lVac, err := s.lastVacuumTime(); err == nil { + if lVac, err := s.LastVacuumTime(); err == nil { status["last_vacuum"] = lVac.String() } @@ -1640,20 +1650,8 @@ func (s *Store) vacuumInto() (string, error) { } func (s *Store) initLastVacuumTime() error { - if _, err := s.boltStore.Get([]byte(lastVacuumTimeKey)); err != nil { - if err == rlog.ErrKeyNotFound { - s.logger.Println("no vacuum has been performed on this database") - n := time.Now().UnixNano() // First vacuum will be in the future. - buf := bytes.NewBuffer(make([]byte, 0, 8)) - if err := binary.Write(buf, binary.LittleEndian, n); err != nil { - return fmt.Errorf("failed to write last vacuum time: %s", err) - } - if err := s.boltStore.Set([]byte(lastVacuumTimeKey), buf.Bytes()); err != nil { - return fmt.Errorf("failed to set last vacuum time: %s", err) - } - } else { - return fmt.Errorf("failed to get last vacuum time: %s", err) - } + if _, err := s.LastVacuumTime(); err != nil { + return s.setLastVacuumTime(time.Now()) } return nil } @@ -1669,15 +1667,6 @@ func (s *Store) setLastVacuumTime(t time.Time) error { return nil } -func (s *Store) lastVacuumTime() (time.Time, error) { - vt, err := s.boltStore.Get([]byte(lastVacuumTimeKey)) - if err != nil { - return time.Time{}, fmt.Errorf("failed to get last vacuum time: %s", err) - } - n := int64(binary.LittleEndian.Uint64(vt)) - return time.Unix(0, n), nil -} - // raftConfig returns a new Raft config for the store. func (s *Store) raftConfig() *raft.Config { config := raft.DefaultConfig() @@ -1833,7 +1822,7 @@ func (s *Store) fsmSnapshot() (fSnap raft.FSMSnapshot, retErr error) { }() // Automatic VACUUM needed? - lvt, err := s.lastVacuumTime() + lvt, err := s.LastVacuumTime() if err != nil { return nil, err } diff --git a/store/store_test.go b/store/store_test.go index ecdda235..6725d373 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -53,6 +53,24 @@ func Test_OpenStoreSingleNode(t *testing.T) { } } +func Test_OpenStoreSingleNode_LastVacuum(t *testing.T) { + s, ln := mustNewStore(t) + defer s.Close(true) + defer ln.Close() + + now := time.Now() + if err := s.Open(); err != nil { + t.Fatalf("failed to open single-node store: %s", err.Error()) + } + lv, err := s.LastVacuumTime() + if err != nil { + t.Fatalf("failed to retrieve last vacuum time: %s", err.Error()) + } + if lv.Before(now) { + t.Fatalf("last vacuum time is before now, lv: %s, now: %s", lv, now) + } +} + // Test_SingleNodeSQLitePath ensures that basic functionality works when the SQLite database path // is explicitly specificed. func Test_SingleNodeOnDiskSQLitePath(t *testing.T) {