mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 09:05:18 +00:00
84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
// Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
|
// of this source code is governed by a BSD-style license that can be found in
|
|
// the LICENSE file.
|
|
|
|
package ackseq
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
)
|
|
|
|
const (
|
|
// The window size constants. These values specify a window that can hold ~1m
|
|
// pending unacknowledged sequence numbers using 128 KB of memory.
|
|
windowSize = 1 << 20
|
|
windowMask = windowSize - 1
|
|
windowBytes = (windowSize + 7) / 8
|
|
)
|
|
|
|
// S keeps track of the largest sequence number such that all sequence numbers
|
|
// in the range [0,v) have been acknowledged.
|
|
type S struct {
|
|
next atomic.Uint64
|
|
mu struct {
|
|
sync.Mutex
|
|
base uint64
|
|
window [windowBytes]uint8
|
|
}
|
|
}
|
|
|
|
// New creates a new acknowledged sequence tracker with the specified base
|
|
// sequence number. All of the sequence numbers in the range [0,base) are
|
|
// considered acknowledged. Next() will return base upon first call.
|
|
func New(base uint64) *S {
|
|
s := &S{}
|
|
s.next.Store(base)
|
|
s.mu.base = base
|
|
return s
|
|
}
|
|
|
|
// Next returns the next sequence number to use.
|
|
func (s *S) Next() uint64 {
|
|
return s.next.Add(1) - 1
|
|
}
|
|
|
|
// Ack acknowledges the specified seqNum, adjusting base as necessary,
|
|
// returning the number of newly acknowledged sequence numbers.
|
|
func (s *S) Ack(seqNum uint64) (int, error) {
|
|
s.mu.Lock()
|
|
if s.getLocked(seqNum) {
|
|
defer s.mu.Unlock()
|
|
return 0, errors.Errorf(
|
|
"pending acks exceeds window size: %d has been acked, but %d has not",
|
|
errors.Safe(seqNum), errors.Safe(s.mu.base))
|
|
}
|
|
|
|
var count int
|
|
s.setLocked(seqNum)
|
|
for s.getLocked(s.mu.base) {
|
|
s.clearLocked(s.mu.base)
|
|
s.mu.base++
|
|
count++
|
|
}
|
|
s.mu.Unlock()
|
|
return count, nil
|
|
}
|
|
|
|
func (s *S) getLocked(seqNum uint64) bool {
|
|
bit := seqNum & windowMask
|
|
return (s.mu.window[bit/8] & (1 << (bit % 8))) != 0
|
|
}
|
|
|
|
func (s *S) setLocked(seqNum uint64) {
|
|
bit := seqNum & windowMask
|
|
s.mu.window[bit/8] |= (1 << (bit % 8))
|
|
}
|
|
|
|
func (s *S) clearLocked(seqNum uint64) {
|
|
bit := seqNum & windowMask
|
|
s.mu.window[bit/8] &^= (1 << (bit % 8))
|
|
}
|