github.com/matrixorigin/matrixone@v0.7.0/pkg/common/morpc/future.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package morpc 16 17 import ( 18 "runtime" 19 "sync" 20 "sync/atomic" 21 ) 22 23 func newFuture(releaseFunc func(f *Future)) *Future { 24 f := &Future{ 25 c: make(chan Message, 1), 26 errC: make(chan error, 1), 27 writtenC: make(chan error, 1), 28 releaseFunc: releaseFunc, 29 } 30 f.setFinalizer() 31 return f 32 } 33 34 // Future is used to obtain response data synchronously. 35 type Future struct { 36 send RPCMessage 37 c chan Message 38 errC chan error 39 // used to check error for sending message 40 writtenC chan error 41 sended atomic.Uint32 42 releaseFunc func(*Future) 43 mu struct { 44 sync.Mutex 45 closed bool 46 ref int 47 cb func() 48 } 49 } 50 51 func (f *Future) init(send RPCMessage) { 52 if _, ok := send.Ctx.Deadline(); !ok { 53 panic("context deadline not set") 54 } 55 f.sended.Store(0) 56 f.send = send 57 f.mu.Lock() 58 f.mu.closed = false 59 f.mu.Unlock() 60 } 61 62 // Get get the response data synchronously, blocking until `context.Done` or the response is received. 63 // This method cannot be called more than once. After calling `Get`, `Close` must be called to close 64 // `Future`. 65 func (f *Future) Get() (Message, error) { 66 // we have to wait until the message is written, otherwise it will result in the message still 67 // waiting in the send queue after the Get returns, causing concurrent reading and writing on the 68 // request. 69 if err := f.waitSendCompleted(); err != nil { 70 return nil, err 71 } 72 select { 73 case <-f.send.Ctx.Done(): 74 return nil, f.send.Ctx.Err() 75 case resp := <-f.c: 76 return resp, nil 77 case err := <-f.errC: 78 return nil, err 79 } 80 } 81 82 // Close close the future. 83 func (f *Future) Close() { 84 f.mu.Lock() 85 defer f.mu.Unlock() 86 87 f.mu.closed = true 88 if f.mu.cb != nil { 89 f.mu.cb() 90 } 91 f.maybeReleaseLocked() 92 } 93 94 func (f *Future) waitSendCompleted() error { 95 err := <-f.writtenC 96 return err 97 } 98 99 func (f *Future) messageSended(err error) { 100 if f.sended.CompareAndSwap(0, 1) { 101 f.writtenC <- err 102 f.unRef() 103 } 104 } 105 106 func (f *Future) maybeReleaseLocked() { 107 if f.mu.closed && f.mu.ref == 0 && f.releaseFunc != nil { 108 f.releaseFunc(f) 109 } 110 } 111 112 func (f *Future) getSendMessageID() uint64 { 113 return f.send.Message.GetID() 114 } 115 116 func (f *Future) done(response Message, cb func()) { 117 f.mu.Lock() 118 defer f.mu.Unlock() 119 120 if !f.mu.closed && !f.timeout() { 121 if response.GetID() != f.getSendMessageID() { 122 return 123 } 124 f.mu.cb = cb 125 f.c <- response 126 } else if cb != nil { 127 cb() 128 } 129 } 130 131 func (f *Future) error(id uint64, err error, cb func()) { 132 f.mu.Lock() 133 defer f.mu.Unlock() 134 135 if !f.mu.closed && !f.timeout() { 136 if id != f.getSendMessageID() { 137 return 138 } 139 f.mu.cb = cb 140 f.errC <- err 141 } else if cb != nil { 142 cb() 143 } 144 } 145 146 func (f *Future) ref() { 147 f.mu.Lock() 148 defer f.mu.Unlock() 149 150 f.mu.ref++ 151 } 152 153 func (f *Future) unRef() { 154 f.mu.Lock() 155 defer f.mu.Unlock() 156 157 f.mu.ref-- 158 if f.mu.ref < 0 { 159 panic("BUG") 160 } 161 f.maybeReleaseLocked() 162 } 163 164 func (f *Future) reset() { 165 select { 166 case <-f.c: 167 default: 168 } 169 f.send = RPCMessage{} 170 f.mu.cb = nil 171 } 172 173 func (f *Future) timeout() bool { 174 select { 175 case <-f.send.Ctx.Done(): 176 return true 177 default: 178 return false 179 } 180 } 181 182 func (f *Future) setFinalizer() { 183 // when we need to reuse, we need to keep chan from being closed to avoid 184 // repeated creation. When Future is released by sync.Pool and is GC'd, we 185 // need to close chan to avoid resource leaks. 186 runtime.SetFinalizer(f, func(f *Future) { 187 close(f.c) 188 close(f.errC) 189 close(f.writtenC) 190 }) 191 }