channeldb: add optional meta and migration30

This commit enables the db to run optional migrations that are specified
by config flags. To achieve this, an optional meta is introduced to
manage the optional migrations. We distinguish the two types of
migrations here so it's easier to manage them for the concern a future
migration can cause trouble for us to determine the db version if we
don't.
This commit is contained in:
yyforyongyu
2022-04-28 06:46:37 +08:00
parent 1832a93d19
commit afb2f72ce2
4 changed files with 309 additions and 17 deletions

View File

@@ -1,7 +1,11 @@
package channeldb
import (
"bytes"
"fmt"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/tlv"
)
var (
@@ -12,6 +16,10 @@ var (
// dbVersionKey is a boltdb key and it's used for storing/retrieving
// current database version.
dbVersionKey = []byte("dbp")
// dbVersionKey is a boltdb key and it's used for storing/retrieving
// a list of optional migrations that have been applied.
optionalVersionKey = []byte("ovk")
)
// Meta structure holds the database meta information.
@@ -80,3 +88,92 @@ func putDbVersion(metaBucket kvdb.RwBucket, meta *Meta) error {
byteOrder.PutUint32(scratch, meta.DbVersionNumber)
return metaBucket.Put(dbVersionKey, scratch)
}
// OptionalMeta structure holds the database optional migration information.
type OptionalMeta struct {
// Versions is a set that contains the versions that have been applied.
// When saved to disk, only the indexes are stored.
Versions map[uint64]string
}
func (om *OptionalMeta) String() string {
s := ""
for index, name := range om.Versions {
s += fmt.Sprintf("%d: %s", index, name)
}
if s == "" {
s = "empty"
}
return s
}
// fetchOptionalMeta reads the optional meta from the database.
func (d *DB) fetchOptionalMeta() (*OptionalMeta, error) {
om := &OptionalMeta{
Versions: make(map[uint64]string),
}
err := kvdb.View(d, func(tx kvdb.RTx) error {
metaBucket := tx.ReadBucket(metaBucket)
if metaBucket == nil {
return ErrMetaNotFound
}
vBytes := metaBucket.Get(optionalVersionKey)
// Exit early if nothing found.
if vBytes == nil {
return nil
}
// Read the versions' length.
r := bytes.NewReader(vBytes)
vLen, err := tlv.ReadVarInt(r, &[8]byte{})
if err != nil {
return err
}
// Write the version index.
for i := uint64(0); i < vLen; i++ {
version, err := tlv.ReadVarInt(r, &[8]byte{})
if err != nil {
return err
}
om.Versions[version] = optionalVersions[i].name
}
return nil
}, func() {})
if err != nil {
return nil, err
}
return om, nil
}
// fetchOptionalMeta writes an optional meta to the database.
func (d *DB) putOptionalMeta(om *OptionalMeta) error {
return kvdb.Update(d, func(tx kvdb.RwTx) error {
metaBucket, err := tx.CreateTopLevelBucket(metaBucket)
if err != nil {
return err
}
var b bytes.Buffer
// Write the total length.
err = tlv.WriteVarInt(&b, uint64(len(om.Versions)), &[8]byte{})
if err != nil {
return err
}
// Write the version indexes.
for v := range om.Versions {
err := tlv.WriteVarInt(&b, v, &[8]byte{})
if err != nil {
return err
}
}
return metaBucket.Put(optionalVersionKey, b.Bytes())
}, func() {})
}