Block query transactions during serialize
@@ -125,6 +125,8 @@ type Store struct {
dbPath string // Path to underlying SQLite file, if not in-memory.
db *sql.DB // The underlying SQLite store.
+ queryTxMu sync.RWMutex
+
dbAppliedIndexMu sync.RWMutex
dbAppliedIndex uint64
@@ -691,6 +693,13 @@ func (s *Store) Query(qr *command.QueryRequest) ([]*command.QueryRows, error) {
return nil, ErrStaleRead
}
+ if qr.Request.Transaction {
+ // Transaction requested during query, but not going through consensus. This means
+ // we need to block any database serialization during the query.
+ s.queryTxMu.RLock()
+ defer s.queryTxMu.RUnlock()
+ }
+
return s.db.Query(qr.Request, qr.Timings)
}
@@ -940,6 +949,8 @@ func (s *Store) Apply(l *raft.Log) (e interface{}) {
// been applied, but it wouldn't have created the on-disk database in that
// case since there were commands in the log. This is the very last chance
// to do convert from in-memory to on-disk.
+ s.queryTxMu.Lock()
+ defer s.queryTxMu.Unlock()
b, _ := s.db.Serialize()
err := s.db.Close()
if err != nil {
@@ -1022,6 +1033,8 @@ func (s *Store) Snapshot() (raft.FSMSnapshot, error) {
logger: s.logger,
}
+ s.queryTxMu.Lock()
+ defer s.queryTxMu.Unlock()
fsm.database, _ = s.db.Serialize()
// The error code is not meaningful from Serialize(). The code needs to be able
// handle a nil byte slice being returned.
