dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/utils/buffer/unbounded.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* 19 * 20 * Copyright 2019 gRPC authors. 21 * 22 */ 23 24 // Package buffer provides an implementation of an unbounded buffer. 25 package buffer 26 27 import ( 28 "sync" 29 ) 30 31 // Unbounded is an implementation of an unbounded buffer which does not use 32 // extra goroutines. This is typically used for passing updates from one entity 33 // to another within gRPC. 34 // 35 // All methods on this type are thread-safe and don't block on anything except 36 // the underlying mutex used for synchronization. 37 // 38 // Unbounded supports values of any type to be stored in it by using a channel 39 // of `interface{}`. This means that a call to Put() incurs an extra memory 40 // allocation, and also that users need a type assertion while reading. For 41 // performance critical code paths, using Unbounded is strongly discouraged and 42 // defining a new type specific implementation of this buffer is preferred. See 43 // internal/transport/transport.go for an example of this. 44 type Unbounded struct { 45 c chan interface{} 46 mu sync.Mutex 47 backlog []interface{} 48 } 49 50 // NewUnbounded returns a new instance of Unbounded. 51 func NewUnbounded() *Unbounded { 52 return &Unbounded{c: make(chan interface{}, 1)} 53 } 54 55 // Put adds t to the unbounded buffer. 56 func (b *Unbounded) Put(t interface{}) { 57 b.mu.Lock() 58 if len(b.backlog) == 0 { 59 select { 60 case b.c <- t: 61 b.mu.Unlock() 62 return 63 default: 64 } 65 } 66 b.backlog = append(b.backlog, t) 67 b.mu.Unlock() 68 } 69 70 // Load sends the earliest buffered data, if any, onto the read channel 71 // returned by Get(). Users are expected to call this every time they read a 72 // value from the read channel. 73 func (b *Unbounded) Load() { 74 b.mu.Lock() 75 if len(b.backlog) > 0 { 76 select { 77 case b.c <- b.backlog[0]: 78 b.backlog[0] = nil 79 b.backlog = b.backlog[1:] 80 default: 81 } 82 } 83 b.mu.Unlock() 84 } 85 86 // Get returns a read channel on which values added to the buffer, via Put(), 87 // are sent on. 88 // 89 // Upon reading a value from this channel, users are expected to call Load() to 90 // send the next buffered value onto the channel if there is any. 91 func (b *Unbounded) Get() <-chan interface{} { 92 return b.c 93 }