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  // }