Skip to content

Commit 613ca36

Browse files
authored
Merge pull request #95 from openshift-kni/pfpstatus-max-size-prep
pfpstatus: record: generalize API
2 parents e0bd23e + 53d8d09 commit 613ca36

2 files changed

Lines changed: 46 additions & 26 deletions

File tree

pkg/pfpstatus/record/recorder.go

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,53 @@ type NodeRecorder struct {
5454
statuses []RecordedStatus
5555
}
5656

57+
type NodeOption func(*NodeRecorder)
58+
59+
func WithCapacity(capacity int) NodeOption {
60+
return func(nr *NodeRecorder) {
61+
nr.capacity = capacity
62+
}
63+
}
64+
5765
// NewNodeRecorder creates a new recorder for the given node with the given capacity.
5866
// The record is a ring buffer, so only the latest <capacity> Statuses are kept at any time.
5967
// The timestamper callback is used to mark times. Use `time.Now` if unsure.
6068
// Returns the newly created instance; if parameters are incorrect, returns an error, on which
6169
// case the returned instance should be ignored.
62-
func NewNodeRecorder(nodeName string, capacity int, timestamper Timestamper) (*NodeRecorder, error) {
70+
func NewNodeRecorder(nodeName string, timestamper Timestamper, opts ...NodeOption) (*NodeRecorder, error) {
6371
if nodeName == "" {
6472
return nil, ErrMissingNode
6573
}
66-
if capacity < 1 {
67-
return nil, ErrInvalidCapacity
68-
}
6974
nr := NodeRecorder{
7075
timestamper: timestamper,
7176
nodeName: nodeName,
72-
capacity: capacity,
7377
}
74-
if capacity == 1 { // handle common special case
78+
for _, opt := range opts {
79+
opt(&nr)
80+
}
81+
if nr.capacity < 1 {
82+
return nil, ErrInvalidCapacity
83+
}
84+
if nr.capacity == 1 { // handle common special case
7585
nr.statuses = make([]RecordedStatus, 1)
7686
}
7787
return &nr, nil
7888
}
7989

90+
func (nr *NodeRecorder) dropOldest() {
91+
if nr.Len() < 1 {
92+
return
93+
}
94+
nr.statuses = nr.statuses[1:]
95+
}
96+
97+
func (nr *NodeRecorder) makeRoom() {
98+
if nr.Len() < nr.Cap() {
99+
return
100+
}
101+
nr.dropOldest()
102+
}
103+
80104
// Push adds a new Status to the record, evicting the oldest Status if necessary.
81105
// The pushed status is a full independent copy of the provided Status.
82106
// If the Status added is inconsistent, returns an error detailing the reason.
@@ -88,21 +112,17 @@ func (nr *NodeRecorder) Push(st podfingerprint.Status) error {
88112
if st.NodeName != nr.nodeName {
89113
return ErrMismatchingNode
90114
}
115+
ts := nr.timestamper()
116+
item := RecordedStatus{
117+
Status: st.Clone(),
118+
RecordTime: ts,
119+
}
91120
if nr.capacity == 1 { // handle common special case, avoid any resize
92-
nr.statuses[0] = RecordedStatus{
93-
Status: st.Clone(),
94-
RecordTime: nr.timestamper(),
95-
}
121+
nr.statuses[0] = item
96122
return nil
97123
}
98-
if nr.Len() == nr.Cap() {
99-
// drop the older sample
100-
nr.statuses = nr.statuses[1:]
101-
}
102-
nr.statuses = append(nr.statuses, RecordedStatus{
103-
Status: st.Clone(),
104-
RecordTime: nr.timestamper(),
105-
})
124+
nr.makeRoom()
125+
nr.statuses = append(nr.statuses, item)
106126
return nil
107127
}
108128

@@ -203,7 +223,7 @@ func (rr *Recorder) Push(st podfingerprint.Status) error {
203223
}
204224

205225
if !ok {
206-
nr, err = NewNodeRecorder(st.NodeName, rr.nodeCapacity, rr.timestamper)
226+
nr, err = NewNodeRecorder(st.NodeName, rr.timestamper, WithCapacity(rr.nodeCapacity))
207227
if err != nil {
208228
return err
209229
}

pkg/pfpstatus/record/recorder_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
)
2727

2828
func TestNodeRecorderCreate(t *testing.T) {
29-
nr, err := NewNodeRecorder("test-node", 16, time.Now)
29+
nr, err := NewNodeRecorder("test-node", time.Now, WithCapacity(16))
3030
if err != nil {
3131
t.Fatalf("unexpected error: %v", err)
3232
}
@@ -40,7 +40,7 @@ func TestNodeRecorderCreate(t *testing.T) {
4040
}
4141

4242
func TestNodeRecorderCreateInvalid(t *testing.T) {
43-
_, err := NewNodeRecorder("test-node", 0, time.Now)
43+
_, err := NewNodeRecorder("test-node", time.Now)
4444
if err == nil {
4545
t.Fatalf("unexpected success")
4646
}
@@ -50,7 +50,7 @@ func TestNodeRecorderCreateInvalid(t *testing.T) {
5050
}
5151

5252
func TestNodeRecorderPushMissingNodeName(t *testing.T) {
53-
nr, err := NewNodeRecorder("test-node", 16, time.Now)
53+
nr, err := NewNodeRecorder("test-node", time.Now, WithCapacity(16))
5454
if err != nil {
5555
t.Fatalf("unexpected error: %v", err)
5656
}
@@ -66,7 +66,7 @@ func TestNodeRecorderPushMissingNodeName(t *testing.T) {
6666
}
6767

6868
func TestNodeRecorderPushMismatchingNodeName(t *testing.T) {
69-
nr, err := NewNodeRecorder("test-node", 16, time.Now)
69+
nr, err := NewNodeRecorder("test-node", time.Now, WithCapacity(16))
7070
if err != nil {
7171
t.Fatalf("unexpected error: %v", err)
7272
}
@@ -82,7 +82,7 @@ func TestNodeRecorderPushMismatchingNodeName(t *testing.T) {
8282
}
8383

8484
func TestNodeRecorderPushBasic(t *testing.T) {
85-
nr, err := NewNodeRecorder("test-node", 16, time.Now)
85+
nr, err := NewNodeRecorder("test-node", time.Now, WithCapacity(16))
8686
if err != nil {
8787
t.Fatalf("unexpected error: %v", err)
8888
}
@@ -98,7 +98,7 @@ func TestNodeRecorderPushBasic(t *testing.T) {
9898
}
9999

100100
func TestNodeRecorderSingleEntryPushEvict(t *testing.T) {
101-
nr, err := NewNodeRecorder("test-node", 1, time.Now)
101+
nr, err := NewNodeRecorder("test-node", time.Now, WithCapacity(1))
102102
if err != nil {
103103
t.Fatalf("unexpected error: %v", err)
104104
}
@@ -132,7 +132,7 @@ func TestNodeRecorderSingleEntryPushEvict(t *testing.T) {
132132
}
133133

134134
func TestNodeRecorderMultiEntryPushContentEvict(t *testing.T) {
135-
nr, err := NewNodeRecorder("test-node", 3, time.Now)
135+
nr, err := NewNodeRecorder("test-node", time.Now, WithCapacity(3))
136136
if err != nil {
137137
t.Fatalf("unexpected error: %v", err)
138138
}

0 commit comments

Comments
 (0)