github.com/celestiaorg/celestia-node@v0.15.0-beta.1/share/p2p/peers/timedqueue.go (about)

     1  package peers
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/benbjohnson/clock"
     8  	"github.com/libp2p/go-libp2p/core/peer"
     9  )
    10  
    11  // timedQueue store items for ttl duration and releases it with calling onPop callback. Each item
    12  // is tracked independently
    13  type timedQueue struct {
    14  	sync.Mutex
    15  	items []item
    16  
    17  	// ttl is the amount of time each item exist in the timedQueue
    18  	ttl   time.Duration
    19  	clock clock.Clock
    20  	after *clock.Timer
    21  	// onPop will be called on item peer.ID after it is released
    22  	onPop func(peer.ID)
    23  }
    24  
    25  type item struct {
    26  	peer.ID
    27  	createdAt time.Time
    28  }
    29  
    30  func newTimedQueue(ttl time.Duration, onPop func(peer.ID)) *timedQueue {
    31  	return &timedQueue{
    32  		items: make([]item, 0),
    33  		clock: clock.New(),
    34  		ttl:   ttl,
    35  		onPop: onPop,
    36  	}
    37  }
    38  
    39  // releaseExpired will release all expired items
    40  func (q *timedQueue) releaseExpired() {
    41  	q.Lock()
    42  	defer q.Unlock()
    43  	q.releaseUnsafe()
    44  }
    45  
    46  func (q *timedQueue) releaseUnsafe() {
    47  	if len(q.items) == 0 {
    48  		return
    49  	}
    50  
    51  	var i int
    52  	for _, next := range q.items {
    53  		timeIn := q.clock.Since(next.createdAt)
    54  		if timeIn < q.ttl {
    55  			// item is not expired yet, create a timer that will call releaseExpired
    56  			q.after.Stop()
    57  			q.after = q.clock.AfterFunc(q.ttl-timeIn, q.releaseExpired)
    58  			break
    59  		}
    60  
    61  		// item is expired
    62  		q.onPop(next.ID)
    63  		i++
    64  	}
    65  
    66  	if i > 0 {
    67  		copy(q.items, q.items[i:])
    68  		q.items = q.items[:len(q.items)-i]
    69  	}
    70  }
    71  
    72  func (q *timedQueue) push(peerID peer.ID) {
    73  	q.Lock()
    74  	defer q.Unlock()
    75  
    76  	q.items = append(q.items, item{
    77  		ID:        peerID,
    78  		createdAt: q.clock.Now(),
    79  	})
    80  
    81  	// if it is the first item in queue, create a timer to call releaseExpired after its expiration
    82  	if len(q.items) == 1 {
    83  		q.after = q.clock.AfterFunc(q.ttl, q.releaseExpired)
    84  	}
    85  }
    86  
    87  func (q *timedQueue) len() int {
    88  	q.Lock()
    89  	defer q.Unlock()
    90  	return len(q.items)
    91  }