github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/store/rateLimit.go (about) 1 package store 2 3 import ( 4 "math" 5 ) 6 7 // store/RateLimiter.java 8 9 /* 10 Abstract base class to rate limit IO. Typically implementations are 11 shared across multiple IndexInputs or IndexOutputs (for example those 12 involved all merging). Those IndexInputs and IndexOutputs would call 13 pause() whenever they have read or written more than 14 minPauseCheckBytes() bytes. 15 */ 16 type RateLimiter interface { 17 // Sets an updated mb per second rate limit. 18 SetMbPerSec(mbPerSec float64) 19 // The current mb per second rate limit. 20 MbPerSec() float64 21 /* 22 Pause, if necessary, to keep the instantaneous IO rate at or below 23 the target. 24 25 Note: the implementation is thread-safe 26 */ 27 Pause(bytes int64) int64 28 } 29 30 // Simple class to rate limit IO 31 // Ian: volatile is not supported 32 type SimpleRateLimiter struct { 33 mbPerSec float64 // volatile 34 minPauseCheckBytes int64 // volatile 35 lastNS int64 36 } 37 38 // mbPerSec is the MB/sec max IO rate 39 func newSimpleRateLimiter(mbPerSec float64) *SimpleRateLimiter { 40 ans := &SimpleRateLimiter{} 41 ans.SetMbPerSec(mbPerSec) 42 return ans 43 } 44 45 func (srl *SimpleRateLimiter) SetMbPerSec(mbPerSec float64) { 46 srl.mbPerSec = mbPerSec 47 panic("not implemented yet") 48 } 49 50 func (srl *SimpleRateLimiter) MbPerSec() float64 { 51 return srl.mbPerSec 52 } 53 54 /* 55 Pause, if necessary, to keep the instantaneous IO rate at or below 56 the target. Be sure to only call this method when bytes > 57 minPauseCheckBytes(), otherwise it will pause way too long! 58 */ 59 func (srl *SimpleRateLimiter) Pause(bytes int64) int64 { 60 panic("not implemented yet") 61 // if bytes == 1 { 62 // return 0 63 // } 64 65 // // TODO: this is purely instantaneous rate; maybe we 66 // // should also offer decayed recent history one? 67 // srl.lastNS += int64(float64(bytes) * srl.nsPerByte) 68 // targetNS := srl.lastNS 69 // startNS := time.Now().UnixNano() 70 // curNS := startNS 71 // if srl.lastNS < curNS { 72 // srl.lastNS = curNS 73 // } 74 75 // // While loop because sleep doesn't always sleep enough: 76 // for pauseNS := targetNS - curNS; pauseNS > 0; pauseNS = targetNS - curNS { 77 // time.Sleep(time.Duration(pauseNS * int64(time.Nanosecond))) 78 // curNS = time.Now().UnixNano() 79 // } 80 // return curNS - startNS 81 } 82 83 // store/RateLimitedDirectoryWrapper.java 84 85 // A Directory wrapper that allows IndexOutput rate limiting using 86 // IO context specific rate limiters. 87 type RateLimitedDirectoryWrapper struct { 88 Directory 89 // we need to be volatile here to make sure we see all the values 90 // that are set / modified concurrently 91 // Ian: volatile is not supported 92 contextRateLimiters []RateLimiter // volatile 93 isOpen bool 94 } 95 96 func NewRateLimitedDirectoryWrapper(wrapped Directory) *RateLimitedDirectoryWrapper { 97 panic("not implemented yet") 98 // return &RateLimitedDirectoryWrapper{ 99 // Directory: wrapped, 100 // contextRateLimiters: make([]RateLimiter, 4), // TODO magic number 101 // isOpen: true, 102 // } 103 } 104 105 func (w *RateLimitedDirectoryWrapper) CreateOutput(name string, ctx IOContext) (IndexOutput, error) { 106 w.EnsureOpen() 107 output, err := w.Directory.CreateOutput(name, ctx) 108 if err == nil { 109 if limiter := w.rateLimiter(ctx.context); limiter != nil { 110 output = newRateLimitedIndexOutput(limiter, output) 111 } 112 } 113 return output, err 114 } 115 116 // func (w *RateLimitedDirectoryWrapper) Close() error { 117 // w.isOpen = false 118 // return w.Directory.Close() 119 // } 120 121 // func (w *RateLimitedDirectoryWrapper) String() string { 122 // return fmt.Sprintf("RateLimitedDirectoryWrapper(%v)", w.Directory) 123 // } 124 125 func (w *RateLimitedDirectoryWrapper) rateLimiter(ctx IOContextType) RateLimiter { 126 assert(int(ctx) != 0) 127 return w.contextRateLimiters[int(ctx)-1] 128 } 129 130 /* 131 Sets the maximum (approx) MB/sec allowed by all write IO performed by 132 IndexOutput created with the given context. Pass non-positve value to 133 have no limit. 134 135 NOTE: For already created IndexOutput instances there is no guarantee 136 this new rate will apply to them; it will only be guaranteed to apply 137 for new created IndexOutput instances. 138 139 NOTE: this is an optional operation and might not be respected by all 140 Directory implementations. Currently only buffered Directory 141 implementations use rate-limiting. 142 */ 143 func (w *RateLimitedDirectoryWrapper) SetMaxWriteMBPerSec(mbPerSec float64, context int) { 144 if !w.isOpen { 145 panic("this Directory is closed") 146 } 147 if context == 0 { 148 panic("Context must not be nil") 149 } 150 ord := context - 1 151 limiter := w.contextRateLimiters[ord] 152 if mbPerSec <= 0 { 153 if limiter != nil { 154 limiter.SetMbPerSec(math.MaxFloat64) 155 w.contextRateLimiters[ord] = nil 156 // atomic.StorePointer(&(w.contextRateLimiters[ord]), nil) 157 } 158 } else if limiter != nil { 159 limiter.SetMbPerSec(mbPerSec) 160 // atomic.StorePointer(&(w.contextRateLimiters[ord]), limiter) // cross the mem barrier again 161 } else { 162 w.contextRateLimiters[ord] = newSimpleRateLimiter(mbPerSec) 163 // atomic.StorePointer(&(w.contextRateLimiters[ord]), newSimpleRateLimiter(mbPerSec)) 164 } 165 } 166 167 /* 168 Sets the rate limiter to be used to limit (approx) MB/sec allowed by 169 all IO performed with the given context. Pass non-positive to have no 170 limit. 171 172 Passing an instance of rate limiter compared to settng it using 173 setMaxWriteMBPersec() allows to use the same limiter instance across 174 several directories globally limiting IO across them. 175 */ 176 func (w *RateLimitedDirectoryWrapper) setRateLimiter(mergeWriteRateLimiter RateLimiter, context int) { 177 panic("not implemented yet") 178 } 179 180 func (w *RateLimitedDirectoryWrapper) MaxWriteMBPerSec(context int) { 181 panic("not implemented yet") 182 } 183 184 // store/RateLimitedIndexOutput.java 185 186 type flushBuffer interface { 187 FlushBuffer(buf []byte) error 188 } 189 190 /* A rate limiting IndexOutput */ 191 type RateLimitedIndexOutput struct { 192 *IndexOutputImpl 193 delegate IndexOutput 194 rateLimiter RateLimiter 195 } 196 197 func newRateLimitedIndexOutput(rateLimiter RateLimiter, delegate IndexOutput) *RateLimitedIndexOutput { 198 panic("not implemented yet") 199 // ans := &RateLimitedIndexOutput{} 200 // ans.BufferedIndexOutput = NewBufferedIndexOutput(DEFAULT_BUFFER_SIZE, ans) 201 // ans.delegate = delegate 202 // ans.rateLimiter = rateLimiter 203 // return ans 204 } 205 206 func (out *RateLimitedIndexOutput) Close() error { 207 return out.delegate.Close() 208 } 209 210 func (out *RateLimitedIndexOutput) FilePointer() int64 { 211 panic("not implementd yet") 212 } 213 214 func (out *RateLimitedIndexOutput) Checksum() int64 { 215 return out.delegate.Checksum() 216 } 217 218 func (out *RateLimitedIndexOutput) WriteByte(b byte) error { 219 panic("not implemented yet") 220 } 221 222 func (out *RateLimitedIndexOutput) WriteBytes(p []byte) error { 223 panic("not implemented yet") 224 } 225 226 // func (out *RateLimitedIndexOutput) FlushBuffer(buf []byte) error { 227 // out.rateLimiter.Pause(int64(len(buf))) 228 // if v, ok := out.delegate.(flushBuffer); ok { 229 // return v.FlushBuffer(buf) 230 // } 231 // panic("double check if flushBuffer interface is satisfied") 232 // return out.delegate.WriteBytes(buf) 233 // } 234 235 // func (out *RateLimitedIndexOutput) Length() (int64, error) { 236 // return out.delegate.Length() 237 // }