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

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