2019-05-24 06:47:08 +03:00
|
|
|
package wtdb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
2020-01-10 05:45:04 +03:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
2019-05-24 06:47:08 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// dbFilePermission requests read+write access to the db file.
|
|
|
|
dbFilePermission = 0600
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// metadataBkt stores all the meta information concerning the state of
|
|
|
|
// the database.
|
|
|
|
metadataBkt = []byte("metadata-bucket")
|
|
|
|
|
|
|
|
// dbVersionKey is a static key used to retrieve the database version
|
|
|
|
// number from the metadataBkt.
|
|
|
|
dbVersionKey = []byte("version")
|
|
|
|
|
|
|
|
// ErrUninitializedDB signals that top-level buckets for the database
|
|
|
|
// have not been initialized.
|
|
|
|
ErrUninitializedDB = errors.New("db not initialized")
|
|
|
|
|
|
|
|
// ErrNoDBVersion signals that the database contains no version info.
|
|
|
|
ErrNoDBVersion = errors.New("db has no version")
|
|
|
|
|
|
|
|
// byteOrder is the default endianness used when serializing integers.
|
|
|
|
byteOrder = binary.BigEndian
|
|
|
|
)
|
|
|
|
|
|
|
|
// fileExists returns true if the file exists, and false otherwise.
|
|
|
|
func fileExists(path string) bool {
|
|
|
|
if _, err := os.Stat(path); err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// createDBIfNotExist opens the boltdb database at dbPath/name, creating one if
|
|
|
|
// one doesn't exist. The boolean returned indicates if the database did not
|
|
|
|
// exist before, or if it has been created but no version metadata exists within
|
|
|
|
// it.
|
2020-01-10 05:45:04 +03:00
|
|
|
func createDBIfNotExist(dbPath, name string) (kvdb.Backend, bool, error) {
|
2019-05-24 06:47:08 +03:00
|
|
|
path := filepath.Join(dbPath, name)
|
|
|
|
|
|
|
|
// If the database file doesn't exist, this indicates we much initialize
|
|
|
|
// a fresh database with the latest version.
|
|
|
|
firstInit := !fileExists(path)
|
|
|
|
if firstInit {
|
|
|
|
// Ensure all parent directories are initialized.
|
|
|
|
err := os.MkdirAll(dbPath, 0700)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-09 01:41:25 +03:00
|
|
|
// Specify bbolt freelist options to reduce heap pressure in case the
|
|
|
|
// freelist grows to be very large.
|
2020-01-10 05:45:04 +03:00
|
|
|
bdb, err := kvdb.Create(kvdb.BoltBackendName, path, true)
|
2019-05-24 06:47:08 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the file existed previously, we'll now check to see that the
|
|
|
|
// metadata bucket is properly initialized. It could be the case that
|
|
|
|
// the database was created, but we failed to actually populate any
|
|
|
|
// metadata. If the metadata bucket does not actually exist, we'll
|
|
|
|
// set firstInit to true so that we can treat is initialize the bucket.
|
|
|
|
if !firstInit {
|
|
|
|
var metadataExists bool
|
2020-05-07 01:45:50 +03:00
|
|
|
err = kvdb.View(bdb, func(tx kvdb.RTx) error {
|
2020-01-10 05:45:04 +03:00
|
|
|
metadataExists = tx.ReadBucket(metadataBkt) != nil
|
2019-05-24 06:47:08 +03:00
|
|
|
return nil
|
2020-10-20 17:18:40 +03:00
|
|
|
}, func() {
|
|
|
|
metadataExists = false
|
2019-05-24 06:47:08 +03:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !metadataExists {
|
|
|
|
firstInit = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return bdb, firstInit, nil
|
|
|
|
}
|