From 889af91faa82bb03216809b3d32cf1b5368a5f65 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Tue, 29 Aug 2023 21:53:02 +0200 Subject: [PATCH 01/22] wip --- integration/commands_diagnostic_test.go | 8 +- internal/handlers/sqlite/msg_getlog.go | 134 +++++++++++++++++++++++- 2 files changed, 136 insertions(+), 6 deletions(-) diff --git a/integration/commands_diagnostic_test.go b/integration/commands_diagnostic_test.go index f49768b77b03..c03a278b1c9f 100644 --- a/integration/commands_diagnostic_test.go +++ b/integration/commands_diagnostic_test.go @@ -186,14 +186,12 @@ func TestCommandsDiagnosticGetLog(t *testing.T) { }, } { name, tc := name, tc - t.Run(name, func(tt *testing.T) { + t.Run(name, func(t *testing.T) { if tc.skip != "" { - tt.Skip(tc.skip) + t.Skip(tc.skip) } - tt.Parallel() - - t := setup.FailsForSQLite(tt, "https://github.com/FerretDB/FerretDB/issues/3261") + t.Parallel() require.NotNil(t, tc.command, "command must not be nil") diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index b5854cca1533..9653ed0136b3 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -16,12 +16,144 @@ package sqlite import ( "context" + "encoding/json" + "fmt" + "strings" + "time" + "go.uber.org/zap" + + "github.com/FerretDB/FerretDB/build/version" + "github.com/FerretDB/FerretDB/internal/handlers/commonerrors" + "github.com/FerretDB/FerretDB/internal/handlers/commonparams" + "github.com/FerretDB/FerretDB/internal/types" + "github.com/FerretDB/FerretDB/internal/util/lazyerrors" + "github.com/FerretDB/FerretDB/internal/util/logging" "github.com/FerretDB/FerretDB/internal/util/must" "github.com/FerretDB/FerretDB/internal/wire" ) // MsgGetLog implements HandlerInterface. func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, error) { - return nil, notImplemented(must.NotFail(msg.Document()).Command()) + document, err := msg.Document() + if err != nil { + return nil, lazyerrors.Error(err) + } + + command := document.Command() + + getLog, err := document.Get(command) + if err != nil { + return nil, lazyerrors.Error(err) + } + + if _, ok := getLog.(types.NullType); ok { + return nil, commonerrors.NewCommandErrorMsg( + commonerrors.ErrMissingField, + `BSON field 'getLog.getLog' is missing but a required field`, + ) + } + + if _, ok := getLog.(string); !ok { + return nil, commonerrors.NewCommandError( + commonerrors.ErrTypeMismatch, + fmt.Errorf( + "BSON field 'getLog.getLog' is the wrong type '%s', expected type 'string'", + commonparams.AliasFromType(getLog), + ), + ) + } + + var resDoc *types.Document + + switch getLog { + case "*": + resDoc = must.NotFail(types.NewDocument( + "names", must.NotFail(types.NewArray("global", "startupWarnings")), + "ok", float64(1), + )) + + case "global": + log, err := logging.RecentEntries.GetArray(zap.DebugLevel) + if err != nil { + return nil, lazyerrors.Error(err) + } + resDoc = must.NotFail(types.NewDocument( + "log", log, + "totalLinesWritten", int64(log.Len()), + "ok", float64(1), + )) + + case "startupWarnings": + state := h.StateProvider.Get() + + info := version.Get() + + // it may be empty if no connection was established yet + hv, _, _ := strings.Cut(state.HandlerVersion, " ") + if hv != "" { + hv = " " + hv + } + + startupWarnings := []string{ + "Powered by FerretDB " + info.Version + " and PostgreSQL" + hv + ".", + "Please star us on GitHub: https://github.com/FerretDB/FerretDB.", + } + + switch { + case state.Telemetry == nil: + startupWarnings = append( + startupWarnings, + "The telemetry state is undecided.", + "Read more about FerretDB telemetry and how to opt out at https://beacon.ferretdb.io.", + ) + case state.UpdateAvailable: + startupWarnings = append( + startupWarnings, + fmt.Sprintf( + "A new version available! The latest version: %s. The current version: %s.", + state.LatestVersion, info.Version, + ), + ) + } + + var log types.Array + + for _, line := range startupWarnings { + b, err := json.Marshal(map[string]any{ + "msg": line, + "tags": []string{"startupWarnings"}, + "s": "I", + "c": "STORAGE", + "id": 42000, + "ctx": "initandlisten", + "t": map[string]string{ + "$date": time.Now().UTC().Format("2006-01-02T15:04:05.999Z07:00"), + }, + }) + if err != nil { + return nil, lazyerrors.Error(err) + } + + log.Append(string(b)) + } + resDoc = must.NotFail(types.NewDocument( + "log", &log, + "totalLinesWritten", int64(log.Len()), + "ok", float64(1), + )) + + default: + return nil, commonerrors.NewCommandError( + commonerrors.ErrOperationFailed, + fmt.Errorf("no RecentEntries named: %s", getLog), + ) + } + + var reply wire.OpMsg + must.NoError(reply.SetSections(wire.OpMsgSection{ + Documents: []*types.Document{resDoc}, + })) + + return &reply, nil } From ffd5e29df901a33e7059ce59dfeb67385c5f5442 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Tue, 29 Aug 2023 21:57:13 +0200 Subject: [PATCH 02/22] wip --- internal/handlers/sqlite/msg_getlog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index 9653ed0136b3..238c67a5c4d1 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -96,7 +96,7 @@ func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, } startupWarnings := []string{ - "Powered by FerretDB " + info.Version + " and PostgreSQL" + hv + ".", + "Powered by FerretDB " + info.Version + " and SQLite" + hv + ".", "Please star us on GitHub: https://github.com/FerretDB/FerretDB.", } From f00dc3ba4f5e8b97a36ab9036a27c12c3eae3ec2 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 09:22:17 +0200 Subject: [PATCH 03/22] no handler version for SQLite --- internal/handlers/sqlite/msg_getlog.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index 238c67a5c4d1..6aea92293f18 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "fmt" - "strings" "time" "go.uber.org/zap" @@ -89,14 +88,8 @@ func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, info := version.Get() - // it may be empty if no connection was established yet - hv, _, _ := strings.Cut(state.HandlerVersion, " ") - if hv != "" { - hv = " " + hv - } - startupWarnings := []string{ - "Powered by FerretDB " + info.Version + " and SQLite" + hv + ".", + "Powered by FerretDB " + info.Version + " and SQLite.", "Please star us on GitHub: https://github.com/FerretDB/FerretDB.", } From cb69450b7f6d9c0d49d22708e350cabc5a6fb276 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 12:54:13 +0200 Subject: [PATCH 04/22] wip --- internal/backends/backend.go | 13 ++++++++++++ internal/backends/postgresql/backend.go | 21 +++++++++++++++---- internal/backends/sqlite/backend.go | 19 +++++++++++++---- internal/handlers/registry/newpg.go | 2 +- internal/handlers/registry/sqlite.go | 2 +- internal/handlers/sqlite/msg_getlog.go | 3 ++- internal/handlers/sqlite/sqlite.go | 28 ++++++++++++++++++------- 7 files changed, 70 insertions(+), 18 deletions(-) diff --git a/internal/backends/backend.go b/internal/backends/backend.go index 850d4d1c677b..7a00300203b9 100644 --- a/internal/backends/backend.go +++ b/internal/backends/backend.go @@ -38,12 +38,20 @@ type Backend interface { ListDatabases(context.Context, *ListDatabasesParams) (*ListDatabasesResult, error) DropDatabase(context.Context, *DropDatabaseParams) error + Info() *Info + prometheus.Collector // There is no interface method to create a database; see package documentation. // TODO https://github.com/FerretDB/FerretDB/issues/3069 } +// Info represents information about a backend. +type Info struct { + Name string + Version string +} + // backendContract implements Backend interface. type backendContract struct { b Backend @@ -132,6 +140,11 @@ func (bc *backendContract) DropDatabase(ctx context.Context, params *DropDatabas return err } +// Info returns information about the backend. +func (bc *backendContract) Info() *Info { + return bc.b.Info() +} + // Describe implements prometheus.Collector. func (bc *backendContract) Describe(ch chan<- *prometheus.Desc) { bc.b.Describe(ch) diff --git a/internal/backends/postgresql/backend.go b/internal/backends/postgresql/backend.go index cc3181253540..31db075e53ad 100644 --- a/internal/backends/postgresql/backend.go +++ b/internal/backends/postgresql/backend.go @@ -24,19 +24,24 @@ import ( ) // backend implements backends.Backend interface. -type backend struct{} +type backend struct { + version string +} // NewBackendParams represents the parameters of NewBackend function. // //nolint:vet // for readability type NewBackendParams struct { - URI string - L *zap.Logger + URI string + L *zap.Logger + Version string } // NewBackend creates a new backend for PostgreSQL-compatible database. func NewBackend(params *NewBackendParams) (backends.Backend, error) { - return backends.BackendContract(new(backend)), nil + return backends.BackendContract(&backend{ + version: params.Version, + }), nil } // Close implements backends.Backend interface. @@ -60,6 +65,14 @@ func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabas panic("not implemented") } +// Info implements backends.Backend interface. +func (b *backend) Info() *backends.Info { + return &backends.Info{ + Name: "PostgreSQL", + Version: b.version, + } +} + // Describe implements prometheus.Collector. func (b *backend) Describe(ch chan<- *prometheus.Desc) { panic("not implemented") diff --git a/internal/backends/sqlite/backend.go b/internal/backends/sqlite/backend.go index afacce1e2b73..98004f478b21 100644 --- a/internal/backends/sqlite/backend.go +++ b/internal/backends/sqlite/backend.go @@ -26,15 +26,17 @@ import ( // backend implements backends.Backend interface. type backend struct { - r *metadata.Registry + r *metadata.Registry + version string // FIXME: set when connect? } // NewBackendParams represents the parameters of NewBackend function. // //nolint:vet // for readability type NewBackendParams struct { - URI string - L *zap.Logger + URI string + L *zap.Logger + Version string } // NewBackend creates a new SQLite backend. @@ -45,7 +47,8 @@ func NewBackend(params *NewBackendParams) (backends.Backend, error) { } return backends.BackendContract(&backend{ - r: r, + r: r, + version: params.Version, }), nil } @@ -84,6 +87,14 @@ func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabas return nil } +// Info implements backends.Backend interface. +func (b *backend) Info() *backends.Info { + return &backends.Info{ + Name: "SQLite", + Version: b.version, + } +} + // Describe implements prometheus.Collector. func (b *backend) Describe(ch chan<- *prometheus.Desc) { b.r.Describe(ch) diff --git a/internal/handlers/registry/newpg.go b/internal/handlers/registry/newpg.go index 31b470c2c1d3..b6e3f5feaf97 100644 --- a/internal/handlers/registry/newpg.go +++ b/internal/handlers/registry/newpg.go @@ -27,7 +27,7 @@ func init() { opts.Logger.Warn("New PostgreSQL backend is in alpha.") handlerOpts := &sqlite.NewOpts{ - Backend: "postgresql", + Backend: sqlite.PostgreSQL, URI: opts.PostgreSQLURL, L: opts.Logger.Named("postgresql"), diff --git a/internal/handlers/registry/sqlite.go b/internal/handlers/registry/sqlite.go index 2ebb97299e22..c1bbbaaed43c 100644 --- a/internal/handlers/registry/sqlite.go +++ b/internal/handlers/registry/sqlite.go @@ -25,7 +25,7 @@ func init() { opts.Logger.Warn("SQLite backend is in beta.") handlerOpts := &sqlite.NewOpts{ - Backend: "sqlite", + Backend: sqlite.SQLite, URI: opts.SQLiteURL, L: opts.Logger.Named("sqlite"), diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index 6aea92293f18..abcd0495623d 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -87,9 +87,10 @@ func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, state := h.StateProvider.Get() info := version.Get() + backend := h.b.Info() startupWarnings := []string{ - "Powered by FerretDB " + info.Version + " and SQLite.", + fmt.Sprintf("Powered by FerretDB %s and %s %s.", info.Version, backend.Name, backend.Version), "Please star us on GitHub: https://github.com/FerretDB/FerretDB.", } diff --git a/internal/handlers/sqlite/sqlite.go b/internal/handlers/sqlite/sqlite.go index 0e2486f712bf..03bde253f953 100644 --- a/internal/handlers/sqlite/sqlite.go +++ b/internal/handlers/sqlite/sqlite.go @@ -48,12 +48,24 @@ type Handler struct { cursors *cursor.Registry } +// Backend represents backend type. +type Backend string + +const ( + // PostgreSQL represents PostgreSQL backend. + PostgreSQL Backend = "postgresql" + + // SQLite represents SQLite backend. + SQLite Backend = "sqlite" +) + // NewOpts represents handler configuration. // //nolint:vet // for readability type NewOpts struct { - Backend string + Backend Backend URI string + Version string L *zap.Logger ConnMetrics *connmetrics.ConnMetrics @@ -69,15 +81,17 @@ func New(opts *NewOpts) (handlers.Interface, error) { var err error switch opts.Backend { - case "postgresql": + case PostgreSQL: b, err = postgresql.NewBackend(&postgresql.NewBackendParams{ - URI: opts.URI, - L: opts.L, + URI: opts.URI, + L: opts.L, + Version: opts.Version, }) - case "sqlite": + case SQLite: b, err = sqlite.NewBackend(&sqlite.NewBackendParams{ - URI: opts.URI, - L: opts.L, + URI: opts.URI, + L: opts.L, + Version: opts.Version, }) default: panic("unknown backend: " + opts.Backend) From 6b13139233d82bbdcca6da4ac7f784d8e5eadb54 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 15:23:15 +0200 Subject: [PATCH 05/22] wip --- internal/backends/postgresql/backend.go | 5 +-- internal/backends/sqlite/backend.go | 11 +++---- internal/backends/sqlite/metadata/registry.go | 31 ++++++++++++++++--- .../backends/sqlite/metadata/registry_test.go | 12 ++++--- internal/handlers/registry/sqlite.go | 2 +- internal/handlers/sqlite/sqlite.go | 28 +++++------------ 6 files changed, 48 insertions(+), 41 deletions(-) diff --git a/internal/backends/postgresql/backend.go b/internal/backends/postgresql/backend.go index 31db075e53ad..c1369b5d77e4 100644 --- a/internal/backends/postgresql/backend.go +++ b/internal/backends/postgresql/backend.go @@ -67,10 +67,7 @@ func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabas // Info implements backends.Backend interface. func (b *backend) Info() *backends.Info { - return &backends.Info{ - Name: "PostgreSQL", - Version: b.version, - } + panic("not implemented") } // Describe implements prometheus.Collector. diff --git a/internal/backends/sqlite/backend.go b/internal/backends/sqlite/backend.go index 98004f478b21..6481dfa6c23d 100644 --- a/internal/backends/sqlite/backend.go +++ b/internal/backends/sqlite/backend.go @@ -27,28 +27,27 @@ import ( // backend implements backends.Backend interface. type backend struct { r *metadata.Registry - version string // FIXME: set when connect? + version string } // NewBackendParams represents the parameters of NewBackend function. // //nolint:vet // for readability type NewBackendParams struct { - URI string - L *zap.Logger - Version string + URI string + L *zap.Logger } // NewBackend creates a new SQLite backend. func NewBackend(params *NewBackendParams) (backends.Backend, error) { - r, err := metadata.NewRegistry(params.URI, params.L) + r, version, err := metadata.NewRegistry(params.URI, params.L) if err != nil { return nil, err } return backends.BackendContract(&backend{ r: r, - version: params.Version, + version: version, }), nil } diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index 781ea3f04d5f..802610fec987 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -65,10 +65,12 @@ type Registry struct { } // NewRegistry creates a registry for SQLite databases in the directory specified by SQLite URI. -func NewRegistry(u string, l *zap.Logger) (*Registry, error) { +// +// As the second return value, it returns the version of SQLite. +func NewRegistry(u string, l *zap.Logger) (*Registry, string, error) { p, initDBs, err := pool.New(u, l) if err != nil { - return nil, err + return nil, "", err } r := &Registry{ @@ -77,14 +79,35 @@ func NewRegistry(u string, l *zap.Logger) (*Registry, error) { colls: map[string]map[string]*Collection{}, } + var ver string for name, db := range initDBs { if err = r.initCollections(context.Background(), name, db); err != nil { r.Close() - return nil, lazyerrors.Error(err) + return nil, "", lazyerrors.Error(err) + } + + // query version for the first DB only + if ver == "" { + if ver, err = version(db); err != nil { + r.Close() + return nil, "", lazyerrors.Error(err) + } } } - return r, nil + return r, ver, nil +} + +// version returns SQLite version. +func version(db *fsql.DB) (string, error) { + row := db.QueryRowContext(context.Background(), "SELECT sqlite_version()") + + var version string + if err := row.Scan(&version); err != nil { + return "", lazyerrors.Error(err) + } + + return version, nil } // Close closes the registry. diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index dc5ac4a3739d..856e1cbb2de4 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -71,8 +71,10 @@ func TestCreateDrop(t *testing.T) { t.Parallel() ctx := testutil.Ctx(t) - r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t)) + r, version, err := NewRegistry("file:./?mode=memory", testutil.Logger(t)) require.NoError(t, err) + require.Equal(t, "3.35.5", version) + t.Cleanup(r.Close) dbName := t.Name() @@ -100,7 +102,7 @@ func TestCreateDropStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, _, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) @@ -139,7 +141,7 @@ func TestCreateSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, _, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) @@ -203,7 +205,7 @@ func TestDropSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, _, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) @@ -252,7 +254,7 @@ func TestCreateDropSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, _, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) diff --git a/internal/handlers/registry/sqlite.go b/internal/handlers/registry/sqlite.go index c1bbbaaed43c..2ebb97299e22 100644 --- a/internal/handlers/registry/sqlite.go +++ b/internal/handlers/registry/sqlite.go @@ -25,7 +25,7 @@ func init() { opts.Logger.Warn("SQLite backend is in beta.") handlerOpts := &sqlite.NewOpts{ - Backend: sqlite.SQLite, + Backend: "sqlite", URI: opts.SQLiteURL, L: opts.Logger.Named("sqlite"), diff --git a/internal/handlers/sqlite/sqlite.go b/internal/handlers/sqlite/sqlite.go index 03bde253f953..0e2486f712bf 100644 --- a/internal/handlers/sqlite/sqlite.go +++ b/internal/handlers/sqlite/sqlite.go @@ -48,24 +48,12 @@ type Handler struct { cursors *cursor.Registry } -// Backend represents backend type. -type Backend string - -const ( - // PostgreSQL represents PostgreSQL backend. - PostgreSQL Backend = "postgresql" - - // SQLite represents SQLite backend. - SQLite Backend = "sqlite" -) - // NewOpts represents handler configuration. // //nolint:vet // for readability type NewOpts struct { - Backend Backend + Backend string URI string - Version string L *zap.Logger ConnMetrics *connmetrics.ConnMetrics @@ -81,17 +69,15 @@ func New(opts *NewOpts) (handlers.Interface, error) { var err error switch opts.Backend { - case PostgreSQL: + case "postgresql": b, err = postgresql.NewBackend(&postgresql.NewBackendParams{ - URI: opts.URI, - L: opts.L, - Version: opts.Version, + URI: opts.URI, + L: opts.L, }) - case SQLite: + case "sqlite": b, err = sqlite.NewBackend(&sqlite.NewBackendParams{ - URI: opts.URI, - L: opts.L, - Version: opts.Version, + URI: opts.URI, + L: opts.L, }) default: panic("unknown backend: " + opts.Backend) From 9e7c7a2b4c11504f72ecb7571aa83e94ca975734 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 15:55:52 +0200 Subject: [PATCH 06/22] wip --- internal/backends/backend.go | 8 ++-- internal/backends/postgresql/backend.go | 15 +++---- internal/backends/sqlite/backend.go | 20 +++++---- .../backends/sqlite/metadata/pool/pool.go | 17 +++++++ internal/backends/sqlite/metadata/registry.go | 45 ++++++++----------- .../backends/sqlite/metadata/registry_test.go | 12 +++-- internal/handlers/sqlite/msg_getlog.go | 6 ++- 7 files changed, 66 insertions(+), 57 deletions(-) diff --git a/internal/backends/backend.go b/internal/backends/backend.go index 7a00300203b9..34edfae2adf4 100644 --- a/internal/backends/backend.go +++ b/internal/backends/backend.go @@ -38,7 +38,7 @@ type Backend interface { ListDatabases(context.Context, *ListDatabasesParams) (*ListDatabasesResult, error) DropDatabase(context.Context, *DropDatabaseParams) error - Info() *Info + Info(context.Context) (*Info, error) prometheus.Collector @@ -49,7 +49,7 @@ type Backend interface { // Info represents information about a backend. type Info struct { Name string - Version string + Version string // can be empty if the pool is not initialized yet } // backendContract implements Backend interface. @@ -141,8 +141,8 @@ func (bc *backendContract) DropDatabase(ctx context.Context, params *DropDatabas } // Info returns information about the backend. -func (bc *backendContract) Info() *Info { - return bc.b.Info() +func (bc *backendContract) Info(ctx context.Context) (*Info, error) { + return bc.b.Info(ctx) } // Describe implements prometheus.Collector. diff --git a/internal/backends/postgresql/backend.go b/internal/backends/postgresql/backend.go index c1369b5d77e4..3d5305a6f22e 100644 --- a/internal/backends/postgresql/backend.go +++ b/internal/backends/postgresql/backend.go @@ -24,24 +24,19 @@ import ( ) // backend implements backends.Backend interface. -type backend struct { - version string -} +type backend struct{} // NewBackendParams represents the parameters of NewBackend function. // //nolint:vet // for readability type NewBackendParams struct { - URI string - L *zap.Logger - Version string + URI string + L *zap.Logger } // NewBackend creates a new backend for PostgreSQL-compatible database. func NewBackend(params *NewBackendParams) (backends.Backend, error) { - return backends.BackendContract(&backend{ - version: params.Version, - }), nil + return backends.BackendContract(&backend{}), nil } // Close implements backends.Backend interface. @@ -66,7 +61,7 @@ func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabas } // Info implements backends.Backend interface. -func (b *backend) Info() *backends.Info { +func (b *backend) Info(ctx context.Context) (*backends.Info, error) { panic("not implemented") } diff --git a/internal/backends/sqlite/backend.go b/internal/backends/sqlite/backend.go index 6481dfa6c23d..71ba38299e44 100644 --- a/internal/backends/sqlite/backend.go +++ b/internal/backends/sqlite/backend.go @@ -22,12 +22,12 @@ import ( "github.com/FerretDB/FerretDB/internal/backends" "github.com/FerretDB/FerretDB/internal/backends/sqlite/metadata" + "github.com/FerretDB/FerretDB/internal/util/lazyerrors" ) // backend implements backends.Backend interface. type backend struct { - r *metadata.Registry - version string + r *metadata.Registry } // NewBackendParams represents the parameters of NewBackend function. @@ -40,14 +40,13 @@ type NewBackendParams struct { // NewBackend creates a new SQLite backend. func NewBackend(params *NewBackendParams) (backends.Backend, error) { - r, version, err := metadata.NewRegistry(params.URI, params.L) + r, err := metadata.NewRegistry(params.URI, params.L) if err != nil { return nil, err } return backends.BackendContract(&backend{ - r: r, - version: version, + r: r, }), nil } @@ -87,11 +86,16 @@ func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabas } // Info implements backends.Backend interface. -func (b *backend) Info() *backends.Info { +func (b *backend) Info(ctx context.Context) (*backends.Info, error) { + version, err := b.r.Version(ctx) + if err != nil { + return nil, lazyerrors.Error(err) + } + return &backends.Info{ Name: "SQLite", - Version: b.version, - } + Version: version, + }, nil } // Describe implements prometheus.Collector. diff --git a/internal/backends/sqlite/metadata/pool/pool.go b/internal/backends/sqlite/metadata/pool/pool.go index e6ece43f3192..4a45cb13ee97 100644 --- a/internal/backends/sqlite/metadata/pool/pool.go +++ b/internal/backends/sqlite/metadata/pool/pool.go @@ -213,6 +213,23 @@ func (p *Pool) GetExisting(ctx context.Context, name string) *fsql.DB { return db } +// GetFirst returns a database from the pool, or nil if there are no databases in the pool. +// +// As the pool is not ordered, the returned database is not guaranteed to be the same. +// This method can be used when a DB-agnostic query is needed. +func (p *Pool) GetFirst(ctx context.Context) *fsql.DB { + defer observability.FuncCall(ctx)() + + p.rw.RLock() + defer p.rw.RUnlock() + + for _, db := range p.dbs { + return db + } + + return nil +} + // GetOrCreate returns an existing database by valid name, or creates a new one. // // Returned boolean value indicates whether the database was created. diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index 802610fec987..18124666fc58 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -65,12 +65,10 @@ type Registry struct { } // NewRegistry creates a registry for SQLite databases in the directory specified by SQLite URI. -// -// As the second return value, it returns the version of SQLite. -func NewRegistry(u string, l *zap.Logger) (*Registry, string, error) { +func NewRegistry(u string, l *zap.Logger) (*Registry, error) { p, initDBs, err := pool.New(u, l) if err != nil { - return nil, "", err + return nil, err } r := &Registry{ @@ -79,35 +77,14 @@ func NewRegistry(u string, l *zap.Logger) (*Registry, string, error) { colls: map[string]map[string]*Collection{}, } - var ver string for name, db := range initDBs { if err = r.initCollections(context.Background(), name, db); err != nil { r.Close() - return nil, "", lazyerrors.Error(err) - } - - // query version for the first DB only - if ver == "" { - if ver, err = version(db); err != nil { - r.Close() - return nil, "", lazyerrors.Error(err) - } + return nil, lazyerrors.Error(err) } } - return r, ver, nil -} - -// version returns SQLite version. -func version(db *fsql.DB) (string, error) { - row := db.QueryRowContext(context.Background(), "SELECT sqlite_version()") - - var version string - if err := row.Scan(&version); err != nil { - return "", lazyerrors.Error(err) - } - - return version, nil + return r, nil } // Close closes the registry. @@ -375,6 +352,20 @@ func (r *Registry) CollectionRename(ctx context.Context, dbName, oldCollectionNa panic("not implemented") } +// Version returns SQLite version. +// +// If there are no databases in the registry, empty string is returned. +func (r *Registry) Version(ctx context.Context) (string, error) { + row := r.p.GetFirst(ctx).QueryRowContext(context.Background(), "SELECT sqlite_version()") + + var version string + if err := row.Scan(&version); err != nil { + return "", lazyerrors.Error(err) + } + + return version, nil +} + // Describe implements prometheus.Collector. func (r *Registry) Describe(ch chan<- *prometheus.Desc) { prometheus.DescribeByCollect(r, ch) diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index 856e1cbb2de4..dc5ac4a3739d 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -71,10 +71,8 @@ func TestCreateDrop(t *testing.T) { t.Parallel() ctx := testutil.Ctx(t) - r, version, err := NewRegistry("file:./?mode=memory", testutil.Logger(t)) + r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t)) require.NoError(t, err) - require.Equal(t, "3.35.5", version) - t.Cleanup(r.Close) dbName := t.Name() @@ -102,7 +100,7 @@ func TestCreateDropStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, _, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) @@ -141,7 +139,7 @@ func TestCreateSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, _, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) @@ -205,7 +203,7 @@ func TestDropSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, _, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) @@ -254,7 +252,7 @@ func TestCreateDropSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, _, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t)) require.NoError(t, err) t.Cleanup(r.Close) diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index abcd0495623d..247093612d19 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -87,7 +87,11 @@ func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, state := h.StateProvider.Get() info := version.Get() - backend := h.b.Info() + + backend, err := h.b.Info(ctx) + if err != nil { + return nil, lazyerrors.Error(err) + } startupWarnings := []string{ fmt.Sprintf("Powered by FerretDB %s and %s %s.", info.Version, backend.Name, backend.Version), From 2e085613ff4c1a959a2cf78241f9ccf06aa2d650 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 16:01:06 +0200 Subject: [PATCH 07/22] wip --- internal/backends/postgresql/backend.go | 2 +- internal/handlers/registry/newpg.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/backends/postgresql/backend.go b/internal/backends/postgresql/backend.go index 3d5305a6f22e..14b38e2bd134 100644 --- a/internal/backends/postgresql/backend.go +++ b/internal/backends/postgresql/backend.go @@ -36,7 +36,7 @@ type NewBackendParams struct { // NewBackend creates a new backend for PostgreSQL-compatible database. func NewBackend(params *NewBackendParams) (backends.Backend, error) { - return backends.BackendContract(&backend{}), nil + return backends.BackendContract(new(backend)), nil } // Close implements backends.Backend interface. diff --git a/internal/handlers/registry/newpg.go b/internal/handlers/registry/newpg.go index b6e3f5feaf97..31b470c2c1d3 100644 --- a/internal/handlers/registry/newpg.go +++ b/internal/handlers/registry/newpg.go @@ -27,7 +27,7 @@ func init() { opts.Logger.Warn("New PostgreSQL backend is in alpha.") handlerOpts := &sqlite.NewOpts{ - Backend: sqlite.PostgreSQL, + Backend: "postgresql", URI: opts.PostgreSQLURL, L: opts.Logger.Named("postgresql"), From 2f87c9f2776aaffa223dc85e8f703d99d33daf71 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 16:12:06 +0200 Subject: [PATCH 08/22] wip --- internal/handlers/pg/pgdb/pool.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/handlers/pg/pgdb/pool.go b/internal/handlers/pg/pgdb/pool.go index 1dfa66153ebd..07e26d01f17a 100644 --- a/internal/handlers/pg/pgdb/pool.go +++ b/internal/handlers/pg/pgdb/pool.go @@ -69,6 +69,9 @@ func NewPool(ctx context.Context, uri string, logger *zap.Logger, p *state.Provi return lazyerrors.Error(err) } + // After moving pg to the new architecture, we should stop storing the version in the state, + // but use backend.Info instead. + // TODO https://github.com/FerretDB/FerretDB/issues/3228 if err := p.Update(func(s *state.State) { s.HandlerVersion = v }); err != nil { logger.Error("pgdb.Pool.AfterConnect: failed to update state", zap.Error(err)) } From dfadf3c9e49c7a937be7150ea24a73373d361b8f Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 16:14:57 +0200 Subject: [PATCH 09/22] wip --- internal/handlers/sqlite/msg_getlog.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index 247093612d19..93faa9e48448 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -93,8 +93,12 @@ func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, return nil, lazyerrors.Error(err) } + if backend.Version != "" { + backend.Version = " " + backend.Version // to format startup warnings + } + startupWarnings := []string{ - fmt.Sprintf("Powered by FerretDB %s and %s %s.", info.Version, backend.Name, backend.Version), + fmt.Sprintf("Powered by FerretDB %s and %s%s.", info.Version, backend.Name, backend.Version), "Please star us on GitHub: https://github.com/FerretDB/FerretDB.", } From ae36e38d9489fea480c4367c987d7fff0cc9f2a8 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Wed, 30 Aug 2023 16:18:38 +0200 Subject: [PATCH 10/22] wip --- internal/backends/sqlite/metadata/registry.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index 18124666fc58..03c0830bca2d 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -55,6 +55,8 @@ type Registry struct { p *pool.Pool l *zap.Logger + version string // SQLite version + // rw protects colls but also acts like a global lock for the whole registry. // The latter effectively replaces transactions (see the sqlite backend description for more info). // One global lock should be replaced by more granular locks – one per database or even one per collection. @@ -356,14 +358,17 @@ func (r *Registry) CollectionRename(ctx context.Context, dbName, oldCollectionNa // // If there are no databases in the registry, empty string is returned. func (r *Registry) Version(ctx context.Context) (string, error) { + if r.version != "" { + return r.version, nil + } + row := r.p.GetFirst(ctx).QueryRowContext(context.Background(), "SELECT sqlite_version()") - var version string - if err := row.Scan(&version); err != nil { + if err := row.Scan(&r.version); err != nil { return "", lazyerrors.Error(err) } - return version, nil + return r.version, nil } // Describe implements prometheus.Collector. From 66cdd3964e082c5a26d7bfe310af0576392d1302 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Thu, 31 Aug 2023 08:06:50 +0200 Subject: [PATCH 11/22] wip --- internal/backends/sqlite/metadata/registry.go | 1 - .../backends/sqlite/metadata/registry_test.go | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index 03c0830bca2d..899529ae1d57 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -363,7 +363,6 @@ func (r *Registry) Version(ctx context.Context) (string, error) { } row := r.p.GetFirst(ctx).QueryRowContext(context.Background(), "SELECT sqlite_version()") - if err := row.Scan(&r.version); err != nil { return "", lazyerrors.Error(err) } diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index dc5ac4a3739d..99b90296ea35 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -20,6 +20,7 @@ import ( "sync/atomic" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/FerretDB/FerretDB/internal/util/fsql" @@ -297,3 +298,27 @@ func TestCreateDropSameStress(t *testing.T) { }) } } + +func TestVersion(t *testing.T) { + t.Parallel() + ctx := testutil.Ctx(t) + + r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t)) + require.NoError(t, err) + t.Cleanup(r.Close) + + dbName := t.Name() + + // database must exist, so version can be queried + db, err := r.DatabaseGetOrCreate(ctx, dbName) + require.NoError(t, err) + require.NotNil(t, db) + + t.Cleanup(func() { + r.DatabaseDrop(ctx, dbName) + }) + + version, err := r.Version(ctx) + require.NoError(t, err) + assert.Equal(t, "3.41.2", version) +} From 12da6332ca9f6e52ea7d419e2cf4d19344dbb24c Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Thu, 31 Aug 2023 08:28:27 +0200 Subject: [PATCH 12/22] wip --- internal/backends/sqlite/metadata/registry_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index 98cab3a635ab..0bf86f5d46ec 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -309,7 +309,12 @@ func TestVersion(t *testing.T) { dbName := t.Name() - // database must exist, so version can be queried + // trying to get the version while database does not exist + version, err := r.Version(ctx) + require.NoError(t, err) + assert.Equal(t, "", version) + + // database exists, so version can be queried db, err := r.DatabaseGetOrCreate(ctx, dbName) require.NoError(t, err) require.NotNil(t, db) @@ -318,7 +323,7 @@ func TestVersion(t *testing.T) { r.DatabaseDrop(ctx, dbName) }) - version, err := r.Version(ctx) + version, err = r.Version(ctx) require.NoError(t, err) assert.Equal(t, "3.41.2", version) } From 76b8d996fbc616fd6c969e2c5e2a5a0868651bf1 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Thu, 31 Aug 2023 08:29:27 +0200 Subject: [PATCH 13/22] wip --- internal/backends/sqlite/metadata/registry.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index 899529ae1d57..dcde452af7bf 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -362,7 +362,12 @@ func (r *Registry) Version(ctx context.Context) (string, error) { return r.version, nil } - row := r.p.GetFirst(ctx).QueryRowContext(context.Background(), "SELECT sqlite_version()") + db := r.p.GetFirst(ctx) + if db == nil { + return "", nil + } + + row := db.QueryRowContext(context.Background(), "SELECT sqlite_version()") if err := row.Scan(&r.version); err != nil { return "", lazyerrors.Error(err) } From 75b5cdddbef1d5241c6f7ef3a27900caf0cd3568 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Thu, 31 Aug 2023 08:45:34 +0200 Subject: [PATCH 14/22] wip --- internal/backends/sqlite/metadata/registry_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index 0bf86f5d46ec..b5ab7ca81a49 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -319,9 +319,12 @@ func TestVersion(t *testing.T) { require.NoError(t, err) require.NotNil(t, db) - t.Cleanup(func() { - r.DatabaseDrop(ctx, dbName) - }) + version, err = r.Version(ctx) + require.NoError(t, err) + assert.Equal(t, "3.41.2", version) + + // no databases available, but the version should be returned because it's stored in the registry + r.DatabaseDrop(ctx, dbName) version, err = r.Version(ctx) require.NoError(t, err) From e48a0bb94f4028e31588e4ce7c43bc901bc73a39 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Thu, 31 Aug 2023 09:20:12 +0200 Subject: [PATCH 15/22] wip --- internal/backends/sqlite/metadata/registry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index dcde452af7bf..659b693f8aa2 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -367,7 +367,7 @@ func (r *Registry) Version(ctx context.Context) (string, error) { return "", nil } - row := db.QueryRowContext(context.Background(), "SELECT sqlite_version()") + row := db.QueryRowContext(ctx, "SELECT sqlite_version()") if err := row.Scan(&r.version); err != nil { return "", lazyerrors.Error(err) } From cee30ac2d0adbc385a4c0d3d16f18a4ea668450b Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Fri, 1 Sep 2023 13:42:43 +0200 Subject: [PATCH 16/22] use state --- internal/backends/sqlite/backend.go | 4 ++- .../backends/sqlite/metadata/pool/pool.go | 25 ++++++++++++--- .../sqlite/metadata/pool/pool_test.go | 16 ++++++++-- internal/backends/sqlite/metadata/registry.go | 5 +-- .../backends/sqlite/metadata/registry_test.go | 31 +++++++++++++++---- internal/handlers/pg/pgdb/pool.go | 3 -- 6 files changed, 65 insertions(+), 19 deletions(-) diff --git a/internal/backends/sqlite/backend.go b/internal/backends/sqlite/backend.go index 71ba38299e44..e97a11266d74 100644 --- a/internal/backends/sqlite/backend.go +++ b/internal/backends/sqlite/backend.go @@ -23,6 +23,7 @@ import ( "github.com/FerretDB/FerretDB/internal/backends" "github.com/FerretDB/FerretDB/internal/backends/sqlite/metadata" "github.com/FerretDB/FerretDB/internal/util/lazyerrors" + "github.com/FerretDB/FerretDB/internal/util/state" ) // backend implements backends.Backend interface. @@ -36,11 +37,12 @@ type backend struct { type NewBackendParams struct { URI string L *zap.Logger + P *state.Provider } // NewBackend creates a new SQLite backend. func NewBackend(params *NewBackendParams) (backends.Backend, error) { - r, err := metadata.NewRegistry(params.URI, params.L) + r, err := metadata.NewRegistry(params.URI, params.L, params.P) if err != nil { return nil, err } diff --git a/internal/backends/sqlite/metadata/pool/pool.go b/internal/backends/sqlite/metadata/pool/pool.go index 4a45cb13ee97..639da6cec4e2 100644 --- a/internal/backends/sqlite/metadata/pool/pool.go +++ b/internal/backends/sqlite/metadata/pool/pool.go @@ -38,6 +38,7 @@ import ( "github.com/FerretDB/FerretDB/internal/util/lazyerrors" "github.com/FerretDB/FerretDB/internal/util/observability" "github.com/FerretDB/FerretDB/internal/util/resource" + "github.com/FerretDB/FerretDB/internal/util/state" ) // filenameExtension represents SQLite database filename extension. @@ -60,6 +61,8 @@ type Pool struct { dbs map[string]*fsql.DB token *resource.Token + + sp *state.Provider } // openDB opens existing database or creates a new one. @@ -68,7 +71,7 @@ type Pool struct { // so no validation is needed. // One exception is very long full path names for the filesystem, // but we don't check it. -func openDB(name, uri string, singleConn bool, l *zap.Logger) (*fsql.DB, error) { +func openDB(name, uri string, singleConn bool, l *zap.Logger, sp *state.Provider) (*fsql.DB, error) { db, err := sql.Open("sqlite", uri) if err != nil { return nil, lazyerrors.Error(err) @@ -88,6 +91,19 @@ func openDB(name, uri string, singleConn bool, l *zap.Logger) (*fsql.DB, error) return nil, lazyerrors.Error(err) } + if err := sp.Update(func(s *state.State) { + if s.HandlerVersion != "" { + return + } + + row := db.QueryRowContext(context.Background(), "SELECT sqlite_version()") + if err := row.Scan(&s.HandlerVersion); err != nil { + l.Error("sqlite.metadata.pool.openDB: failed to query SQLite version", zap.Error(err)) + } + }); err != nil { + l.Error("sqlite.metadata.pool.openDB: failed to update state", zap.Error(err)) + } + return fsql.WrapDB(db, name, l), nil } @@ -97,7 +113,7 @@ func openDB(name, uri string, singleConn bool, l *zap.Logger) (*fsql.DB, error) // // The returned map is the initial set of existing databases. // It should not be modified. -func New(u string, l *zap.Logger) (*Pool, map[string]*fsql.DB, error) { +func New(u string, l *zap.Logger, sp *state.Provider) (*Pool, map[string]*fsql.DB, error) { uri, err := parseURI(u) if err != nil { return nil, nil, fmt.Errorf("failed to parse SQLite URI %q: %s", u, err) @@ -113,6 +129,7 @@ func New(u string, l *zap.Logger) (*Pool, map[string]*fsql.DB, error) { l: l, dbs: make(map[string]*fsql.DB, len(matches)), token: resource.NewToken(), + sp: sp, } resource.Track(p, p.token) @@ -123,7 +140,7 @@ func New(u string, l *zap.Logger) (*Pool, map[string]*fsql.DB, error) { p.l.Debug("Opening existing database.", zap.String("name", name), zap.String("uri", uri)) - db, err := openDB(name, uri, p.singleConn(), l) + db, err := openDB(name, uri, p.singleConn(), l, p.sp) if err != nil { p.Close() return nil, nil, lazyerrors.Error(err) @@ -250,7 +267,7 @@ func (p *Pool) GetOrCreate(ctx context.Context, name string) (*fsql.DB, bool, er } uri := p.databaseURI(name) - db, err := openDB(name, uri, p.singleConn(), p.l) + db, err := openDB(name, uri, p.singleConn(), p.l, p.sp) if err != nil { return nil, false, lazyerrors.Errorf("%s: %w", uri, err) } diff --git a/internal/backends/sqlite/metadata/pool/pool_test.go b/internal/backends/sqlite/metadata/pool/pool_test.go index 0ff253b61389..cb725716b30b 100644 --- a/internal/backends/sqlite/metadata/pool/pool_test.go +++ b/internal/backends/sqlite/metadata/pool/pool_test.go @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/FerretDB/FerretDB/internal/util/state" "github.com/FerretDB/FerretDB/internal/util/testutil" "github.com/FerretDB/FerretDB/internal/util/testutil/teststress" ) @@ -29,8 +30,11 @@ func TestCreateDrop(t *testing.T) { t.Parallel() ctx := testutil.Ctx(t) + sp, err := state.NewProvider("") + require.NoError(t, err) + // that also tests that query parameters are preserved by using non-writable directory - p, _, err := New("file:/?mode=memory&_pragma=journal_mode(wal)", testutil.Logger(t)) + p, _, err := New("file:/?mode=memory&_pragma=journal_mode(wal)", testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(p.Close) @@ -76,6 +80,9 @@ func TestCreateDrop(t *testing.T) { func TestCreateDropStress(t *testing.T) { ctx := testutil.Ctx(t) + sp, err := state.NewProvider("") + require.NoError(t, err) + for testName, uri := range map[string]string{ "file": "file:./", "file-immediate": "file:./?_txlock=immediate", @@ -83,7 +90,7 @@ func TestCreateDropStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - p, _, err := New(uri, testutil.Logger(t)) + p, _, err := New(uri, testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(p.Close) @@ -137,7 +144,10 @@ func TestDefaults(t *testing.T) { t.Parallel() ctx := testutil.Ctx(t) - p, _, err := New("file:./", testutil.Logger(t)) + sp, err := state.NewProvider("") + require.NoError(t, err) + + p, _, err := New("file:./", testutil.Logger(t), sp) require.NoError(t, err) dbName := testutil.DatabaseName(t) diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index 659b693f8aa2..53397487a2d0 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -31,6 +31,7 @@ import ( "github.com/FerretDB/FerretDB/internal/util/lazyerrors" "github.com/FerretDB/FerretDB/internal/util/must" "github.com/FerretDB/FerretDB/internal/util/observability" + "github.com/FerretDB/FerretDB/internal/util/state" ) const ( @@ -67,8 +68,8 @@ type Registry struct { } // NewRegistry creates a registry for SQLite databases in the directory specified by SQLite URI. -func NewRegistry(u string, l *zap.Logger) (*Registry, error) { - p, initDBs, err := pool.New(u, l) +func NewRegistry(u string, l *zap.Logger, sp *state.Provider) (*Registry, error) { + p, initDBs, err := pool.New(u, l, sp) if err != nil { return nil, err } diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index b5ab7ca81a49..d4ab8b5e3cb6 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/require" "github.com/FerretDB/FerretDB/internal/util/fsql" + "github.com/FerretDB/FerretDB/internal/util/state" "github.com/FerretDB/FerretDB/internal/util/testutil" "github.com/FerretDB/FerretDB/internal/util/testutil/teststress" ) @@ -72,7 +73,10 @@ func TestCreateDrop(t *testing.T) { t.Parallel() ctx := testutil.Ctx(t) - r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t)) + sp, err := state.NewProvider("") + require.NoError(t, err) + + r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(r.Close) @@ -94,6 +98,9 @@ func TestCreateDrop(t *testing.T) { func TestCreateDropStress(t *testing.T) { ctx := testutil.Ctx(t) + sp, err := state.NewProvider("") + require.NoError(t, err) + for testName, uri := range map[string]string{ "file": "file:./", "file-immediate": "file:./?_txlock=immediate", @@ -101,7 +108,7 @@ func TestCreateDropStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(r.Close) @@ -133,6 +140,9 @@ func TestCreateDropStress(t *testing.T) { func TestCreateSameStress(t *testing.T) { ctx := testutil.Ctx(t) + sp, err := state.NewProvider("") + require.NoError(t, err) + for testName, uri := range map[string]string{ "file": "file:./", "file-immediate": "file:./?_txlock=immediate", @@ -140,7 +150,7 @@ func TestCreateSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(r.Close) @@ -197,6 +207,9 @@ func TestCreateSameStress(t *testing.T) { func TestDropSameStress(t *testing.T) { ctx := testutil.Ctx(t) + sp, err := state.NewProvider("") + require.NoError(t, err) + for testName, uri := range map[string]string{ "file": "file:./", "file-immediate": "file:./?_txlock=immediate", @@ -204,7 +217,7 @@ func TestDropSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(r.Close) @@ -246,6 +259,9 @@ func TestDropSameStress(t *testing.T) { func TestCreateDropSameStress(t *testing.T) { ctx := testutil.Ctx(t) + sp, err := state.NewProvider("") + require.NoError(t, err) + for testName, uri := range map[string]string{ "file": "file:./", "file-immediate": "file:./?_txlock=immediate", @@ -253,7 +269,7 @@ func TestCreateDropSameStress(t *testing.T) { "memory-immediate": "file:./?mode=memory&_txlock=immediate", } { t.Run(testName, func(t *testing.T) { - r, err := NewRegistry(uri, testutil.Logger(t)) + r, err := NewRegistry(uri, testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(r.Close) @@ -303,7 +319,10 @@ func TestVersion(t *testing.T) { t.Parallel() ctx := testutil.Ctx(t) - r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t)) + sp, err := state.NewProvider("") + require.NoError(t, err) + + r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t), sp) require.NoError(t, err) t.Cleanup(r.Close) diff --git a/internal/handlers/pg/pgdb/pool.go b/internal/handlers/pg/pgdb/pool.go index 07e26d01f17a..1dfa66153ebd 100644 --- a/internal/handlers/pg/pgdb/pool.go +++ b/internal/handlers/pg/pgdb/pool.go @@ -69,9 +69,6 @@ func NewPool(ctx context.Context, uri string, logger *zap.Logger, p *state.Provi return lazyerrors.Error(err) } - // After moving pg to the new architecture, we should stop storing the version in the state, - // but use backend.Info instead. - // TODO https://github.com/FerretDB/FerretDB/issues/3228 if err := p.Update(func(s *state.State) { s.HandlerVersion = v }); err != nil { logger.Error("pgdb.Pool.AfterConnect: failed to update state", zap.Error(err)) } From 14b585385774814804217decb4b760f7a99c53b9 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Fri, 1 Sep 2023 13:46:21 +0200 Subject: [PATCH 17/22] print version --- internal/handlers/sqlite/msg_getlog.go | 13 ++++++++----- internal/handlers/sqlite/sqlite.go | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index 93faa9e48448..9f656ee231f7 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -18,6 +18,7 @@ import ( "context" "encoding/json" "fmt" + "strings" "time" "go.uber.org/zap" @@ -88,17 +89,19 @@ func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, info := version.Get() + // it may be empty if no connection was established yet + hv, _, _ := strings.Cut(state.HandlerVersion, " ") + if hv != "" { + hv = " " + hv + } + backend, err := h.b.Info(ctx) if err != nil { return nil, lazyerrors.Error(err) } - if backend.Version != "" { - backend.Version = " " + backend.Version // to format startup warnings - } - startupWarnings := []string{ - fmt.Sprintf("Powered by FerretDB %s and %s%s.", info.Version, backend.Name, backend.Version), + fmt.Sprintf("Powered by FerretDB %s and %s%s.", info.Version, backend.Name, hv), "Please star us on GitHub: https://github.com/FerretDB/FerretDB.", } diff --git a/internal/handlers/sqlite/sqlite.go b/internal/handlers/sqlite/sqlite.go index e77a0b3c80bc..6629b6a126f1 100644 --- a/internal/handlers/sqlite/sqlite.go +++ b/internal/handlers/sqlite/sqlite.go @@ -81,6 +81,7 @@ func New(opts *NewOpts) (handlers.Interface, error) { b, err = sqlite.NewBackend(&sqlite.NewBackendParams{ URI: opts.URI, L: opts.L, + P: opts.StateProvider, }) default: panic("unknown backend: " + opts.Backend) From 84f7e847eaca481989aceac80317ed2271b11af6 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Fri, 1 Sep 2023 13:56:53 +0200 Subject: [PATCH 18/22] remove unnecessary version --- internal/backends/backend.go | 14 ++++---------- internal/backends/postgresql/backend.go | 6 +++--- internal/backends/sqlite/backend.go | 15 +++------------ internal/handlers/sqlite/msg_getlog.go | 7 +------ 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/internal/backends/backend.go b/internal/backends/backend.go index 34edfae2adf4..2d6adbc4e382 100644 --- a/internal/backends/backend.go +++ b/internal/backends/backend.go @@ -38,7 +38,7 @@ type Backend interface { ListDatabases(context.Context, *ListDatabasesParams) (*ListDatabasesResult, error) DropDatabase(context.Context, *DropDatabaseParams) error - Info(context.Context) (*Info, error) + Name() string prometheus.Collector @@ -46,12 +46,6 @@ type Backend interface { // TODO https://github.com/FerretDB/FerretDB/issues/3069 } -// Info represents information about a backend. -type Info struct { - Name string - Version string // can be empty if the pool is not initialized yet -} - // backendContract implements Backend interface. type backendContract struct { b Backend @@ -140,9 +134,9 @@ func (bc *backendContract) DropDatabase(ctx context.Context, params *DropDatabas return err } -// Info returns information about the backend. -func (bc *backendContract) Info(ctx context.Context) (*Info, error) { - return bc.b.Info(ctx) +// Name returns human-readable formatted name of the backend. +func (bc *backendContract) Name() string { + return bc.b.Name() } // Describe implements prometheus.Collector. diff --git a/internal/backends/postgresql/backend.go b/internal/backends/postgresql/backend.go index 14b38e2bd134..8b1a1fcbd2aa 100644 --- a/internal/backends/postgresql/backend.go +++ b/internal/backends/postgresql/backend.go @@ -60,9 +60,9 @@ func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabas panic("not implemented") } -// Info implements backends.Backend interface. -func (b *backend) Info(ctx context.Context) (*backends.Info, error) { - panic("not implemented") +// Name implements backends.Backend interface. +func (b *backend) Name() string { + return "PostgreSQL" } // Describe implements prometheus.Collector. diff --git a/internal/backends/sqlite/backend.go b/internal/backends/sqlite/backend.go index e97a11266d74..ea0aa249df07 100644 --- a/internal/backends/sqlite/backend.go +++ b/internal/backends/sqlite/backend.go @@ -22,7 +22,6 @@ import ( "github.com/FerretDB/FerretDB/internal/backends" "github.com/FerretDB/FerretDB/internal/backends/sqlite/metadata" - "github.com/FerretDB/FerretDB/internal/util/lazyerrors" "github.com/FerretDB/FerretDB/internal/util/state" ) @@ -87,17 +86,9 @@ func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabas return nil } -// Info implements backends.Backend interface. -func (b *backend) Info(ctx context.Context) (*backends.Info, error) { - version, err := b.r.Version(ctx) - if err != nil { - return nil, lazyerrors.Error(err) - } - - return &backends.Info{ - Name: "SQLite", - Version: version, - }, nil +// Name implements backends.Backend interface. +func (b *backend) Name() string { + return "SQLite" } // Describe implements prometheus.Collector. diff --git a/internal/handlers/sqlite/msg_getlog.go b/internal/handlers/sqlite/msg_getlog.go index 9f656ee231f7..d1d27c39e4c5 100644 --- a/internal/handlers/sqlite/msg_getlog.go +++ b/internal/handlers/sqlite/msg_getlog.go @@ -95,13 +95,8 @@ func (h *Handler) MsgGetLog(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg, hv = " " + hv } - backend, err := h.b.Info(ctx) - if err != nil { - return nil, lazyerrors.Error(err) - } - startupWarnings := []string{ - fmt.Sprintf("Powered by FerretDB %s and %s%s.", info.Version, backend.Name, hv), + fmt.Sprintf("Powered by FerretDB %s and %s%s.", info.Version, h.b.Name(), hv), "Please star us on GitHub: https://github.com/FerretDB/FerretDB.", } From badab62617151dac254d3b1522a69e97c6fa4c5e Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Fri, 1 Sep 2023 14:13:59 +0200 Subject: [PATCH 19/22] cleanup version calculation --- .../backends/sqlite/metadata/pool/pool.go | 17 --------- internal/backends/sqlite/metadata/registry.go | 23 ------------ .../backends/sqlite/metadata/registry_test.go | 36 ------------------- 3 files changed, 76 deletions(-) diff --git a/internal/backends/sqlite/metadata/pool/pool.go b/internal/backends/sqlite/metadata/pool/pool.go index 639da6cec4e2..2d078121fd66 100644 --- a/internal/backends/sqlite/metadata/pool/pool.go +++ b/internal/backends/sqlite/metadata/pool/pool.go @@ -230,23 +230,6 @@ func (p *Pool) GetExisting(ctx context.Context, name string) *fsql.DB { return db } -// GetFirst returns a database from the pool, or nil if there are no databases in the pool. -// -// As the pool is not ordered, the returned database is not guaranteed to be the same. -// This method can be used when a DB-agnostic query is needed. -func (p *Pool) GetFirst(ctx context.Context) *fsql.DB { - defer observability.FuncCall(ctx)() - - p.rw.RLock() - defer p.rw.RUnlock() - - for _, db := range p.dbs { - return db - } - - return nil -} - // GetOrCreate returns an existing database by valid name, or creates a new one. // // Returned boolean value indicates whether the database was created. diff --git a/internal/backends/sqlite/metadata/registry.go b/internal/backends/sqlite/metadata/registry.go index 53397487a2d0..155eb8a75825 100644 --- a/internal/backends/sqlite/metadata/registry.go +++ b/internal/backends/sqlite/metadata/registry.go @@ -56,8 +56,6 @@ type Registry struct { p *pool.Pool l *zap.Logger - version string // SQLite version - // rw protects colls but also acts like a global lock for the whole registry. // The latter effectively replaces transactions (see the sqlite backend description for more info). // One global lock should be replaced by more granular locks – one per database or even one per collection. @@ -355,27 +353,6 @@ func (r *Registry) CollectionRename(ctx context.Context, dbName, oldCollectionNa panic("not implemented") } -// Version returns SQLite version. -// -// If there are no databases in the registry, empty string is returned. -func (r *Registry) Version(ctx context.Context) (string, error) { - if r.version != "" { - return r.version, nil - } - - db := r.p.GetFirst(ctx) - if db == nil { - return "", nil - } - - row := db.QueryRowContext(ctx, "SELECT sqlite_version()") - if err := row.Scan(&r.version); err != nil { - return "", lazyerrors.Error(err) - } - - return r.version, nil -} - // Describe implements prometheus.Collector. func (r *Registry) Describe(ch chan<- *prometheus.Desc) { prometheus.DescribeByCollect(r, ch) diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index d4ab8b5e3cb6..c6f210a6e122 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -20,7 +20,6 @@ import ( "sync/atomic" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/FerretDB/FerretDB/internal/util/fsql" @@ -314,38 +313,3 @@ func TestCreateDropSameStress(t *testing.T) { }) } } - -func TestVersion(t *testing.T) { - t.Parallel() - ctx := testutil.Ctx(t) - - sp, err := state.NewProvider("") - require.NoError(t, err) - - r, err := NewRegistry("file:./?mode=memory", testutil.Logger(t), sp) - require.NoError(t, err) - t.Cleanup(r.Close) - - dbName := t.Name() - - // trying to get the version while database does not exist - version, err := r.Version(ctx) - require.NoError(t, err) - assert.Equal(t, "", version) - - // database exists, so version can be queried - db, err := r.DatabaseGetOrCreate(ctx, dbName) - require.NoError(t, err) - require.NotNil(t, db) - - version, err = r.Version(ctx) - require.NoError(t, err) - assert.Equal(t, "3.41.2", version) - - // no databases available, but the version should be returned because it's stored in the registry - r.DatabaseDrop(ctx, dbName) - - version, err = r.Version(ctx) - require.NoError(t, err) - assert.Equal(t, "3.41.2", version) -} From 3e27ca3441da08d05e0783377ceaac0d282007f2 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Fri, 1 Sep 2023 15:07:13 +0200 Subject: [PATCH 20/22] add test for version --- internal/backends/sqlite/metadata/registry_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/backends/sqlite/metadata/registry_test.go b/internal/backends/sqlite/metadata/registry_test.go index 055abfb907ce..e240198fe0a3 100644 --- a/internal/backends/sqlite/metadata/registry_test.go +++ b/internal/backends/sqlite/metadata/registry_test.go @@ -85,6 +85,9 @@ func TestCreateDrop(t *testing.T) { require.NoError(t, err) require.NotNil(t, db) + state := sp.Get() + require.Equal(t, "3.41.2", state.HandlerVersion) + t.Cleanup(func() { r.DatabaseDrop(ctx, dbName) }) From 9c4317defb6c894102d813fad87c632c9b829431 Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Fri, 1 Sep 2023 15:43:58 +0200 Subject: [PATCH 21/22] fix tests --- internal/backends/postgresql/collection.go | 2 +- internal/backends/sqlite/collection.go | 2 +- internal/backends/sqlite/collection_test.go | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/backends/postgresql/collection.go b/internal/backends/postgresql/collection.go index 046574065777..412e92d269dc 100644 --- a/internal/backends/postgresql/collection.go +++ b/internal/backends/postgresql/collection.go @@ -39,7 +39,7 @@ func (c *collection) Query(ctx context.Context, params *backends.QueryParams) (* panic("not implemented") } -// Insert implements backends.Collection interface. +// InsertAll implements backends.Collection interface. func (c *collection) InsertAll(ctx context.Context, params *backends.InsertAllParams) (*backends.InsertAllResult, error) { panic("not implemented") } diff --git a/internal/backends/sqlite/collection.go b/internal/backends/sqlite/collection.go index 02c7a1bfb1be..f2d1a7d6206e 100644 --- a/internal/backends/sqlite/collection.go +++ b/internal/backends/sqlite/collection.go @@ -75,7 +75,7 @@ func (c *collection) Query(ctx context.Context, params *backends.QueryParams) (* }, nil } -// Insert implements backends.Collection interface. +// InsertAll implements backends.Collection interface. func (c *collection) InsertAll(ctx context.Context, params *backends.InsertAllParams) (*backends.InsertAllResult, error) { if _, err := c.r.CollectionCreate(ctx, c.dbName, c.name); err != nil { return nil, lazyerrors.Error(err) diff --git a/internal/backends/sqlite/collection_test.go b/internal/backends/sqlite/collection_test.go index 2bef278cd7e9..b6fd0161c1b1 100644 --- a/internal/backends/sqlite/collection_test.go +++ b/internal/backends/sqlite/collection_test.go @@ -21,11 +21,15 @@ import ( "github.com/FerretDB/FerretDB/internal/backends" "github.com/FerretDB/FerretDB/internal/types" + "github.com/FerretDB/FerretDB/internal/util/state" "github.com/FerretDB/FerretDB/internal/util/testutil" ) func TestInsert(t *testing.T) { - b, err := NewBackend(&NewBackendParams{URI: "file:./?mode=memory", L: testutil.Logger(t)}) + sp, err := state.NewProvider("") + require.NoError(t, err) + + b, err := NewBackend(&NewBackendParams{URI: "file:./?mode=memory", L: testutil.Logger(t), P: sp}) require.NoError(t, err) defer b.Close() From 83a834b9ec88e62c3b36b6718ce37d3033ed745e Mon Sep 17 00:00:00 2001 From: Elena Grahovac Date: Fri, 1 Sep 2023 15:47:20 +0200 Subject: [PATCH 22/22] wip --- internal/backends/sqlite/backend.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/backends/sqlite/backend.go b/internal/backends/sqlite/backend.go index ea0aa249df07..05a93758050e 100644 --- a/internal/backends/sqlite/backend.go +++ b/internal/backends/sqlite/backend.go @@ -41,6 +41,10 @@ type NewBackendParams struct { // NewBackend creates a new SQLite backend. func NewBackend(params *NewBackendParams) (backends.Backend, error) { + if params.P == nil { + panic("state provider is required but not set") + } + r, err := metadata.NewRegistry(params.URI, params.L, params.P) if err != nil { return nil, err