| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Copyright 2019 gRPC authors. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Package buffer provides an implementation of an unbounded buffer. | 
					
						
							|  |  |  | package buffer | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Unbounded is an implementation of an unbounded buffer which does not use | 
					
						
							|  |  |  | // extra goroutines. This is typically used for passing updates from one entity | 
					
						
							|  |  |  | // to another within gRPC. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // All methods on this type are thread-safe and don't block on anything except | 
					
						
							|  |  |  | // the underlying mutex used for synchronization. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Unbounded supports values of any type to be stored in it by using a channel | 
					
						
							| 
									
										
										
										
											2023-09-18 13:47:28 +01:00
										 |  |  | // of `any`. This means that a call to Put() incurs an extra memory allocation, | 
					
						
							|  |  |  | // and also that users need a type assertion while reading. For performance | 
					
						
							|  |  |  | // critical code paths, using Unbounded is strongly discouraged and defining a | 
					
						
							|  |  |  | // new type specific implementation of this buffer is preferred. See | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // internal/transport/transport.go for an example of this. | 
					
						
							|  |  |  | type Unbounded struct { | 
					
						
							| 
									
										
										
										
											2023-09-18 13:47:28 +01:00
										 |  |  | 	c       chan any | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 	closed  bool | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | 	closing bool | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	mu      sync.Mutex | 
					
						
							| 
									
										
										
										
											2023-09-18 13:47:28 +01:00
										 |  |  | 	backlog []any | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewUnbounded returns a new instance of Unbounded. | 
					
						
							|  |  |  | func NewUnbounded() *Unbounded { | 
					
						
							| 
									
										
										
										
											2023-09-18 13:47:28 +01:00
										 |  |  | 	return &Unbounded{c: make(chan any, 1)} | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | var errBufferClosed = errors.New("Put called on closed buffer.Unbounded") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // Put adds t to the unbounded buffer. | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | func (b *Unbounded) Put(t any) error { | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	b.mu.Lock() | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 	defer b.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | 	if b.closing { | 
					
						
							|  |  |  | 		return errBufferClosed | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	if len(b.backlog) == 0 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case b.c <- t: | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | 			return nil | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	b.backlog = append(b.backlog, t) | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | // Load sends the earliest buffered data, if any, onto the read channel returned | 
					
						
							|  |  |  | // by Get(). Users are expected to call this every time they successfully read a | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // value from the read channel. | 
					
						
							|  |  |  | func (b *Unbounded) Load() { | 
					
						
							|  |  |  | 	b.mu.Lock() | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 	defer b.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	if len(b.backlog) > 0 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case b.c <- b.backlog[0]: | 
					
						
							|  |  |  | 			b.backlog[0] = nil | 
					
						
							|  |  |  | 			b.backlog = b.backlog[1:] | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | 	} else if b.closing && !b.closed { | 
					
						
							|  |  |  | 		close(b.c) | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get returns a read channel on which values added to the buffer, via Put(), | 
					
						
							|  |  |  | // are sent on. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Upon reading a value from this channel, users are expected to call Load() to | 
					
						
							|  |  |  | // send the next buffered value onto the channel if there is any. | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | // | 
					
						
							|  |  |  | // If the unbounded buffer is closed, the read channel returned by this method | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | // is closed after all data is drained. | 
					
						
							| 
									
										
										
										
											2023-09-18 13:47:28 +01:00
										 |  |  | func (b *Unbounded) Get() <-chan any { | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	return b.c | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | // Close closes the unbounded buffer. No subsequent data may be Put(), and the | 
					
						
							|  |  |  | // channel returned from Get() will be closed after all the data is read and | 
					
						
							|  |  |  | // Load() is called for the final time. | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | func (b *Unbounded) Close() { | 
					
						
							|  |  |  | 	b.mu.Lock() | 
					
						
							|  |  |  | 	defer b.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | 	if b.closing { | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-11 15:34:34 +01:00
										 |  |  | 	b.closing = true | 
					
						
							|  |  |  | 	if len(b.backlog) == 0 { | 
					
						
							|  |  |  | 		b.closed = true | 
					
						
							|  |  |  | 		close(b.c) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | } |