Adjust error for already locked db and prevent level db lock on malformed connstr (#18923)
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 <art27@cantab.net>
This commit is contained in:
parent
548adb94b4
commit
4697735c8d
1 changed files with 43 additions and 7 deletions
|
@ -5,10 +5,12 @@
|
||||||
package nosql
|
package nosql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/errors"
|
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
|
@ -20,8 +22,16 @@ func (m *Manager) CloseLevelDB(connection string) error {
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
db, ok := m.LevelDBConnections[connection]
|
db, ok := m.LevelDBConnections[connection]
|
||||||
if !ok {
|
if !ok {
|
||||||
connection = ToLevelDBURI(connection).String()
|
// Try the full URI
|
||||||
db, ok = m.LevelDBConnections[connection]
|
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 {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -40,6 +50,12 @@ func (m *Manager) CloseLevelDB(connection string) error {
|
||||||
|
|
||||||
// GetLevelDB gets a levelDB for a particular connection
|
// GetLevelDB gets a levelDB for a particular connection
|
||||||
func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) {
|
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()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
db, ok := m.LevelDBConnections[connection]
|
db, ok := m.LevelDBConnections[connection]
|
||||||
|
@ -48,12 +64,28 @@ func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) {
|
||||||
|
|
||||||
return db.db, nil
|
return db.db, nil
|
||||||
}
|
}
|
||||||
uri := ToLevelDBURI(connection)
|
|
||||||
db = &levelDBHolder{
|
db, ok = m.LevelDBConnections[uri.String()]
|
||||||
name: []string{connection, 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(), dataDir},
|
||||||
}
|
}
|
||||||
|
|
||||||
dataDir := path.Join(uri.Host, uri.Path)
|
|
||||||
opts := &opt.Options{}
|
opts := &opt.Options{}
|
||||||
for k, v := range uri.Query() {
|
for k, v := range uri.Query() {
|
||||||
switch replacer.Replace(strings.ToLower(k)) {
|
switch replacer.Replace(strings.ToLower(k)) {
|
||||||
|
@ -134,7 +166,11 @@ func (m *Manager) GetLevelDB(connection string) (*leveldb.DB, error) {
|
||||||
db.db, err = leveldb.OpenFile(dataDir, opts)
|
db.db, err = leveldb.OpenFile(dataDir, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.IsCorrupted(err) {
|
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)
|
db.db, err = leveldb.RecoverFile(dataDir, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue