github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/series_resolver.go (about)

     1  // Copyright (c) 2021 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 storage
    22  
    23  import (
    24  	"fmt"
    25  	"sync"
    26  
    27  	"github.com/m3db/m3/src/dbnode/storage/bootstrap"
    28  	"github.com/m3db/m3/src/x/ident"
    29  )
    30  
    31  // retrieveWritableSeriesAndIncrementReaderWriterCountFn represents the function to retrieve series entry.
    32  type retrieveWritableSeriesAndIncrementReaderWriterCountFn func(id ident.ID) (*Entry, error)
    33  
    34  type seriesResolver struct {
    35  	sync.RWMutex
    36  
    37  	wg                                                    *sync.WaitGroup
    38  	createdEntry                                          *Entry
    39  	retrieveWritableSeriesAndIncrementReaderWriterCountFn retrieveWritableSeriesAndIncrementReaderWriterCountFn
    40  
    41  	resolved    bool
    42  	resolvedErr error
    43  	entry       *Entry
    44  }
    45  
    46  // NewSeriesResolver creates new series ref resolver.
    47  func NewSeriesResolver(
    48  	wg *sync.WaitGroup,
    49  	createdEntry *Entry,
    50  	retrieveWritableSeriesAndIncrementReaderWriterCountFn retrieveWritableSeriesAndIncrementReaderWriterCountFn,
    51  ) bootstrap.SeriesRefResolver {
    52  	return &seriesResolver{
    53  		wg:           wg,
    54  		createdEntry: createdEntry,
    55  		retrieveWritableSeriesAndIncrementReaderWriterCountFn: retrieveWritableSeriesAndIncrementReaderWriterCountFn,
    56  	}
    57  }
    58  
    59  func (r *seriesResolver) resolve() error {
    60  	r.RLock()
    61  	if r.resolved {
    62  		resolvedResult := r.resolvedErr
    63  		r.RUnlock()
    64  		return resolvedResult
    65  	}
    66  	r.RUnlock()
    67  
    68  	r.Lock()
    69  	defer r.Unlock()
    70  
    71  	// Fast path: if we already resolved the result, just return it.
    72  	if r.resolved {
    73  		return r.resolvedErr
    74  	}
    75  
    76  	// Wait for the insertion.
    77  	r.wg.Wait()
    78  
    79  	// Retrieve the inserted entry.
    80  	entry, err := r.retrieveWritableSeriesAndIncrementReaderWriterCountFn(r.createdEntry.ID)
    81  	r.resolved = true
    82  	if err != nil {
    83  		r.resolvedErr = err
    84  		return r.resolvedErr
    85  	}
    86  
    87  	if entry == nil {
    88  		r.resolvedErr = fmt.Errorf("could not resolve: %s", r.createdEntry.ID)
    89  		return r.resolvedErr
    90  	}
    91  
    92  	r.entry = entry
    93  	return nil
    94  }
    95  
    96  func (r *seriesResolver) SeriesRef() (bootstrap.SeriesRef, error) {
    97  	if err := r.resolve(); err != nil {
    98  		return nil, err
    99  	}
   100  	return r.entry, nil
   101  }
   102  
   103  func (r *seriesResolver) ReleaseRef() {
   104  	if r.createdEntry != nil {
   105  		// We explicitly dec the originally created entry for the resolver since
   106  		// that it is the one that was incremented before we took ownership of it,
   107  		// this was done to make sure it was valid during insertion until we
   108  		// operated on it.
   109  		// If we got it back from the shard map and incremented the reader writer
   110  		// count as well during that retrieval, then we'll again decrement it below.
   111  		r.createdEntry.ReleaseRef()
   112  		r.createdEntry = nil
   113  	}
   114  	if r.entry != nil {
   115  		// To account for decrementing the increment that occurred when checking
   116  		// out the series from the shard itself (which was incremented
   117  		// the reader writer counter when we checked it out using by calling
   118  		// "retrieveWritableSeriesAndIncrementReaderWriterCount").
   119  		r.entry.DecrementReaderWriterCount()
   120  		r.entry = nil
   121  	}
   122  }