github.com/decred/dcrlnd@v0.7.6/channeldb/peers.go (about)

     1  package channeldb
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"time"
     7  
     8  	"github.com/decred/dcrlnd/kvdb"
     9  	"github.com/decred/dcrlnd/routing/route"
    10  )
    11  
    12  var (
    13  	// peersBucket is the name of a top level bucket in which we store
    14  	// information about our peers. Information for different peers is
    15  	// stored in buckets keyed by their public key.
    16  	//
    17  	//
    18  	// peers-bucket
    19  	//      |
    20  	//      |-- <peer-pubkey>
    21  	//      |        |--flap-count-key: <ts><flap count>
    22  	//      |
    23  	//      |-- <peer-pubkey>
    24  	//      |        |--flap-count-key: <ts><flap count>
    25  	//
    26  	// Note(decred): each peer has an additional value set:
    27  	//               |--last-gossip-msg-ts: <ts>
    28  	peersBucket = []byte("peers-bucket")
    29  
    30  	// flapCountKey is a key used in the peer pubkey sub-bucket that stores
    31  	// the timestamp of a peer's last flap count and its all time flap
    32  	// count.
    33  	flapCountKey = []byte("flap-count")
    34  )
    35  
    36  var (
    37  	// ErrNoPeerBucket is returned when we try to read entries for a peer
    38  	// that is not tracked.
    39  	ErrNoPeerBucket = errors.New("peer bucket not found")
    40  )
    41  
    42  // FlapCount contains information about a peer's flap count.
    43  type FlapCount struct {
    44  	// Count provides the total flap count for a peer.
    45  	Count uint32
    46  
    47  	// LastFlap is the timestamp of the last flap recorded for a peer.
    48  	LastFlap time.Time
    49  }
    50  
    51  // WriteFlapCounts writes the flap count for a set of peers to disk, creating a
    52  // bucket for the peer's pubkey if necessary. Note that this function overwrites
    53  // the current value.
    54  func (d *DB) WriteFlapCounts(flapCounts map[route.Vertex]*FlapCount) error {
    55  	return kvdb.Update(d, func(tx kvdb.RwTx) error {
    56  		// Run through our set of flap counts and record them for
    57  		// each peer, creating a bucket for the peer pubkey if required.
    58  		for peer, flapCount := range flapCounts {
    59  			peers := tx.ReadWriteBucket(peersBucket)
    60  
    61  			peerBucket, err := peers.CreateBucketIfNotExists(
    62  				peer[:],
    63  			)
    64  			if err != nil {
    65  				return err
    66  			}
    67  
    68  			var b bytes.Buffer
    69  			err = serializeTime(&b, flapCount.LastFlap)
    70  			if err != nil {
    71  				return err
    72  			}
    73  
    74  			if err = WriteElement(&b, flapCount.Count); err != nil {
    75  				return err
    76  			}
    77  
    78  			err = peerBucket.Put(flapCountKey, b.Bytes())
    79  			if err != nil {
    80  				return err
    81  			}
    82  		}
    83  
    84  		return nil
    85  	}, func() {})
    86  }
    87  
    88  // ReadFlapCount attempts to read the flap count for a peer, failing if the
    89  // peer is not found or we do not have flap count stored.
    90  func (d *DB) ReadFlapCount(pubkey route.Vertex) (*FlapCount, error) {
    91  	var flapCount FlapCount
    92  
    93  	if err := kvdb.View(d, func(tx kvdb.RTx) error {
    94  		peers := tx.ReadBucket(peersBucket)
    95  
    96  		peerBucket := peers.NestedReadBucket(pubkey[:])
    97  		if peerBucket == nil {
    98  			return ErrNoPeerBucket
    99  		}
   100  
   101  		flapBytes := peerBucket.Get(flapCountKey)
   102  		if flapBytes == nil {
   103  			// Note(decred): in lnd this returns an opaque error,
   104  			// but we may have entries in the peersBucket that
   105  			// may not have a set flapCountKey, so return the same
   106  			// error that flags that the info does not exist for
   107  			// this peer.
   108  			return ErrNoPeerBucket
   109  		}
   110  
   111  		var (
   112  			err error
   113  			r   = bytes.NewReader(flapBytes)
   114  		)
   115  
   116  		flapCount.LastFlap, err = deserializeTime(r)
   117  		if err != nil {
   118  			return err
   119  		}
   120  
   121  		return ReadElements(r, &flapCount.Count)
   122  	}, func() {
   123  		flapCount = FlapCount{}
   124  	}); err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	return &flapCount, nil
   129  }