github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/ident/types.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 ident provides utilities for working with identifiers.
    22  package ident
    23  
    24  import (
    25  	"fmt"
    26  
    27  	"github.com/m3db/m3/src/m3ninx/doc"
    28  	"github.com/m3db/m3/src/x/checked"
    29  	"github.com/m3db/m3/src/x/context"
    30  )
    31  
    32  // ID represents an immutable identifier to allow use of byte slice pooling
    33  // for the contents of the ID.
    34  type ID interface {
    35  	fmt.Stringer
    36  
    37  	// Bytes returns the underlying byte slice of the bytes ID unpacked from
    38  	// any checked bytes container, callers cannot safely hold a ref to these
    39  	// bytes.
    40  	Bytes() []byte
    41  
    42  	// Equal returns whether the ID is equal to a given ID.
    43  	Equal(value ID) bool
    44  
    45  	// NoFinalize makes calls to finalize a no-op, this is useful when you
    46  	// would like to share a type with another sub-system that should is not
    47  	// allowed to finalize the resource as the resource is kept indefinitely
    48  	// until garbage collected (i.e. longly lived).
    49  	NoFinalize()
    50  
    51  	// IsNoFinalize returns whether finalize is a no-op or not, this is useful
    52  	// when you know you can use an ID without having to worry to take a copy.
    53  	IsNoFinalize() bool
    54  
    55  	// Finalize releases all resources held by the ID, unless NoFinalize has
    56  	// been called previously in which case this is a no-op.
    57  	Finalize()
    58  }
    59  
    60  // TagName represents the name of a timeseries tag.
    61  type TagName ID
    62  
    63  // TagValue represents the value of a timeseries tag.
    64  type TagValue ID
    65  
    66  // Tag represents a timeseries tag.
    67  type Tag struct {
    68  	Name       TagName
    69  	Value      TagValue
    70  	noFinalize bool
    71  }
    72  
    73  // NoFinalize makes calls to finalize a no-op, this is useful when you
    74  // would like to share a type with another sub-system that should is not
    75  // allowed to finalize the resource as the resource is kept indefinitely
    76  // until garbage collected (i.e. longly lived).
    77  func (t *Tag) NoFinalize() {
    78  	t.noFinalize = true
    79  	t.Name.NoFinalize()
    80  	t.Value.NoFinalize()
    81  }
    82  
    83  // Finalize releases all resources held by the Tag, unless NoFinalize has
    84  // been called previously in which case this is a no-op.
    85  func (t *Tag) Finalize() {
    86  	if t.noFinalize {
    87  		return
    88  	}
    89  	if t.Name != nil {
    90  		t.Name.Finalize()
    91  		t.Name = nil
    92  	}
    93  	if t.Value != nil {
    94  		t.Value.Finalize()
    95  		t.Value = nil
    96  	}
    97  }
    98  
    99  // Equal returns whether the two tags are equal.
   100  func (t Tag) Equal(value Tag) bool {
   101  	return t.Name.Equal(value.Name) && t.Value.Equal(value.Value)
   102  }
   103  
   104  // Pool represents an automatic pool of `ident` objects.
   105  type Pool interface {
   106  	// GetBinaryID will create a new binary ID and take reference to the bytes.
   107  	// When the context closes the ID will be finalized and so too will
   108  	// the bytes, i.e. it will take ownership of the bytes.
   109  	GetBinaryID(c context.Context, data checked.Bytes) ID
   110  
   111  	// BinaryID will create a new binary ID and take a reference to the bytes.
   112  	BinaryID(data checked.Bytes) ID
   113  
   114  	// GetBinaryTag will create a new binary Tag and take reference to the bytes.
   115  	// When the context closes, the Tag will be finalized and so too will
   116  	// the bytes, i.e. it will take ownership of the bytes.
   117  	GetBinaryTag(c context.Context, name, value checked.Bytes) Tag
   118  
   119  	// BinaryTag will create a new binary Tag and take a reference to the provided bytes.
   120  	BinaryTag(name, value checked.Bytes) Tag
   121  
   122  	// GetStringID will create a new string ID and create a bytes copy of the
   123  	// string. When the context closes the ID will be finalized.
   124  	GetStringID(c context.Context, id string) ID
   125  
   126  	// StringID will create a new string ID and create a bytes copy of the
   127  	// string.
   128  	StringID(data string) ID
   129  
   130  	// GetStringTag will create a new string Tag and create a bytes copy of the
   131  	// string. When the context closes the ID will be finalized.
   132  	GetStringTag(c context.Context, name, value string) Tag
   133  
   134  	// StringTag will create a new string Tag and create a bytes copy of the
   135  	// string.
   136  	StringTag(name, value string) Tag
   137  
   138  	// Tags will create a new array of tags and return it.
   139  	Tags() Tags
   140  
   141  	// GetTagsIterator will create a tag iterator and return it. When the context
   142  	// closes the tags array and any tags contained will be finalized.
   143  	GetTagsIterator(c context.Context) TagsIterator
   144  
   145  	// TagsIterator will create a tag iterator and return it.
   146  	TagsIterator() TagsIterator
   147  
   148  	// Put an ID back in the pool.
   149  	Put(id ID)
   150  
   151  	// PutTag puts a tag back in the pool.
   152  	PutTag(tag Tag)
   153  
   154  	// PutTags puts a set of tags back in the pool.
   155  	PutTags(tags Tags)
   156  
   157  	// PutTagsIterator puts a tags iterator back in the pool.
   158  	PutTagsIterator(iter TagsIterator)
   159  
   160  	// Clone replicates a given ID into a pooled ID.
   161  	Clone(id ID) ID
   162  
   163  	// CloneTag replicates a given Tag into a pooled Tag.
   164  	CloneTag(tag Tag) Tag
   165  
   166  	// CloneTags replicates a given set of Tags into a pooled Tags.
   167  	CloneTags(tags Tags) Tags
   168  }
   169  
   170  // Iterator represents an iterator over `ID` instances. It is not thread-safe.
   171  type Iterator interface {
   172  	// Next returns a bool indicating the presence of the next ID instance.
   173  	Next() bool
   174  
   175  	// Current returns the current ID instance.
   176  	Current() ID
   177  
   178  	// CurrentIndex returns the current index at.
   179  	CurrentIndex() int
   180  
   181  	// Close releases any resources held by the iterator.
   182  	Close()
   183  
   184  	// Err returns any errors encountered during iteration.
   185  	Err() error
   186  
   187  	// Len returns the number of elements.
   188  	Len() int
   189  
   190  	// Remaining returns the number of elements remaining to be iterated over.
   191  	Remaining() int
   192  
   193  	// Dupe returns an independent duplicate of the iterator.
   194  	Duplicate() Iterator
   195  }
   196  
   197  // TagIterator represents an iterator over `Tag` instances. It is not thread-safe.
   198  type TagIterator interface {
   199  	// Next returns a bool indicating the presence of the next Tag instance.
   200  	Next() bool
   201  
   202  	// Current returns the current Tag instance.
   203  	Current() Tag
   204  
   205  	// CurrentIndex returns the current index at.
   206  	CurrentIndex() int
   207  
   208  	// Err returns any errors encountered during iteration.
   209  	Err() error
   210  
   211  	// Close releases any resources held by the iterator.
   212  	Close()
   213  
   214  	// Len returns the number of elements.
   215  	Len() int
   216  
   217  	// Remaining returns the number of elements remaining to be iterated over.
   218  	Remaining() int
   219  
   220  	// Duplicate returns an independent duplicate of the iterator.
   221  	Duplicate() TagIterator
   222  
   223  	// Rewind resets the tag iterator to the initial position.
   224  	Rewind()
   225  }
   226  
   227  // TagsIterator represents a TagIterator that can be reset with a Tags
   228  // collection type. It is not thread-safe.
   229  type TagsIterator interface {
   230  	TagIterator
   231  
   232  	// Reset allows the tag iterator to be reused with a new set of tags.
   233  	Reset(tags Tags)
   234  
   235  	// ResetFields allows tag iterator to be reused from a set of fields.
   236  	ResetFields(fields []doc.Field)
   237  }
   238  
   239  // Tags is a collection of Tag instances that can be pooled.
   240  type Tags struct {
   241  	values     []Tag
   242  	pool       Pool
   243  	noFinalize bool
   244  }
   245  
   246  // NewTags returns a new set of tags.
   247  func NewTags(values ...Tag) Tags {
   248  	return Tags{values: values}
   249  }
   250  
   251  // Reset resets the tags for reuse.
   252  func (t *Tags) Reset(values []Tag) {
   253  	t.values = values
   254  }
   255  
   256  // Values returns the tags values.
   257  func (t Tags) Values() []Tag {
   258  	return t.values
   259  }
   260  
   261  // Append will append a tag.
   262  func (t *Tags) Append(tag Tag) {
   263  	t.values = append(t.values, tag)
   264  }
   265  
   266  // NoFinalize makes calls to finalize a no-op, this is useful when you
   267  // would like to share a type with another sub-system that should is not
   268  // allowed to finalize the resource as the resource is kept indefinitely
   269  // until garbage collected (i.e. longly lived).
   270  func (t *Tags) NoFinalize() {
   271  	t.noFinalize = true
   272  	for _, tag := range t.values {
   273  		tag.NoFinalize()
   274  	}
   275  }
   276  
   277  // Finalize finalizes all Tags, unless NoFinalize has been called previously
   278  // in which case this is a no-op.
   279  func (t *Tags) Finalize() {
   280  	if t.noFinalize {
   281  		return
   282  	}
   283  
   284  	values := t.values
   285  	t.values = nil
   286  
   287  	for i := range values {
   288  		values[i].Finalize()
   289  	}
   290  
   291  	if t.pool == nil {
   292  		return
   293  	}
   294  
   295  	t.pool.PutTags(Tags{values: values})
   296  }
   297  
   298  // Equal returns a bool indicating if the tags are equal. It requires
   299  // the two slices are ordered the same.
   300  func (t Tags) Equal(other Tags) bool {
   301  	if len(t.Values()) != len(other.Values()) {
   302  		return false
   303  	}
   304  	for i := 0; i < len(t.Values()); i++ {
   305  		equal := t.values[i].Name.Equal(other.values[i].Name) &&
   306  			t.values[i].Value.Equal(other.values[i].Value)
   307  		if !equal {
   308  			return false
   309  		}
   310  	}
   311  	return true
   312  }