-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add custom ring implementation to the BatchProcessor (#5237)
- Loading branch information
Showing
4 changed files
with
201 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Copyright 2009 The Go 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 log // import "go.opentelemetry.io/otel/sdk/log" | ||
|
||
// A ring is an element of a circular list, or ring. Rings do not have a | ||
// beginning or end; a pointer to any ring element serves as reference to the | ||
// entire ring. Empty rings are represented as nil ring pointers. The zero | ||
// value for a ring is a one-element ring with a nil Value. | ||
// | ||
// This is copied from the "container/ring" package. It uses a Record type for | ||
// Value instead of any to avoid allocations. | ||
type ring struct { | ||
next, prev *ring | ||
Value Record | ||
} | ||
|
||
func (r *ring) init() *ring { | ||
r.next = r | ||
r.prev = r | ||
return r | ||
} | ||
|
||
// Next returns the next ring element. r must not be empty. | ||
func (r *ring) Next() *ring { | ||
if r.next == nil { | ||
return r.init() | ||
} | ||
return r.next | ||
} | ||
|
||
// Prev returns the previous ring element. r must not be empty. | ||
func (r *ring) Prev() *ring { | ||
if r.next == nil { | ||
return r.init() | ||
} | ||
return r.prev | ||
} | ||
|
||
// newRing creates a ring of n elements. | ||
func newRing(n int) *ring { | ||
if n <= 0 { | ||
return nil | ||
} | ||
r := new(ring) | ||
p := r | ||
for i := 1; i < n; i++ { | ||
p.next = &ring{prev: p} | ||
p = p.next | ||
} | ||
p.next = r | ||
r.prev = p | ||
return r | ||
} | ||
|
||
// Len computes the number of elements in ring r. It executes in time | ||
// proportional to the number of elements. | ||
func (r *ring) Len() int { | ||
n := 0 | ||
if r != nil { | ||
n = 1 | ||
for p := r.Next(); p != r; p = p.next { | ||
n++ | ||
} | ||
} | ||
return n | ||
} | ||
|
||
// Do calls function f on each element of the ring, in forward order. The | ||
// behavior of Do is undefined if f changes *r. | ||
func (r *ring) Do(f func(Record)) { | ||
if r != nil { | ||
f(r.Value) | ||
for p := r.Next(); p != r; p = p.next { | ||
f(p.Value) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Copyright 2009 The Go 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 log | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"go.opentelemetry.io/otel/log" | ||
) | ||
|
||
func verifyRing(t *testing.T, r *ring, N int, sum int) { | ||
// Length. | ||
assert.Equal(t, N, r.Len(), "r.Len()") | ||
|
||
// Iteration. | ||
var n, s int | ||
r.Do(func(v Record) { | ||
n++ | ||
body := v.Body() | ||
if body.Kind() != log.KindEmpty { | ||
s += int(body.AsInt64()) | ||
} | ||
}) | ||
assert.Equal(t, N, n, "number of forward iterations") | ||
if sum >= 0 { | ||
assert.Equal(t, sum, s, "forward ring sum") | ||
} | ||
|
||
if r == nil { | ||
return | ||
} | ||
|
||
// Connections. | ||
if r.next != nil { | ||
var p *ring // previous element. | ||
for q := r; p == nil || q != r; q = q.next { | ||
if p != nil { | ||
assert.Equalf(t, p, q.prev, "prev = %p, expected q.prev = %p", p, q.prev) | ||
} | ||
p = q | ||
} | ||
assert.Equalf(t, p, r.prev, "prev = %p, expected r.prev = %p", p, r.prev) | ||
} | ||
|
||
// Next, Prev. | ||
assert.Equal(t, r.next, r.Next(), "r.Next() != r.next") | ||
assert.Equal(t, r.prev, r.Prev(), "r.Prev() != r.prev") | ||
} | ||
|
||
func TestNewRing(t *testing.T) { | ||
for i := 0; i < 10; i++ { | ||
// Empty value. | ||
r := newRing(i) | ||
verifyRing(t, r, i, -1) | ||
} | ||
|
||
for n := 0; n < 10; n++ { | ||
r := newRing(n) | ||
for i := 1; i <= n; i++ { | ||
var rec Record | ||
rec.SetBody(log.IntValue(i)) | ||
r.Value = rec | ||
r = r.Next() | ||
} | ||
|
||
sum := (n*n + n) / 2 | ||
verifyRing(t, r, n, sum) | ||
} | ||
} | ||
|
||
func TestEmptyRing(t *testing.T) { | ||
var rNext, rPrev ring | ||
verifyRing(t, rNext.Next(), 1, 0) | ||
verifyRing(t, rPrev.Prev(), 1, 0) | ||
|
||
var rLen, rDo *ring | ||
assert.Equal(t, rLen.Len(), 0, "Len()") | ||
rDo.Do(func(Record) { assert.Fail(t, "Do func arg called") }) | ||
} |