go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/sync/dispatcher/buffer/batch.go (about)

     1  // Copyright 2019 The LUCI Authors.
     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 buffer
    16  
    17  import (
    18  	"time"
    19  
    20  	"go.chromium.org/luci/common/retry"
    21  )
    22  
    23  // BatchItem is just a container for the user-provided work items.
    24  //
    25  // This includes the Size of `Data` at the time the work item was added to
    26  // the buffer. This will not be modified by Buffer, but can be adjusted
    27  // by your application while handling a Batch if your handler needs to trim
    28  // this somehow.
    29  type BatchItem struct {
    30  	Item any
    31  	Size int
    32  }
    33  
    34  // Batch represents a collection of individual work items and associated
    35  // metadata.
    36  //
    37  // Batches are are cut by the Channel according to Options.Buffer, and can be
    38  // manipulated by ErrorFn and SendFn.
    39  //
    40  // ErrorFn and SendFn may manipulate the contents of the Batch (Data and Meta)
    41  // to do things such as:
    42  //   - Associate a UID with the Batch (e.g. in the Meta field) to identify it to
    43  //     remote services for deduplication.
    44  //   - Remove already-processed items from Data in case the SendFn partially
    45  //     succeeded.
    46  //
    47  // The dispatcher accounts for the number of work items in the Batch as it
    48  // leases the Batch out; initially the Batch's length will be len(Data). If the
    49  // SendFn reduces the length of Data before the NACK, the accounted number of
    50  // work items will be accordingly reduced. The accounted length can never grow
    51  // (i.e. extending Data doesn't do anything).
    52  //
    53  // Similarly, if the buffer is configured with BatchSize, the accounted Size of
    54  // the batch is defined as the sum of the cached sizes in Data. Reducing this
    55  // amount (by removing items, or potentially reducing the Size in a BatchItem)
    56  // will reduce the effective Size of this Batch, but adding to Data cannot
    57  // increase the Size of the batch.
    58  type Batch struct {
    59  	// Data is the work items pushed into the Buffer, plus their Size as provided
    60  	// to AddNoBlock.
    61  	Data []BatchItem
    62  
    63  	// Meta is an object which dispatcher.Channel will treat as totally opaque;
    64  	// You may manipulate it in SendFn or ErrorFn as you see fit. This can be used
    65  	// for e.g. associating a nonce with the Batch for retries, or stashing
    66  	// a constructed RPC proto, etc.
    67  	Meta any
    68  
    69  	// id is a 1-based counter which is generated by Buffer when the Batch
    70  	// is created. Within a Buffer it is monotonically increasing.
    71  	id uint64
    72  
    73  	// retry is the retry.Iterator associated with this Batch. Its Next method
    74  	// will be called when it is NACK'd.
    75  	retry retry.Iterator
    76  
    77  	// nextSend is the next timestamp after which this Batch is eligible for
    78  	// sending.
    79  	//
    80  	// While the batch is the `currentBatch` in the buffer, this timestamp
    81  	// represents the deadline for cutting this batch.
    82  	nextSend time.Time
    83  
    84  	// countedItems is the number of items in this Batch as the Buffer counts it.
    85  	// It starts as the original value of len(Batch.Data) and can decrease if
    86  	// len(Batch.Data) is smaller on a NACK().
    87  	countedItems int
    88  
    89  	// countedSize is the number of size units of this Batch as the Buffer counts
    90  	// it. It starts as the sum of the Size of Data, and can decrease if
    91  	// BatchItems in Data have their Size reduced or if items are removed
    92  	// from BatchItems.
    93  	countedSize int
    94  }
    95  
    96  func (b *Batch) canAccept(o *Options, itemSize int) bool {
    97  	switch {
    98  	case b == nil:
    99  		return false
   100  	case o.BatchItemsMax > -1 && b.countedItems+1 > o.BatchItemsMax:
   101  		return false
   102  	case o.BatchSizeMax > -1 && b.countedSize+itemSize > o.BatchSizeMax:
   103  		return false
   104  	}
   105  	return true
   106  }