mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
b16df45076
In this commit, a new session-ID index is added to the tower client db with the help of a migration. This index holds a mapping from a db-assigned-ID (a uint64 encoded using BigSize encoding) to real session ID (33 bytes). This mapping will help us save space in future when persisting references to sessions.
115 lines
3.4 KiB
Go
115 lines
3.4 KiB
Go
package migration6
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
|
|
"github.com/lightningnetwork/lnd/kvdb"
|
|
"github.com/lightningnetwork/lnd/tlv"
|
|
)
|
|
|
|
var (
|
|
// cSessionBkt is a top-level bucket storing:
|
|
// session-id => cSessionBody -> encoded ClientSessionBody
|
|
// => cSessionDBID -> db-assigned-id
|
|
// => cSessionCommits => seqnum -> encoded CommittedUpdate
|
|
// => cSessionAcks => seqnum -> encoded BackupID
|
|
cSessionBkt = []byte("client-session-bucket")
|
|
|
|
// cSessionDBID is a key used in the cSessionBkt to store the
|
|
// db-assigned-id of a session.
|
|
cSessionDBID = []byte("client-session-db-id")
|
|
|
|
// cSessionIDIndexBkt is a top-level bucket storing:
|
|
// db-assigned-id -> session-id
|
|
cSessionIDIndexBkt = []byte("client-session-id-index")
|
|
|
|
// cSessionBody is a sub-bucket of cSessionBkt storing only the body of
|
|
// the ClientSession.
|
|
cSessionBody = []byte("client-session-body")
|
|
|
|
// ErrUninitializedDB signals that top-level buckets for the database
|
|
// have not been initialized.
|
|
ErrUninitializedDB = errors.New("db not initialized")
|
|
|
|
// ErrCorruptClientSession signals that the client session's on-disk
|
|
// structure deviates from what is expected.
|
|
ErrCorruptClientSession = errors.New("client session corrupted")
|
|
|
|
byteOrder = binary.BigEndian
|
|
)
|
|
|
|
// MigrateSessionIDIndex adds a new session ID index to the tower client db.
|
|
// This index is a mapping from db-assigned ID (a uint64 encoded using BigSize)
|
|
// to real session ID (33 bytes). This mapping will allow us to persist session
|
|
// pointers with fewer bytes in the future.
|
|
func MigrateSessionIDIndex(tx kvdb.RwTx) error {
|
|
log.Infof("Migrating the tower client db to add a new session ID " +
|
|
"index which stores a mapping from db-assigned ID to real " +
|
|
"session ID")
|
|
|
|
// Create a new top-level bucket for the index.
|
|
indexBkt, err := tx.CreateTopLevelBucket(cSessionIDIndexBkt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get the existing top-level sessions bucket.
|
|
sessionsBkt := tx.ReadWriteBucket(cSessionBkt)
|
|
if sessionsBkt == nil {
|
|
return ErrUninitializedDB
|
|
}
|
|
|
|
// Iterate over the sessions bucket where each key is a session-ID.
|
|
return sessionsBkt.ForEach(func(sessionID, _ []byte) error {
|
|
// Ask the DB for a new, unique, id for the index bucket.
|
|
nextSeq, err := indexBkt.NextSequence()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
newIndex, err := writeBigSize(nextSeq)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Add the new db-assigned-ID to real-session-ID pair to the
|
|
// new index bucket.
|
|
err = indexBkt.Put(newIndex, sessionID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get the sub-bucket for this specific session ID.
|
|
sessionBkt := sessionsBkt.NestedReadWriteBucket(sessionID)
|
|
if sessionBkt == nil {
|
|
return ErrCorruptClientSession
|
|
}
|
|
|
|
// Here we ensure that the session bucket includes a session
|
|
// body. The only reason we do this is so that we can simulate
|
|
// a migration fail in a test to ensure that a migration fail
|
|
// results in an untouched db.
|
|
sessionBodyBytes := sessionBkt.Get(cSessionBody)
|
|
if sessionBodyBytes == nil {
|
|
return ErrCorruptClientSession
|
|
}
|
|
|
|
// Add the db-assigned ID of the session to the session under
|
|
// the cSessionDBID key.
|
|
return sessionBkt.Put(cSessionDBID, newIndex)
|
|
})
|
|
}
|
|
|
|
// writeBigSize will encode the given uint64 as a BigSize byte slice.
|
|
func writeBigSize(i uint64) ([]byte, error) {
|
|
var b bytes.Buffer
|
|
err := tlv.WriteVarInt(&b, i, &[8]byte{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return b.Bytes(), nil
|
|
}
|