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

Store indexes metadata #3434

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5f63251
wip
rumyantseva Sep 26, 2023
4632b38
wip
rumyantseva Sep 26, 2023
b4bac2d
Merge branch 'main' into issue-3375-pg-indexes-mentadata
Sep 26, 2023
9547f3a
wip
rumyantseva Sep 26, 2023
ada4498
wip
rumyantseva Sep 26, 2023
d31b7ba
wip
rumyantseva Sep 27, 2023
61bb540
wip
rumyantseva Sep 27, 2023
86e88c6
wip
rumyantseva Sep 27, 2023
ccc1b97
wip
rumyantseva Sep 27, 2023
97e0a21
fixed a strange thing
rumyantseva Sep 27, 2023
fa4684f
merge conflicts
rumyantseva Sep 28, 2023
e97422b
bugfix
rumyantseva Sep 28, 2023
cdaca09
fix test
rumyantseva Sep 28, 2023
a198a14
linter things
rumyantseva Sep 28, 2023
1d6f3fb
Merge branch 'main' into issue-3375-pg-indexes-mentadata
rumyantseva Sep 28, 2023
acb5d20
Merge branch 'main' into issue-3375-pg-indexes-mentadata
rumyantseva Sep 28, 2023
49ece35
wip
rumyantseva Sep 28, 2023
ed53d66
wip
rumyantseva Sep 29, 2023
184ec9a
wip
rumyantseva Sep 29, 2023
c1e2861
wip
rumyantseva Sep 29, 2023
0d7bf07
wip
rumyantseva Sep 29, 2023
586f314
wip
rumyantseva Sep 29, 2023
3661271
wip
rumyantseva Sep 29, 2023
9a9a5a8
wip
rumyantseva Sep 29, 2023
97afd35
wip
rumyantseva Sep 29, 2023
db39ee5
wip
rumyantseva Sep 29, 2023
05139bb
wip
rumyantseva Sep 29, 2023
650df0d
Merge branch 'main' into issue-3375-pg-indexes-mentadata
Sep 29, 2023
8019fe0
Merge branch 'main' into issue-3375-pg-indexes-mentadata
Sep 29, 2023
0fb411a
wip
rumyantseva Sep 29, 2023
71c8389
wip
rumyantseva Sep 29, 2023
e577da1
wip
rumyantseva Sep 29, 2023
fc0ad27
Merge branch 'main' into issue-3375-pg-indexes-mentadata
AlekSi Oct 2, 2023
ebe36f1
Simplify
AlekSi Oct 2, 2023
0f6cf2c
Tidy comments
AlekSi Oct 2, 2023
f268901
Extract settings
AlekSi Oct 2, 2023
402e731
Refactor
AlekSi Oct 2, 2023
3fc9156
Cleanup
AlekSi Oct 2, 2023
9819817
Remove tests for library functions
AlekSi Oct 2, 2023
800d3b7
Merge branch 'main' into issue-3375-pg-indexes-mentadata
AlekSi Oct 4, 2023
47de006
version without uuid
rumyantseva Oct 4, 2023
11958ae
simpler way to check for existing indexes
rumyantseva Oct 4, 2023
b03d927
wip
rumyantseva Oct 4, 2023
14ad43d
Merge branch 'main' into issue-3375-pg-indexes-mentadata
Oct 4, 2023
4ebd311
wip
rumyantseva Oct 4, 2023
ee8a461
wip
rumyantseva Oct 4, 2023
bc35680
wip
rumyantseva Oct 4, 2023
97e89f7
wip
rumyantseva Oct 4, 2023
335953f
Merge branch 'main' into issue-3375-pg-indexes-mentadata
Oct 4, 2023
13a7cf7
wip
rumyantseva Oct 5, 2023
bc1800a
Merge branch 'main' into issue-3375-pg-indexes-mentadata
AlekSi Oct 5, 2023
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
Extract settings
  • Loading branch information
AlekSi committed Oct 2, 2023
commit f26890179dafabff3ecf393d64853ee79254b2e8
193 changes: 62 additions & 131 deletions internal/backends/postgresql/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
package metadata

