github.com/m3db/m3@v1.5.0/src/dbnode/client/fetch_batch.go (about)

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package client
    22  
    23  import (
    24  	"github.com/m3db/m3/src/dbnode/generated/thrift/rpc"
    25  	"github.com/m3db/m3/src/x/checked"
    26  	"github.com/m3db/m3/src/x/pool"
    27  )
    28  
    29  type fetchBatchOp struct {
    30  	checked.RefCount
    31  	request           rpc.FetchBatchRawRequest
    32  	requestV2Elements []rpc.FetchBatchRawV2RequestElement
    33  	completionFns     []completionFn
    34  	finalizer         fetchBatchOpFinalizer
    35  }
    36  
    37  func (f *fetchBatchOp) reset() {
    38  	f.IncWrites()
    39  	f.request.RangeStart = 0
    40  	f.request.RangeEnd = 0
    41  	f.request.NameSpace = nil
    42  	for i := range f.request.Ids {
    43  		f.request.Ids[i] = nil
    44  	}
    45  	f.request.Ids = f.request.Ids[:0]
    46  	for i := range f.completionFns {
    47  		f.completionFns[i] = nil
    48  	}
    49  	f.completionFns = f.completionFns[:0]
    50  
    51  	for i := range f.requestV2Elements {
    52  		f.requestV2Elements[i].NameSpace = 0
    53  		f.requestV2Elements[i].RangeStart = 0
    54  		f.requestV2Elements[i].RangeEnd = 0
    55  		f.requestV2Elements[i].ID = nil
    56  		f.requestV2Elements[i].RangeTimeType = 0
    57  	}
    58  	f.requestV2Elements = f.requestV2Elements[:0]
    59  
    60  	f.DecWrites()
    61  }
    62  
    63  func (f *fetchBatchOp) append(namespace, id []byte, completionFn completionFn) {
    64  	f.IncWrites()
    65  	f.request.NameSpace = namespace
    66  	f.request.Ids = append(f.request.Ids, id)
    67  	f.requestV2Elements = append(f.requestV2Elements, rpc.FetchBatchRawV2RequestElement{
    68  		// NameSpace filled in by the host queue later.
    69  		RangeStart:    f.request.RangeStart,
    70  		RangeEnd:      f.request.RangeEnd,
    71  		ID:            id,
    72  		RangeTimeType: f.request.RangeTimeType,
    73  	})
    74  	f.completionFns = append(f.completionFns, completionFn)
    75  	f.DecWrites()
    76  }
    77  
    78  func (f *fetchBatchOp) Size() int {
    79  	f.IncReads()
    80  	value := len(f.request.Ids)
    81  	if value == 0 {
    82  		value = len(f.requestV2Elements)
    83  	}
    84  	f.DecReads()
    85  	return value
    86  }
    87  
    88  func (f *fetchBatchOp) CompletionFn() completionFn {
    89  	return f.completeAll
    90  }
    91  
    92  func (f *fetchBatchOp) completeAll(result interface{}, err error) {
    93  	for idx := range f.completionFns {
    94  		f.completionFns[idx](result, err)
    95  	}
    96  }
    97  
    98  func (f *fetchBatchOp) complete(idx int, result interface{}, err error) {
    99  	f.IncReads()
   100  	fn := f.completionFns[idx]
   101  	f.DecReads()
   102  	fn(result, err)
   103  }
   104  
   105  type fetchBatchOpFinalizer struct {
   106  	ref  *fetchBatchOp
   107  	pool *fetchBatchOpPool
   108  }
   109  
   110  func (f fetchBatchOpFinalizer) OnFinalize() {
   111  	f.pool.Put(f.ref)
   112  }
   113  
   114  type fetchBatchOpPool struct {
   115  	pool     pool.ObjectPool
   116  	capacity int
   117  }
   118  
   119  func newFetchBatchOpPool(opts pool.ObjectPoolOptions, capacity int) *fetchBatchOpPool {
   120  	p := pool.NewObjectPool(opts)
   121  	return &fetchBatchOpPool{pool: p, capacity: capacity}
   122  }
   123  
   124  func (p *fetchBatchOpPool) Init() {
   125  	p.pool.Init(func() interface{} {
   126  		f := &fetchBatchOp{}
   127  		f.request.Ids = make([][]byte, 0, p.capacity)
   128  		f.completionFns = make([]completionFn, 0, p.capacity)
   129  		f.finalizer.ref = f
   130  		f.finalizer.pool = p
   131  		f.SetOnFinalize(&f.finalizer)
   132  
   133  		f.IncRef()
   134  		f.reset()
   135  		f.DecRef()
   136  		return f
   137  	})
   138  }
   139  
   140  func (p *fetchBatchOpPool) Get() *fetchBatchOp {
   141  	return p.pool.Get().(*fetchBatchOp)
   142  }
   143  
   144  func (p *fetchBatchOpPool) Put(f *fetchBatchOp) {
   145  	f.IncRef()
   146  	if cap(f.request.Ids) != p.capacity || cap(f.completionFns) != p.capacity {
   147  		// Grew outside capacity, do not return to pool
   148  		f.DecRef()
   149  		return
   150  	}
   151  	f.reset()
   152  	f.DecRef()
   153  	p.pool.Put(f)
   154  }