channeldb: further GC optimizations during path finding

In this commit, we made a series of modification to the way we handle
reading edges and vertexes from disk, in order to reduce the amount of
garbage generated:
  1. Properly use PubKeyBytes are required rather than PubKey()
  2. Return direct structs rather than pointers, and leave it to the
runtime to perform escape analysis.
  3. In-line the former readSig() method when reading sigs from disk.
This commit is contained in:
Olaoluwa Osuntokun 2018-02-12 16:17:08 -08:00
parent 03abc73e8d
commit 3e422fedd3
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
1 changed files with 50 additions and 64 deletions

View File

@ -210,7 +210,7 @@ func (c *ChannelGraph) ForEachChannel(cb func(*ChannelEdgeInfo, *ChannelEdgePoli
// With both edges read, execute the call back. IF this
// function returns an error then the transaction will
// be aborted.
return cb(edgeInfo, edge1, edge2)
return cb(&edgeInfo, edge1, edge2)
})
})
}
@ -253,7 +253,7 @@ func (c *ChannelGraph) ForEachNode(tx *bolt.Tx, cb func(*bolt.Tx, *LightningNode
// Execute the callback, the transaction will abort if
// this returns an error.
return cb(tx, node)
return cb(tx, &node)
})
}
@ -294,7 +294,7 @@ func (c *ChannelGraph) SourceNode() (*LightningNode, error) {
return err
}
source = node
source = &node
source.db = c.db
return nil
})
@ -622,7 +622,7 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint,
if err != nil {
return err
}
chansClosed = append(chansClosed, edgeInfo)
chansClosed = append(chansClosed, &edgeInfo)
// Attempt to delete the channel, an ErrEdgeNotFound
// will be returned if that outpoint isn't known to be
@ -727,7 +727,7 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf
return err
}
removedChans = append(removedChans, edgeInfo)
removedChans = append(removedChans, &edgeInfo)
}
// Delete all the entries in the prune log having a height
@ -1081,7 +1081,7 @@ func (c *ChannelGraph) FetchLightningNode(pub *btcec.PublicKey) (*LightningNode,
}
n.db = c.db
node = n
node = &n
return nil
})
@ -1153,11 +1153,7 @@ func (c *ChannelGraph) HasLightningNode(nodePub [33]byte) (time.Time, bool, erro
func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
cb func(*bolt.Tx, *ChannelEdgeInfo, *ChannelEdgePolicy, *ChannelEdgePolicy) error) error {
pub, err := l.PubKey()
if err != nil {
return err
}
nodePub := pub.SerializeCompressed()
nodePub := l.PubKeyBytes[:]
traversal := func(tx *bolt.Tx) error {
nodes := tx.Bucket(nodeBucket)
@ -1210,12 +1206,7 @@ func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
// We'll also fetch the incoming edge so this
// information can be available to the caller.
incomingNodeKey, err := toEdgePolicy.Node.PubKey()
if err != nil {
return err
}
incomingNode := incomingNodeKey.SerializeCompressed()
incomingNode := toEdgePolicy.Node.PubKeyBytes[:]
fromEdgePolicy, err := fetchChanEdgePolicy(
edges, chanID, incomingNode, nodes,
)
@ -1231,7 +1222,7 @@ func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
}
// Finally, we execute the callback.
err = cb(tx, edgeInfo, toEdgePolicy, fromEdgePolicy)
err = cb(tx, &edgeInfo, toEdgePolicy, fromEdgePolicy)
if err != nil {
return err
}
@ -1658,7 +1649,7 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (*ChannelE
if err != nil {
return err
}
edgeInfo = edge
edgeInfo = &edge
// Once we have the information about the channels' parameters,
// we'll fetch the routing policies for each for the directed
@ -1720,7 +1711,7 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) (*ChannelEdgeInfo, *
if err != nil {
return err
}
edgeInfo = edge
edgeInfo = &edge
e1, e2, err := fetchChanEdgePolicies(edgeIndex, edges, nodes,
channelID[:], c.db)
@ -1874,38 +1865,37 @@ func putLightningNode(nodeBucket *bolt.Bucket, aliasBucket *bolt.Bucket, node *L
}
func fetchLightningNode(nodeBucket *bolt.Bucket,
nodePub []byte) (*LightningNode, error) {
nodePub []byte) (LightningNode, error) {
nodeBytes := nodeBucket.Get(nodePub)
if nodeBytes == nil {
return nil, ErrGraphNodeNotFound
return LightningNode{}, ErrGraphNodeNotFound
}
nodeReader := bytes.NewReader(nodeBytes)
return deserializeLightningNode(nodeReader)
}
func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
func deserializeLightningNode(r io.Reader) (LightningNode, error) {
var (
node LightningNode
scratch [8]byte
err error
)
node := &LightningNode{}
if _, err := r.Read(scratch[:]); err != nil {
return nil, err
return LightningNode{}, err
}
unix := int64(byteOrder.Uint64(scratch[:]))
node.LastUpdate = time.Unix(unix, 0)
if _, err := io.ReadFull(r, node.PubKeyBytes[:]); err != nil {
return nil, err
return LightningNode{}, err
}
if _, err := r.Read(scratch[:2]); err != nil {
return nil, err
return LightningNode{}, err
}
hasNodeAnn := byteOrder.Uint16(scratch[:2])
@ -1924,29 +1914,29 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
// We did get a node announcement for this node, so we'll have the rest
// of the data available.
if err := binary.Read(r, byteOrder, &node.Color.R); err != nil {
return nil, err
return LightningNode{}, err
}
if err := binary.Read(r, byteOrder, &node.Color.G); err != nil {
return nil, err
return LightningNode{}, err
}
if err := binary.Read(r, byteOrder, &node.Color.B); err != nil {
return nil, err
return LightningNode{}, err
}
node.Alias, err = wire.ReadVarString(r, 0)
if err != nil {
return nil, err
return LightningNode{}, err
}
fv := lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures)
err = fv.Decode(r)
if err != nil {
return nil, err
return LightningNode{}, err
}
node.Features = fv
if _, err := r.Read(scratch[:2]); err != nil {
return nil, err
return LightningNode{}, err
}
numAddresses := int(byteOrder.Uint16(scratch[:2]))
@ -1954,7 +1944,7 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
for i := 0; i < numAddresses; i++ {
address, err := deserializeAddr(r)
if err != nil {
return nil, err
return LightningNode{}, err
}
addresses = append(addresses, address)
}
@ -1962,7 +1952,7 @@ func deserializeLightningNode(r io.Reader) (*LightningNode, error) {
node.AuthSigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig")
if err != nil {
return nil, err
return LightningNode{}, err
}
return node, nil
@ -2027,62 +2017,58 @@ func putChanEdgeInfo(edgeIndex *bolt.Bucket, edgeInfo *ChannelEdgeInfo, chanID [
}
func fetchChanEdgeInfo(edgeIndex *bolt.Bucket,
chanID []byte) (*ChannelEdgeInfo, error) {
chanID []byte) (ChannelEdgeInfo, error) {
edgeInfoBytes := edgeIndex.Get(chanID)
if edgeInfoBytes == nil {
return nil, ErrEdgeNotFound
return ChannelEdgeInfo{}, ErrEdgeNotFound
}
edgeInfoReader := bytes.NewReader(edgeInfoBytes)
return deserializeChanEdgeInfo(edgeInfoReader)
}
func deserializeChanEdgeInfo(r io.Reader) (*ChannelEdgeInfo, error) {
func deserializeChanEdgeInfo(r io.Reader) (ChannelEdgeInfo, error) {
var (
err error
edgeInfo = &ChannelEdgeInfo{}
edgeInfo ChannelEdgeInfo
)
if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
edgeInfo.Features, err = wire.ReadVarBytes(r, 0, 900, "features")
if err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
proof := &ChannelAuthProof{}
readSig := func() ([]byte, error) {
return wire.ReadVarBytes(r, 0, 80, "sigs")
}
proof.NodeSig1Bytes, err = readSig()
proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
proof.NodeSig2Bytes, err = readSig()
proof.NodeSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
proof.BitcoinSig1Bytes, err = readSig()
proof.BitcoinSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
proof.BitcoinSig2Bytes, err = readSig()
proof.BitcoinSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
if !proof.IsEmpty() {
@ -2091,17 +2077,17 @@ func deserializeChanEdgeInfo(r io.Reader) (*ChannelEdgeInfo, error) {
edgeInfo.ChannelPoint = wire.OutPoint{}
if err := readOutpoint(r, &edgeInfo.ChannelPoint); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
if err := binary.Read(r, byteOrder, &edgeInfo.Capacity); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
if err := binary.Read(r, byteOrder, &edgeInfo.ChannelID); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
if _, err := io.ReadFull(r, edgeInfo.ChainHash[:]); err != nil {
return nil, err
return ChannelEdgeInfo{}, err
}
return edgeInfo, nil
@ -2216,11 +2202,11 @@ func deserializeChanEdgePolicy(r io.Reader,
edge := &ChannelEdgePolicy{}
sigBytes, err := wire.ReadVarBytes(r, 0, 80, "sig")
var err error
edge.SigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig")
if err != nil {
return nil, err
}
edge.SigBytes = sigBytes
if err := binary.Read(r, byteOrder, &edge.ChannelID); err != nil {
return nil, err
@ -2266,6 +2252,6 @@ func deserializeChanEdgePolicy(r io.Reader,
return nil, err
}
edge.Node = node
edge.Node = &node
return edge, nil
}