package wtdb import ( "encoding/binary" "errors" "os" "path/filepath" "time" "github.com/lightningnetwork/lnd/kvdb" ) 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. func createDBIfNotExist(dbPath, name string, dbTimeout time.Duration) (kvdb.Backend, bool, error) { 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 } } // Specify bbolt freelist options to reduce heap pressure in case the // freelist grows to be very large. bdb, err := kvdb.Create( kvdb.BoltBackendName, path, true, dbTimeout, ) 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 err = kvdb.View(bdb, func(tx kvdb.RTx) error { metadataExists = tx.ReadBucket(metadataBkt) != nil return nil }, func() { metadataExists = false }) if err != nil { return nil, false, err } if !metadataExists { firstInit = true } } return bdb, firstInit, nil }