-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[chore] Simplify sized channel by not using a channel, remove corner …
…case Signed-off-by: Bogdan Drutu <[email protected]>
- Loading branch information
1 parent
da5b68a
commit 02391f7
Showing
5 changed files
with
184 additions
and
120 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 was deleted.
Oops, something went wrong.
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,124 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package exporterqueue // import "go.opentelemetry.io/collector/exporter/exporterqueue" | ||
|
||
import ( | ||
"sync" | ||
) | ||
|
||
type node[T any] struct { | ||
data T | ||
size int64 | ||
next *node[T] | ||
} | ||
|
||
type linkedQueue[T any] struct { | ||
head *node[T] | ||
tail *node[T] | ||
} | ||
|
||
func (l *linkedQueue[T]) push(data T, size int64) { | ||
n := &node[T]{data: data, size: size} | ||
if l.tail == nil { | ||
l.head = n | ||
l.tail = n | ||
return | ||
} | ||
l.tail.next = n | ||
l.tail = n | ||
} | ||
|
||
func (l *linkedQueue[T]) pop() (T, int64) { | ||
n := l.head | ||
l.head = n.next | ||
if l.head == nil { | ||
l.tail = nil | ||
} | ||
return n.data, n.size | ||
} | ||
|
||
// sizedQueue is a channel wrapper for sized elements with a capacity set to a total size of all the elements. | ||
// The channel will accept elements until the total size of the elements reaches the capacity. | ||
type sizedQueue[T any] struct { | ||
sizer sizer[T] | ||
cap int64 | ||
|
||
mu sync.Mutex | ||
hasElements *sync.Cond | ||
items *linkedQueue[T] | ||
size int64 | ||
stopped bool | ||
} | ||
|
||
// newSizedQueue creates a sized elements channel. Each element is assigned a size by the provided sizer. | ||
// capacity is the capacity of the queue. | ||
func newSizedQueue[T any](capacity int64, sizer sizer[T]) *sizedQueue[T] { | ||
sq := &sizedQueue[T]{ | ||
sizer: sizer, | ||
cap: capacity, | ||
items: &linkedQueue[T]{}, | ||
} | ||
sq.hasElements = sync.NewCond(&sq.mu) | ||
return sq | ||
} | ||
|
||
// push puts the element into the queue with the given sized if there is enough capacity. | ||
// Returns an error if the queue is full. | ||
func (sq *sizedQueue[T]) push(el T) error { | ||
elSize := sq.sizer.Sizeof(el) | ||
|
||
sq.mu.Lock() | ||
defer sq.mu.Unlock() | ||
|
||
if sq.size+elSize > sq.cap { | ||
return ErrQueueIsFull | ||
} | ||
|
||
sq.size += elSize | ||
sq.items.push(el, elSize) | ||
// Signal one consumer if any. | ||
sq.hasElements.Signal() | ||
return nil | ||
} | ||
|
||
// pop removes the element from the queue and returns it. | ||
// The call blocks until there is an item available or the queue is stopped. | ||
// The function returns true when an item is consumed or false if the queue is stopped and emptied. | ||
func (sq *sizedQueue[T]) pop() (T, bool) { | ||
sq.mu.Lock() | ||
defer sq.mu.Unlock() | ||
|
||
for { | ||
if sq.size > 0 { | ||
el, elSize := sq.items.pop() | ||
sq.size -= elSize | ||
return el, true | ||
} | ||
|
||
if sq.stopped { | ||
var el T | ||
return el, false | ||
} | ||
|
||
sq.hasElements.Wait() | ||
} | ||
} | ||
|
||
// shutdown closes the queue channel to initiate draining of the queue. | ||
func (sq *sizedQueue[T]) shutdown() { | ||
sq.mu.Lock() | ||
defer sq.mu.Unlock() | ||
sq.stopped = true | ||
sq.hasElements.Broadcast() | ||
} | ||
|
||
func (sq *sizedQueue[T]) Size() int { | ||
sq.mu.Lock() | ||
defer sq.mu.Unlock() | ||
return int(sq.size) | ||
} | ||
|
||
func (sq *sizedQueue[T]) Capacity() int { | ||
return int(sq.cap) | ||
} |
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