Skip to content

Commit 290344f

Browse files
authored
Merge pull request #967 from ellemouton/sql9Sessions1
[sql-9] sessions: small sql preparations
2 parents df0e867 + 29f6db7 commit 290344f

File tree

5 files changed

+145
-147
lines changed

5 files changed

+145
-147
lines changed

session/db.go

-127
This file was deleted.

session/errors.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package session
2+
3+
import "errors"
4+
5+
var (
6+
// ErrSessionNotFound is an error returned when we attempt to retrieve
7+
// information about a session but it is not found.
8+
ErrSessionNotFound = errors.New("session not found")
9+
)

session/store.go renamed to session/kvdb_store.go

+127-14
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package session
22

33
import (
44
"bytes"
5+
"encoding/binary"
56
"errors"
67
"fmt"
8+
"os"
9+
"path/filepath"
710
"time"
811

912
"github.com/btcsuite/btcd/btcec/v2"
@@ -46,15 +49,125 @@ var (
4649
// IDs associated with the given group ID.
4750
sessionIDKey = []byte("session-id")
4851

49-
// ErrSessionNotFound is an error returned when we attempt to retrieve
50-
// information about a session but it is not found.
51-
ErrSessionNotFound = errors.New("session not found")
52-
5352
// ErrDBInitErr is returned when a bucket that we expect to have been
5453
// set up during DB initialisation is not found.
5554
ErrDBInitErr = errors.New("db did not initialise properly")
55+
56+
// byteOrder is the default byte order we'll use for serialization
57+
// within the database.
58+
byteOrder = binary.BigEndian
59+
)
60+
61+
const (
62+
// DBFilename is the default filename of the session database.
63+
DBFilename = "session.db"
64+
65+
// dbFilePermission is the default permission the session database file
66+
// is created with.
67+
dbFilePermission = 0600
68+
69+
// DefaultSessionDBTimeout is the default maximum time we wait for the
70+
// session bbolt database to be opened. If the database is already
71+
// opened by another process, the unique lock cannot be obtained. With
72+
// the timeout we error out after the given time instead of just
73+
// blocking for forever.
74+
DefaultSessionDBTimeout = 5 * time.Second
5675
)
5776

77+
// BoltStore is a bolt-backed persistent store.
78+
type BoltStore struct {
79+
*bbolt.DB
80+
}
81+
82+
// A compile-time check to ensure that BoltStore implements the Store interface.
83+
var _ Store = (*BoltStore)(nil)
84+
85+
// NewDB creates a new bolt database that can be found at the given directory.
86+
func NewDB(dir, fileName string) (*BoltStore, error) {
87+
firstInit := false
88+
path := filepath.Join(dir, fileName)
89+
90+
// If the database file does not exist yet, create its directory.
91+
if !fileExists(path) {
92+
if err := os.MkdirAll(dir, 0700); err != nil {
93+
return nil, err
94+
}
95+
firstInit = true
96+
}
97+
98+
db, err := initDB(path, firstInit)
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
// Attempt to sync the database's current version with the latest known
104+
// version available.
105+
if err := syncVersions(db); err != nil {
106+
return nil, err
107+
}
108+
109+
return &BoltStore{DB: db}, nil
110+
}
111+
112+
// fileExists reports whether the named file or directory exists.
113+
func fileExists(path string) bool {
114+
if _, err := os.Stat(path); err != nil {
115+
if os.IsNotExist(err) {
116+
return false
117+
}
118+
}
119+
return true
120+
}
121+
122+
// initDB initializes all the required top-level buckets for the database.
123+
func initDB(filepath string, firstInit bool) (*bbolt.DB, error) {
124+
db, err := bbolt.Open(filepath, dbFilePermission, &bbolt.Options{
125+
Timeout: DefaultSessionDBTimeout,
126+
})
127+
if err == bbolt.ErrTimeout {
128+
return nil, fmt.Errorf("error while trying to open %s: timed "+
129+
"out after %v when trying to obtain exclusive lock",
130+
filepath, DefaultSessionDBTimeout)
131+
}
132+
if err != nil {
133+
return nil, err
134+
}
135+
136+
err = db.Update(func(tx *bbolt.Tx) error {
137+
if firstInit {
138+
metadataBucket, err := tx.CreateBucketIfNotExists(
139+
metadataBucketKey,
140+
)
141+
if err != nil {
142+
return err
143+
}
144+
err = setDBVersion(metadataBucket, latestDBVersion)
145+
if err != nil {
146+
return err
147+
}
148+
}
149+
150+
sessionBkt, err := tx.CreateBucketIfNotExists(sessionBucketKey)
151+
if err != nil {
152+
return err
153+
}
154+
155+
_, err = sessionBkt.CreateBucketIfNotExists(idIndexKey)
156+
if err != nil {
157+
return err
158+
}
159+
160+
_, err = sessionBkt.CreateBucketIfNotExists(groupIDIndexKey)
161+
162+
return err
163+
})
164+
if err != nil {
165+
return nil, err
166+
}
167+
168+
return db, nil
169+
}
170+
58171
// getSessionKey returns the key for a session.
59172
func getSessionKey(session *Session) []byte {
60173
return session.LocalPublicKey.SerializeCompressed()
@@ -64,7 +177,7 @@ func getSessionKey(session *Session) []byte {
64177
// local public key already exists an error is returned.
65178
//
66179
// NOTE: this is part of the Store interface.
67-
func (db *DB) CreateSession(session *Session) error {
180+
func (db *BoltStore) CreateSession(session *Session) error {
68181
var buf bytes.Buffer
69182
if err := SerializeSession(&buf, session); err != nil {
70183
return err
@@ -158,7 +271,7 @@ func (db *DB) CreateSession(session *Session) error {
158271
// to the session with the given local pub key.
159272
//
160273
// NOTE: this is part of the Store interface.
161-
func (db *DB) UpdateSessionRemotePubKey(localPubKey,
274+
func (db *BoltStore) UpdateSessionRemotePubKey(localPubKey,
162275
remotePubKey *btcec.PublicKey) error {
163276

164277
key := localPubKey.SerializeCompressed()
@@ -196,7 +309,7 @@ func (db *DB) UpdateSessionRemotePubKey(localPubKey,
196309
// GetSession fetches the session with the given key.
197310
//
198311
// NOTE: this is part of the Store interface.
199-
func (db *DB) GetSession(key *btcec.PublicKey) (*Session, error) {
312+
func (db *BoltStore) GetSession(key *btcec.PublicKey) (*Session, error) {
200313
var session *Session
201314
err := db.View(func(tx *bbolt.Tx) error {
202315
sessionBucket, err := getBucket(tx, sessionBucketKey)
@@ -226,7 +339,7 @@ func (db *DB) GetSession(key *btcec.PublicKey) (*Session, error) {
226339
// ListSessions returns all sessions currently known to the store.
227340
//
228341
// NOTE: this is part of the Store interface.
229-
func (db *DB) ListSessions(filterFn func(s *Session) bool) ([]*Session, error) {
342+
func (db *BoltStore) ListSessions(filterFn func(s *Session) bool) ([]*Session, error) {
230343
var sessions []*Session
231344
err := db.View(func(tx *bbolt.Tx) error {
232345
sessionBucket, err := getBucket(tx, sessionBucketKey)
@@ -266,7 +379,7 @@ func (db *DB) ListSessions(filterFn func(s *Session) bool) ([]*Session, error) {
266379
// public key to be revoked.
267380
//
268381
// NOTE: this is part of the Store interface.
269-
func (db *DB) RevokeSession(key *btcec.PublicKey) error {
382+
func (db *BoltStore) RevokeSession(key *btcec.PublicKey) error {
270383
var session *Session
271384
return db.Update(func(tx *bbolt.Tx) error {
272385
sessionBucket, err := getBucket(tx, sessionBucketKey)
@@ -299,7 +412,7 @@ func (db *DB) RevokeSession(key *btcec.PublicKey) error {
299412
// GetSessionByID fetches the session with the given ID.
300413
//
301414
// NOTE: this is part of the Store interface.
302-
func (db *DB) GetSessionByID(id ID) (*Session, error) {
415+
func (db *BoltStore) GetSessionByID(id ID) (*Session, error) {
303416
var session *Session
304417
err := db.View(func(tx *bbolt.Tx) error {
305418
sessionBucket, err := getBucket(tx, sessionBucketKey)
@@ -337,7 +450,7 @@ func (db *DB) GetSessionByID(id ID) (*Session, error) {
337450
// used or discarded.
338451
//
339452
// NOTE: this is part of the Store interface.
340-
func (db *DB) GetUnusedIDAndKeyPair() (ID, *btcec.PrivateKey, error) {
453+
func (db *BoltStore) GetUnusedIDAndKeyPair() (ID, *btcec.PrivateKey, error) {
341454
var (
342455
id ID
343456
privKey *btcec.PrivateKey
@@ -383,7 +496,7 @@ func (db *DB) GetUnusedIDAndKeyPair() (ID, *btcec.PrivateKey, error) {
383496
// GetGroupID will return the group ID for the given session ID.
384497
//
385498
// NOTE: this is part of the IDToGroupIndex interface.
386-
func (db *DB) GetGroupID(sessionID ID) (ID, error) {
499+
func (db *BoltStore) GetGroupID(sessionID ID) (ID, error) {
387500
var groupID ID
388501
err := db.View(func(tx *bbolt.Tx) error {
389502
sessionBkt, err := getBucket(tx, sessionBucketKey)
@@ -423,7 +536,7 @@ func (db *DB) GetGroupID(sessionID ID) (ID, error) {
423536
// group with the given ID.
424537
//
425538
// NOTE: this is part of the IDToGroupIndex interface.
426-
func (db *DB) GetSessionIDs(groupID ID) ([]ID, error) {
539+
func (db *BoltStore) GetSessionIDs(groupID ID) ([]ID, error) {
427540
var (
428541
sessionIDs []ID
429542
err error
@@ -450,7 +563,7 @@ func (db *DB) GetSessionIDs(groupID ID) ([]ID, error) {
450563
// each session passes.
451564
//
452565
// NOTE: this is part of the Store interface.
453-
func (db *DB) CheckSessionGroupPredicate(groupID ID,
566+
func (db *BoltStore) CheckSessionGroupPredicate(groupID ID,
454567
fn func(s *Session) bool) (bool, error) {
455568

456569
var (

session_rpcserver.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ type sessionRpcServer struct {
5858
// sessionRpcServerConfig holds the values used to configure the
5959
// sessionRpcServer.
6060
type sessionRpcServerConfig struct {
61-
db *session.DB
61+
db session.Store
6262
basicAuth string
6363
grpcOptions []grpc.ServerOption
6464
registerGrpcServers func(server *grpc.Server)
@@ -175,10 +175,6 @@ func (s *sessionRpcServer) start(ctx context.Context) error {
175175
func (s *sessionRpcServer) stop() error {
176176
var returnErr error
177177
s.stopOnce.Do(func() {
178-
if err := s.cfg.db.Close(); err != nil {
179-
log.Errorf("Error closing session DB: %v", err)
180-
returnErr = err
181-
}
182178
s.sessionServer.Stop()
183179

184180
close(s.quit)

0 commit comments

Comments
 (0)