Skip to content

Commit

Permalink
move session store to storage.SessionDatabase (#2475)
Browse files Browse the repository at this point in the history
  • Loading branch information
woutslakhorst authored Oct 3, 2023
1 parent 7ab8356 commit f979467
Show file tree
Hide file tree
Showing 17 changed files with 676 additions and 317 deletions.
4 changes: 1 addition & 3 deletions network/dag/consistency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ import (
)

func TestXorTreeRepair(t *testing.T) {
t.Cleanup(func() {
goleak.VerifyNone(t)
})
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

tx, _, _ := CreateTestTransaction(1)
t.Run("xor tree repaired after 2 signals", func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion network/transport/grpc/connection_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func Test_grpcConnectionManager_hasActiveConnection(t *testing.T) {

func Test_grpcConnectionManager_dialerLoop(t *testing.T) {
// make sure connectLoop only returns after all of its goroutines are closed
defer goleak.VerifyNone(t)
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

targetAddress := "bootstrap"
var capturedAddress string
Expand Down
2 changes: 1 addition & 1 deletion network/transport/v2/gossip/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func TestManager_PeerDisconnected(t *testing.T) {

t.Run("stops ticker", func(t *testing.T) {
// Use uber/goleak to assert the goroutine started by PeerConnected is stopped when PeerDisconnected is called
defer goleak.VerifyNone(t)
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

gMan := giveMeAgMan(t)
gMan.interval = time.Millisecond
Expand Down
2 changes: 1 addition & 1 deletion network/transport/v2/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func TestProtocol_Start(t *testing.T) {

func TestProtocol_Stop(t *testing.T) {
t.Run("waits until goroutines have finished", func(t *testing.T) {
defer goleak.VerifyNone(t)
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

// Use waitgroup to make sure the goroutine that blocks has started
wg := &sync.WaitGroup{}
Expand Down
4 changes: 1 addition & 3 deletions network/transport/v2/transactionlist_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ import (
)

func TestTransactionListHandler(t *testing.T) {
t.Cleanup(func() {
goleak.VerifyNone(t)
})
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

t.Run("fn is called", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
Expand Down
2 changes: 1 addition & 1 deletion pki/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ var crlPathMap = map[string]string{
}

func TestValidator_Start(t *testing.T) {
defer goleak.VerifyNone(t)
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())
store, err := core.LoadTrustStore(truststorePKIo)
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
Expand Down
25 changes: 18 additions & 7 deletions storage/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,19 @@ const storeShutdownTimeout = 5 * time.Second
// New creates a new instance of the storage engine.
func New() Engine {
return &engine{
storesMux: &sync.Mutex{},
stores: map[string]stoabs.Store{},
storesMux: &sync.Mutex{},
stores: map[string]stoabs.Store{},
sessionDatabase: NewInMemorySessionDatabase(),
}
}

type engine struct {
datadir string
storesMux *sync.Mutex
stores map[string]stoabs.Store
databases []database
config Config
datadir string
storesMux *sync.Mutex
stores map[string]stoabs.Store
databases []database
sessionDatabase SessionDatabase
config Config
}

func (e *engine) Config() interface{} {
Expand Down Expand Up @@ -84,9 +86,13 @@ func (e engine) Shutdown() error {
failures = true
}
}

if failures {
return errors.New("one or more stores failed to close")
}

e.sessionDatabase.close()

return nil
}

Expand All @@ -108,6 +114,7 @@ func (e *engine) Configure(config core.ServerConfig) error {
return fmt.Errorf("unable to configure BBolt database: %w", err)
}
e.databases = append(e.databases, bboltDB)

return nil
}

Expand All @@ -118,6 +125,10 @@ func (e *engine) GetProvider(moduleName string) Provider {
}
}

func (e *engine) GetSessionDatabase() SessionDatabase {
return e.sessionDatabase
}

type provider struct {
moduleName string
engine *engine
Expand Down
32 changes: 32 additions & 0 deletions storage/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package storage

import (
"errors"
"github.com/nuts-foundation/go-stoabs"
"github.com/nuts-foundation/nuts-node/core"
"time"
Expand All @@ -34,6 +35,8 @@ type Engine interface {

// GetProvider returns the Provider for the given module.
GetProvider(moduleName string) Provider
// GetSessionDatabase returns the SessionDatabase
GetSessionDatabase() SessionDatabase
}

// Provider lets callers get access to stores.
Expand All @@ -59,3 +62,32 @@ type database interface {
getClass() Class
close()
}

var ErrNotFound = errors.New("not found")

// SessionDatabase is a non-persistent database that holds session data on a KV basis.
// Keys could be access tokens, nonce's, authorization codes, etc.
// All entries are stored with a TTL, so they will be removed automatically.
type SessionDatabase interface {
// GetStore returns a SessionStore with the given keys as key prefixes.
// The keys are used to logically partition the store, eg: tenants and/or flows that are not allowed to overlap like credential issuance and verification.
// The TTL is the time-to-live for the entries in the store.
GetStore(ttl time.Duration, keys ...string) SessionStore
// close stops any background processes and closes the database.
close()
}

// SessionStore is a key-value store that holds session data.
// The SessionStore is an abstraction for underlying storage, it automatically adds prefixes for logical partitions.
type SessionStore interface {
// Delete deletes the entry for the given key.
// It does not return an error if the key does not exist.
Delete(key string) error
// Exists returns true if the key exists.
Exists(key string) bool
// Get returns the value for the given key.
// Returns ErrNotFound if the key does not exist.
Get(key string, target interface{}) error
// Put stores the given value for the given key.
Put(key string, value interface{}) error
}
148 changes: 148 additions & 0 deletions storage/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f979467

Please sign in to comment.