github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/pkg/registrar/registrar.go (about)

     1  // Package registrar provides name registration. It reserves a name to a given key.
     2  package registrar
     3  
     4  import (
     5  	"errors"
     6  	"sync"
     7  )
     8  
     9  var (
    10  	// ErrNameReserved is an error which is returned when a name is requested to be reserved that already is reserved
    11  	ErrNameReserved = errors.New("name is reserved")
    12  	// ErrNameNotReserved is an error which is returned when trying to find a name that is not reserved
    13  	ErrNameNotReserved = errors.New("name is not reserved")
    14  	// ErrNoSuchKey is returned when trying to find the names for a key which is not known
    15  	ErrNoSuchKey = errors.New("provided key does not exist")
    16  )
    17  
    18  // Registrar stores indexes a list of keys and their registered names as well as indexes names and the key that they are registered to
    19  // Names must be unique.
    20  // Registrar is safe for concurrent access.
    21  type Registrar struct {
    22  	idx   map[string][]string
    23  	names map[string]string
    24  	mu    sync.Mutex
    25  }
    26  
    27  // NewRegistrar creates a new Registrar with the an empty index
    28  func NewRegistrar() *Registrar {
    29  	return &Registrar{
    30  		idx:   make(map[string][]string),
    31  		names: make(map[string]string),
    32  	}
    33  }
    34  
    35  // Reserve registers a key to a name
    36  // Reserve is idempotent
    37  // Attempting to reserve a key to a name that already exists results in an `ErrNameReserved`
    38  // A name reservation is globally unique
    39  func (r *Registrar) Reserve(name, key string) error {
    40  	r.mu.Lock()
    41  	defer r.mu.Unlock()
    42  
    43  	if k, exists := r.names[name]; exists {
    44  		if k != key {
    45  			return ErrNameReserved
    46  		}
    47  		return nil
    48  	}
    49  
    50  	r.idx[key] = append(r.idx[key], name)
    51  	r.names[name] = key
    52  	return nil
    53  }
    54  
    55  // Release releases the reserved name
    56  // Once released, a name can be reserved again
    57  func (r *Registrar) Release(name string) {
    58  	r.mu.Lock()
    59  	defer r.mu.Unlock()
    60  
    61  	key, exists := r.names[name]
    62  	if !exists {
    63  		return
    64  	}
    65  
    66  	for i, n := range r.idx[key] {
    67  		if n != name {
    68  			continue
    69  		}
    70  		r.idx[key] = append(r.idx[key][:i], r.idx[key][i+1:]...)
    71  		break
    72  	}
    73  
    74  	delete(r.names, name)
    75  
    76  	if len(r.idx[key]) == 0 {
    77  		delete(r.idx, key)
    78  	}
    79  }
    80  
    81  // Delete removes all reservations for the passed in key.
    82  // All names reserved to this key are released.
    83  func (r *Registrar) Delete(key string) {
    84  	r.mu.Lock()
    85  	for _, name := range r.idx[key] {
    86  		delete(r.names, name)
    87  	}
    88  	delete(r.idx, key)
    89  	r.mu.Unlock()
    90  }
    91  
    92  // GetNames lists all the reserved names for the given key
    93  func (r *Registrar) GetNames(key string) ([]string, error) {
    94  	r.mu.Lock()
    95  	defer r.mu.Unlock()
    96  
    97  	names, exists := r.idx[key]
    98  	if !exists {
    99  		return nil, ErrNoSuchKey
   100  	}
   101  	return names, nil
   102  }
   103  
   104  // Get returns the key that the passed in name is reserved to
   105  func (r *Registrar) Get(name string) (string, error) {
   106  	r.mu.Lock()
   107  	key, exists := r.names[name]
   108  	r.mu.Unlock()
   109  
   110  	if !exists {
   111  		return "", ErrNameNotReserved
   112  	}
   113  	return key, nil
   114  }
   115  
   116  // GetAll returns all registered names
   117  func (r *Registrar) GetAll() map[string][]string {
   118  	out := make(map[string][]string)
   119  
   120  	r.mu.Lock()
   121  	// copy index into out
   122  	for id, names := range r.idx {
   123  		out[id] = names
   124  	}
   125  	r.mu.Unlock()
   126  	return out
   127  }