From a642c035ee8f354cf992159a573dd8208256f9f8 Mon Sep 17 00:00:00 2001 From: Linh Tran Tuan Date: Wed, 31 Jan 2024 00:59:43 +0900 Subject: [PATCH] HOTFIX Mem leak while calling SetOptions (#141) --- Makefile | 2 +- backup.go | 1 - db.go | 12 ++++++++++++ db_test.go | 40 +++++++++++++++++++++++++++++++++------- options.go | 2 +- 5 files changed, 47 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index be39c44..1eb7906 100644 --- a/Makefile +++ b/Makefile @@ -21,4 +21,4 @@ libs: .PHONY: test test: - go test -v -count=1 -tags testing,grocksdb_no_link + go test -race -v -count=1 -tags testing,grocksdb_no_link diff --git a/backup.go b/backup.go index a211a55..bc32ff3 100644 --- a/backup.go +++ b/backup.go @@ -67,7 +67,6 @@ func CreateBackupEngineWithPath(db *DB, path string) (be *BackupEngine, err erro return } - // CreateNewBackup takes a new backup from db. func (b *BackupEngine) CreateNewBackup() (err error) { var cErr *C.char diff --git a/db.go b/db.go index 1fa2632..685f496 100644 --- a/db.go +++ b/db.go @@ -1461,6 +1461,12 @@ func (db *DB) SetOptions(keys, values []string) (err error) { ) err = fromCError(cErr) + // free before return + for i := range cKeys { + C.free(unsafe.Pointer(cKeys[i])) + C.free(unsafe.Pointer(cValues[i])) + } + return } @@ -1490,6 +1496,12 @@ func (db *DB) SetOptionsCF(cf *ColumnFamilyHandle, keys, values []string) (err e ) err = fromCError(cErr) + // free before return + for i := range cKeys { + C.free(unsafe.Pointer(cKeys[i])) + C.free(unsafe.Pointer(cValues[i])) + } + return } diff --git a/db_test.go b/db_test.go index 7bb0216..397b350 100644 --- a/db_test.go +++ b/db_test.go @@ -21,6 +21,30 @@ func TestOpenDb(t *testing.T) { require.True(t, success) } +func TestSetOptions(t *testing.T) { + t.Parallel() + + db := newTestDB(t, nil) + defer db.Close() + + for i := 0; i < 100; i++ { + require.Error(t, db.SetOptions([]string{"a"}, []string{"b"})) + runtime.GC() + } +} + +func TestSetOptionsCF(t *testing.T) { + t.Parallel() + + db, cfh, cleanup := newTestDBMultiCF(t, []string{"default", "custom"}, nil) + defer cleanup() + + for i := 0; i < 100; i++ { + require.Error(t, db.SetOptionsCF(cfh[1], []string{"a"}, []string{"b"})) + runtime.GC() + } +} + func TestDBCRUD(t *testing.T) { t.Parallel() @@ -320,13 +344,15 @@ func TestLoadLatestOpts(t *testing.T) { require.NoError(t, db.Flush(NewDefaultFlushOptions())) db.Close() - o, err := LoadLatestOptions(dir, NewDefaultEnv(), true, NewLRUCache(1)) - runtime.GC() - require.NoError(t, err) - require.NotEmpty(t, o.ColumnFamilyNames()) - require.NotEmpty(t, o.ColumnFamilyOpts()) - o.Destroy() - runtime.GC() + for i := 0; i < 10; i++ { + o, err := LoadLatestOptions(dir, NewDefaultEnv(), true, NewLRUCache(1)) + runtime.GC() + require.NoError(t, err) + require.NotEmpty(t, o.ColumnFamilyNames()) + require.NotEmpty(t, o.ColumnFamilyOpts()) + o.Destroy() + runtime.GC() + } _, err = LoadLatestOptions("", nil, true, nil) require.Error(t, err) diff --git a/options.go b/options.go index 9fd5f00..8fc0a1e 100644 --- a/options.go +++ b/options.go @@ -2665,7 +2665,6 @@ func LoadLatestOptions(path string, env *Env, ignoreUnknownOpts bool, cache *Cac } cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) var env_ *C.rocksdb_env_t if env != nil { @@ -2705,6 +2704,7 @@ func LoadLatestOptions(path string, env *Env, ignoreUnknownOpts bool, cache *Cac } } + C.free(unsafe.Pointer(cPath)) return }