From a5677e804aaa11ef1fa29df310bece44887680de Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sat, 26 Feb 2022 19:55:52 +0000 Subject: [PATCH 1/2] Adjust error for already locked db and prevent level db lock on malformed connstr This PR adjusts the error returned when there is failure to lock the level db, and permits a connections to the same leveldb where there is a different connection string. Reference #18921 Reference #18917 Signed-off-by: Andrew Thornton --- modules/nosql/manager_leveldb.go | 36 ++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/modules/nosql/manager_leveldb.go b/modules/nosql/manager_leveldb.go index eeb0cf74d91a4..581553f0d515c 100644 --- a/modules/nosql/manager_leveldb.go +++ b/modules/nosql/manager_leveldb.go @@ -5,10 +5,12 @@ package nosql import ( + "fmt" "path" "strconv" "strings" + "code.gitea.io/gitea/modules/log" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" "github.com/syndtr/goleveldb/leveldb/opt" @@ -40,6 +42,12 @@ func (m *Manager) CloseLevelDB(connection string) error { // GetLevelDB gets a levelDB for a particular connection func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) { + // Convert the provided connection description to the common format + uri := ToLevelDBURI(connection) + + // Get the datadir + dataDir := path.Join(uri.Host, uri.Path) + m.mutex.Lock() defer m.mutex.Unlock() db, ok := m.LevelDBConnections[connection] @@ -48,12 +56,28 @@ func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) { return db.db, nil } - uri := ToLevelDBURI(connection) + + db, ok = m.LevelDBConnections[uri.String()] + if ok { + db.count++ + + return db.db, nil + } + + // if there is already a connection to this leveldb reuse that + // NOTE: if there differing options then only the first leveldb connection will be used + db, ok = m.LevelDBConnections[dataDir] + if ok { + db.count++ + log.Warn("Duplicate connnection to level db: %s with different connection strings. Initial connection: %s. This connection: %s", dataDir, db.name[0], connection) + db.name = append(db.name, connection) + m.LevelDBConnections[connection] = db + return db.db, nil + } db = &levelDBHolder{ - name: []string{connection, uri.String()}, + name: []string{connection, uri.String(), dataDir}, } - dataDir := path.Join(uri.Host, uri.Path) opts := &opt.Options{} for k, v := range uri.Query() { switch replacer.Replace(strings.ToLower(k)) { @@ -134,7 +158,11 @@ func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) { db.db, err = leveldb.OpenFile(dataDir, opts) if err != nil { if !errors.IsCorrupted(err) { - return nil, err + if strings.Contains(err.Error(), "resource temporarily unavailable") { + return nil, fmt.Errorf("unable to lock level db at %s: %w", dataDir, err) + } + + return nil, fmt.Errorf("unable to open level db at %s: %w", dataDir, err) } db.db, err = leveldb.RecoverFile(dataDir, opts) if err != nil { From b125ad25aee580b544e78cd8da57a026b2dd9856 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sun, 27 Feb 2022 15:40:24 +0000 Subject: [PATCH 2/2] On close also check datadir Signed-off-by: Andrew Thornton --- modules/nosql/manager_leveldb.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/nosql/manager_leveldb.go b/modules/nosql/manager_leveldb.go index 581553f0d515c..97f917af78c5c 100644 --- a/modules/nosql/manager_leveldb.go +++ b/modules/nosql/manager_leveldb.go @@ -22,8 +22,16 @@ func (m *Manager) CloseLevelDB(connection string) error { defer m.mutex.Unlock() db, ok := m.LevelDBConnections[connection] if !ok { - connection = ToLevelDBURI(connection).String() - db, ok = m.LevelDBConnections[connection] + // Try the full URI + uri := ToLevelDBURI(connection) + db, ok = m.LevelDBConnections[uri.String()] + + if !ok { + // Try the datadir directly + dataDir := path.Join(uri.Host, uri.Path) + + db, ok = m.LevelDBConnections[dataDir] + } } if !ok { return nil