Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement metadata storage #2656

Merged
merged 41 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
WIP
  • Loading branch information
Dmitry committed May 17, 2023
commit f9dbb259eead9c37333233fe7168c4de4a46f0e5
18 changes: 14 additions & 4 deletions internal/backends/sqlite/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import (

// backend implements backends.Backend interface.
type backend struct {
dir string
dir string
metadataStorage *metadataStorage
}

// NewBackendParams represents the parameters of NewBackend function.
Expand All @@ -33,10 +34,19 @@ type NewBackendParams struct {
}

// NewBackend creates a new SQLite backend.
func NewBackend(params *NewBackendParams) backends.Backend {
func NewBackend(params *NewBackendParams) (backends.Backend, error) {
// TODO: we should close it when backend is closed.
pool := newConnPool()

storage, err := newMetadataStorage(params.Dir, pool)
if err != nil {
return nil, err
}

return backends.BackendContract(&backend{
dir: params.Dir,
})
dir: params.Dir,
metadataStorage: storage,
}), nil
}

// Database implements backends.Backend interface.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2021 FerretDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sqlite

import (
Expand All @@ -16,7 +30,6 @@ import (
)

const (

// Reserved prefix for database and collection names.
reservedPrefix = "_ferretdb_"

Expand All @@ -27,14 +40,13 @@ const (
)

// newMetadataStorage returns instance of metadata storage.
func newMetadataStorage(dbPath string) (*metadataStorage, error) {
func newMetadataStorage(dbPath string, pool *connPool) (*metadataStorage, error) {
if dbPath == "" {
return nil, errors.New("db path is empty")
}

return &metadataStorage{
// TODO: might be passed as parameter.
connPool: newConnPool(),
connPool: pool,
dbPath: dbPath,
dbs: make(map[string]*dbInfo),
}, nil
Expand Down Expand Up @@ -131,7 +143,7 @@ func (m *metadataStorage) RemoveDatabase(database string) error {
}

// RemoveCollection removes collection metadata.
// It does not physically remove collection from database.
// It does not remove collection from database.
func (m *metadataStorage) RemoveCollection(database, collection string) error {
m.mx.Lock()
defer m.mx.Unlock()
Expand All @@ -151,6 +163,8 @@ func (m *metadataStorage) RemoveCollection(database, collection string) error {
return nil
}

// CreateDatabase adds database to metadata storage.
// It doesn't create database file.
func (m *metadataStorage) CreateDatabase(database string) error {
m.mx.Lock()
defer m.mx.Unlock()
Expand All @@ -165,7 +179,7 @@ func (m *metadataStorage) CreateDatabase(database string) error {
return nil
}

// CreateCollection saves collection metadata to database file
// CreateCollection saves collection metadata to database file.
func (m *metadataStorage) CreateCollection(ctx context.Context, database, collection string) error {
m.mx.Lock()
defer m.mx.Unlock()
Expand All @@ -180,7 +194,7 @@ func (m *metadataStorage) CreateCollection(ctx context.Context, database, collec
return errors.New("collection already exists")
}

tableName := mangleCollection(collection)
tableName := tableNameFromCollectionName(collection)

err := m.saveCollection(ctx, database, collection, tableName)
if err != nil {
Expand Down Expand Up @@ -257,8 +271,8 @@ func (m *metadataStorage) saveCollection(ctx context.Context, dbName, collName,
return nil
}

// mangleCollection mangles collection name to table name.
// tableNameFromCollectionName mangles collection name to table name.
// TODO: implement proper mangle if needed.
func mangleCollection(name string) string {
func tableNameFromCollectionName(name string) string {
return name
}
70 changes: 70 additions & 0 deletions internal/backends/sqlite/pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2021 FerretDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sqlite

import (
"database/sql"
"errors"
"sync"
)

// newConnPool creates a new connection pool.
func newConnPool() *connPool {
return &connPool{
mx: sync.Mutex{},
dbs: make(map[string]*sql.DB),
}
}

// connPool is a pool of database connections.
type connPool struct {
mx sync.Mutex
dbs map[string]*sql.DB
}

// DB returns a database connection for the given name.
func (c *connPool) DB(name string) (*sql.DB, error) {
c.mx.Lock()
defer c.mx.Unlock()

if db, ok := c.dbs[name]; ok {
return db, nil
}

db, err := sql.Open("sqlite", name)
if err != nil {
return nil, err
}

c.dbs[name] = db

return db, nil
}

// Close closes all database connections.
func (c *connPool) Close() error {
var errs error

c.mx.Lock()
defer c.mx.Unlock()

for _, conn := range c.dbs {
if err := conn.Close(); err != nil {
errors.Join(err)
}
}

return errs
}
52 changes: 0 additions & 52 deletions internal/handlers/sqlite/pool.go

This file was deleted.

5 changes: 4 additions & 1 deletion internal/handlers/sqlite/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ type NewOpts struct {

// New returns a new handler.
func New(opts *NewOpts) (handlers.Interface, error) {
b := sqlite.NewBackend(&sqlite.NewBackendParams{
b, err := sqlite.NewBackend(&sqlite.NewBackendParams{
Dir: opts.Dir,
})
if err != nil {
return nil, err
}

return &Handler{
NewOpts: opts,
Expand Down