import (
"errors"

"golang.org/x/exp/slices"
"database/sql"
"database/sql/driver"

"github.com/FerretDB/FerretDB/internal/handlers/sjson"
"github.com/FerretDB/FerretDB/internal/types"
"github.com/FerretDB/FerretDB/internal/util/iterator"
"github.com/FerretDB/FerretDB/internal/util/lazyerrors"
"github.com/FerretDB/FerretDB/internal/util/must"
)
Expand Down Expand Up @@ -57,151 +56,83 @@ func (c *Collection) deepCopy() *Collection {
}
}

// Marshal returns [*types.Document] for that collection.
func (c *Collection) Marshal() *types.Document {
return must.NotFail(types.NewDocument(
"_id", c.Name,
"table", c.TableName,
"settings", c.Settings.Marshal(),
))
}

// Unmarshal sets collection metadata from [*types.Document].
func (c *Collection) Unmarshal(doc *types.Document) error {
c.Name = must.NotFail(doc.Get("_id")).(string)
c.TableName = must.NotFail(doc.Get("table")).(string)

var settings Settings
must.NoError(settings.Unmarshal(must.NotFail(doc.Get("settings")).(*types.Document)))
c.Settings = settings

return nil
}
// Value implements driver.Valuer interface.
func (c Collection) Value() (driver.Value, error) {
b, err := sjson.Marshal(c.marshal())
if err != nil {
return nil, lazyerrors.Error(err)
}

// Settings represents collection settings.
type Settings struct {
Indexes []IndexInfo `json:"indexes"`
return b, nil
}

// deepCopy returns a deep copy.
func (s Settings) deepCopy() Settings {
indexes := make([]IndexInfo, len(s.Indexes))

for i, index := range s.Indexes {
indexes[i] = IndexInfo{
Name: index.Name,
TableIndexName: index.TableIndexName,
Key: slices.Clone(index.Key),
Unique: index.Unique,
}
// Scan implements sql.Scanner interface.
func (c *Collection) Scan(src any) error {
var doc *types.Document
var err error
switch src := src.(type) {
case nil:
*c = Collection{}
return nil
case []byte:
doc, err = sjson.Unmarshal(src)
case string:
doc, err = sjson.Unmarshal([]byte(src))
default:
panic("can't scan collection")
}

return Settings{
Indexes: indexes,
if err != nil {
return lazyerrors.Error(err)
}
}

// Marshal returns [*types.Document] for settings.
func (s Settings) Marshal() *types.Document {
indexes := types.MakeArray(len(s.Indexes))

for _, index := range s.Indexes {
key := types.MakeDocument(len(index.Key))

// The format of the index key storing was defined in the early versions of FerretDB,
// it's kept for backward compatibility.
for _, pair := range index.Key {
order := int32(1) // order is set as int32 to be sjson-marshaled correctly

if pair.Descending {
order = -1
}

key.Set(pair.Field, order)
}

indexes.Append(must.NotFail(types.NewDocument(
"pgindex", index.TableIndexName,
"name", index.Name,
"key", key,
"unique", index.Unique,
)))
if err = c.unmarshal(doc); err != nil {
return lazyerrors.Error(err)
}

return nil
}

// marshal returns [*types.Document] for that collection.
func (c *Collection) marshal() *types.Document {
return must.NotFail(types.NewDocument(
"indexes", indexes,
"_id", c.Name,
"table", c.TableName,
"settings", c.Settings.marshal(),
))
}

// Unmarshal sets settings from [*types.Document].
func (s *Settings) Unmarshal(doc *types.Document) error {
indexes := must.NotFail(doc.Get("indexes")).(*types.Array)

s.Indexes = make([]IndexInfo, indexes.Len())

iter := indexes.Iterator()
defer iter.Close()

for {
i, v, err := iter.Next()
if errors.Is(err, iterator.ErrIteratorDone) {
break
}

if err != nil {
return lazyerrors.Error(err)
}

doc := v.(*types.Document)

keyDoc := must.NotFail(doc.Get("key")).(*types.Document)
keyIter := keyDoc.Iterator()
key := make([]IndexKeyPair, keyDoc.Len())

defer keyIter.Close()

for j := 0; ; j++ {
field, order, err := keyIter.Next()
if errors.Is(err, iterator.ErrIteratorDone) {
break
}
// unmarshal sets collection metadata from [*types.Document].
func (c *Collection) unmarshal(doc *types.Document) error {
v, _ := doc.Get("_id")
c.Name, _ = v.(string)
if c.Name == "" {
return lazyerrors.New("collection name is empty")
}

if err != nil {
return lazyerrors.Error(err)
}
v, _ = doc.Get("table")
c.TableName, _ = v.(string)
if c.TableName == "" {
return lazyerrors.New("table name is empty")
}

descending := false
if order.(int32) == -1 {
descending = true
}
v, _ = doc.Get("settings")
s, _ := v.(*types.Document)
if s == nil {
return lazyerrors.New("settings are empty")
}

key[j] = IndexKeyPair{
Field: field,
Descending: descending,
}
}
c.Settings.unmarshal(doc)

s.Indexes[i] = IndexInfo{
Name: must.NotFail(doc.Get("name")).(string),
TableIndexName: must.NotFail(doc.Get("pgindex")).(string),
Key: key,
Unique: must.NotFail(doc.Get("unique")).(bool),
}
}
var settings Settings
must.NoError(settings.unmarshal(must.NotFail(doc.Get("settings")).(*types.Document)))
c.Settings = settings

return nil
}

// IndexInfo represents information about a single index.
type IndexInfo struct {
Name string
TableIndexName string // how the index is created in the DB, like TableName for Collection
Key []IndexKeyPair
Unique bool
}

// IndexKeyPair consists of a field name and a sort order that are part of the index.
type IndexKeyPair struct {
Field string
Descending bool
}
// check interfaces
var (
_ driver.Valuer = Collection{}
_ sql.Scanner = (*Collection)(nil)
)
49 changes: 13 additions & 36 deletions internal/backends/postgresql/metadata/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import (
"github.com/FerretDB/FerretDB/internal/backends/postgresql/metadata/pool"
"github.com/FerretDB/FerretDB/internal/clientconn/conninfo"
"github.com/FerretDB/FerretDB/internal/handlers/sjson"
"github.com/FerretDB/FerretDB/internal/types"
"github.com/FerretDB/FerretDB/internal/util/lazyerrors"
"github.com/FerretDB/FerretDB/internal/util/must"
"github.com/FerretDB/FerretDB/internal/util/observability"
Expand Down Expand Up @@ -221,19 +220,8 @@ func (r *Registry) initCollections(ctx context.Context, dbName string, p *pgxpoo
colls := map[string]*Collection{}

for rows.Next() {
var b []byte
if err = rows.Scan(&b); err != nil {
return lazyerrors.Error(err)
}

var doc *types.Document

if doc, err = sjson.Unmarshal(b); err != nil {
return lazyerrors.Error(err)
}

var c Collection
if err = c.Unmarshal(doc); err != nil {
if err = rows.Scan(&c); err != nil {
return lazyerrors.Error(err)
}

Expand Down Expand Up @@ -525,17 +513,11 @@ func (r *Registry) collectionCreate(ctx context.Context, p *pgxpool.Pool, dbName
TableName: tableName,
}

b, err := sjson.Marshal(c.Marshal())
if err != nil {
return false, lazyerrors.Error(err)
}

q := fmt.Sprintf(
`CREATE TABLE %s (%s jsonb)`,
pgx.Identifier{dbName, tableName}.Sanitize(),
DefaultColumn,
)

if _, err = p.Exec(ctx, q); err != nil {
return false, lazyerrors.Error(err)
}
Expand All @@ -545,8 +527,7 @@ func (r *Registry) collectionCreate(ctx context.Context, p *pgxpool.Pool, dbName
pgx.Identifier{dbName, metadataTableName}.Sanitize(),
DefaultColumn,
)

if _, err = p.Exec(ctx, q, string(b)); err != nil {
if _, err = p.Exec(ctx, q, c); err != nil {
q = fmt.Sprintf(`DROP TABLE %s`, pgx.Identifier{dbName, tableName}.Sanitize())
_, _ = p.Exec(ctx, q)

Expand All @@ -558,15 +539,11 @@ func (r *Registry) collectionCreate(ctx context.Context, p *pgxpool.Pool, dbName
}
r.colls[dbName][collectionName] = c

err = r.indexesCreate(ctx, p, dbName, collectionName,
[]IndexInfo{
{
Name: "_id_",
Key: []IndexKeyPair{{Field: "_id"}},
Unique: true,
},
},
)
err = r.indexesCreate(ctx, p, dbName, collectionName, []IndexInfo{{
Name: "_id_",
Key: []IndexKeyPair{{Field: "_id"}},
Unique: true,
}})
if err != nil {
_, _ = r.collectionDrop(ctx, p, dbName, collectionName)
return false, lazyerrors.Error(err)
Expand Down Expand Up @@ -710,7 +687,7 @@ func (r *Registry) CollectionRename(ctx context.Context, dbName, oldCollectionNa

c.Name = newCollectionName

b, err := sjson.Marshal(c.Marshal())
b, err := sjson.Marshal(c.marshal())
if err != nil {
return false, lazyerrors.Error(err)
}
Expand Down Expand Up @@ -795,7 +772,7 @@ func (r *Registry) indexesCreate(ctx context.Context, p *pgxpool.Pool, dbName, c
tableNamePart = tableNamePart[:tableNamePartMax]
}

index.TableIndexName = fmt.Sprintf("%s_%s_idx", tableNamePart, uuidPart)
index.PgName = fmt.Sprintf("%s_%s_idx", tableNamePart, uuidPart)

q := "CREATE "

Expand Down Expand Up @@ -825,7 +802,7 @@ func (r *Registry) indexesCreate(ctx context.Context, p *pgxpool.Pool, dbName, c

q = fmt.Sprintf(
q,
pgx.Identifier{index.TableIndexName}.Sanitize(),
pgx.Identifier{index.PgName}.Sanitize(),
pgx.Identifier{dbName, c.TableName}.Sanitize(),
strings.Join(columns, ", "),
)
Expand All @@ -839,7 +816,7 @@ func (r *Registry) indexesCreate(ctx context.Context, p *pgxpool.Pool, dbName, c
c.Settings.Indexes = append(c.Settings.Indexes, index)
}

b, err := sjson.Marshal(c.Marshal())
b, err := sjson.Marshal(c.marshal())
if err != nil {
return lazyerrors.Error(err)
}
Expand Down Expand Up @@ -907,15 +884,15 @@ func (r *Registry) indexesDrop(ctx context.Context, p *pgxpool.Pool, dbName, col
continue
}

q := fmt.Sprintf("DROP INDEX %s", pgx.Identifier{dbName, c.Settings.Indexes[i].TableIndexName}.Sanitize())
q := fmt.Sprintf("DROP INDEX %s", pgx.Identifier{dbName, c.Settings.Indexes[i].PgName}.Sanitize())
if _, err := p.Exec(ctx, q); err != nil {
return lazyerrors.Error(err)
}

c.Settings.Indexes = slices.Delete(c.Settings.Indexes, i, i+1)
}

b, err := sjson.Marshal(c.Marshal())
b, err := sjson.Marshal(c.marshal())
if err != nil {
return lazyerrors.Error(err)
}
Expand Down
8 changes: 4 additions & 4 deletions internal/backends/postgresql/metadata/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ func TestIndexesCreateDrop(t *testing.T) {
return ii.Name == "index_non_unique"
})
require.GreaterOrEqual(t, i, 0)
tableIndexName := collection.Settings.Indexes[i].TableIndexName
tableIndexName := collection.Settings.Indexes[i].PgName

var sql string
err = db.QueryRow(
Expand All @@ -534,7 +534,7 @@ func TestIndexesCreateDrop(t *testing.T) {
return ii.Name == "index_unique"
})
require.GreaterOrEqual(t, i, 0)
tableIndexName := collection.Settings.Indexes[i].TableIndexName
tableIndexName := collection.Settings.Indexes[i].PgName

var sql string
err = db.QueryRow(
Expand All @@ -556,7 +556,7 @@ func TestIndexesCreateDrop(t *testing.T) {
return ii.Name == "nested_fields"
})
require.GreaterOrEqual(t, i, 0)
tableIndexName := collection.Settings.Indexes[i].TableIndexName
tableIndexName := collection.Settings.Indexes[i].PgName

var sql string
err = db.QueryRow(
Expand All @@ -579,7 +579,7 @@ func TestIndexesCreateDrop(t *testing.T) {
return ii.Name == "_id_"
})
require.GreaterOrEqual(t, i, 0)
tableIndexName := collection.Settings.Indexes[i].TableIndexName
tableIndexName := collection.Settings.Indexes[i].PgName

var sql string
err = db.QueryRow(
Expand Down
Loading