a23c456e5a
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
130 lines
3 KiB
Go
130 lines
3 KiB
Go
// Package registrar provides name registration. It reserves a name to a given key.
|
|
package registrar
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
)
|
|
|
|
var (
|
|
// ErrNameReserved is an error which is returned when a name is requested to be reserved that already is reserved
|
|
ErrNameReserved = errors.New("name is reserved")
|
|
// ErrNameNotReserved is an error which is returned when trying to find a name that is not reserved
|
|
ErrNameNotReserved = errors.New("name is not reserved")
|
|
// ErrNoSuchKey is returned when trying to find the names for a key which is not known
|
|
ErrNoSuchKey = errors.New("provided key does not exist")
|
|
)
|
|
|
|
// Registrar stores indexes a list of keys and their registered names as well as indexes names and the key that they are registered to
|
|
// Names must be unique.
|
|
// Registrar is safe for concurrent access.
|
|
type Registrar struct {
|
|
idx map[string][]string
|
|
names map[string]string
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// NewRegistrar creates a new Registrar with the an empty index
|
|
func NewRegistrar() *Registrar {
|
|
return &Registrar{
|
|
idx: make(map[string][]string),
|
|
names: make(map[string]string),
|
|
}
|
|
}
|
|
|
|
// Reserve registers a key to a name
|
|
// Reserve is idempotent
|
|
// Attempting to reserve a key to a name that already exists results in an `ErrNameReserved`
|
|
// A name reservation is globally unique
|
|
func (r *Registrar) Reserve(name, key string) error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
if k, exists := r.names[name]; exists {
|
|
if k != key {
|
|
return ErrNameReserved
|
|
}
|
|
return nil
|
|
}
|
|
|
|
r.idx[key] = append(r.idx[key], name)
|
|
r.names[name] = key
|
|
return nil
|
|
}
|
|
|
|
// Release releases the reserved name
|
|
// Once released, a name can be reserved again
|
|
func (r *Registrar) Release(name string) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
key, exists := r.names[name]
|
|
if !exists {
|
|
return
|
|
}
|
|
|
|
for i, n := range r.idx[key] {
|
|
if n != name {
|
|
continue
|
|
}
|
|
r.idx[key] = append(r.idx[key][:i], r.idx[key][i+1:]...)
|
|
break
|
|
}
|
|
|
|
delete(r.names, name)
|
|
|
|
if len(r.idx[key]) == 0 {
|
|
delete(r.idx, key)
|
|
}
|
|
}
|
|
|
|
// Delete removes all reservations for the passed in key.
|
|
// All names reserved to this key are released.
|
|
func (r *Registrar) Delete(key string) {
|
|
r.mu.Lock()
|
|
for _, name := range r.idx[key] {
|
|
delete(r.names, name)
|
|
}
|
|
delete(r.idx, key)
|
|
r.mu.Unlock()
|
|
}
|
|
|
|
// GetNames lists all the reserved names for the given key
|
|
func (r *Registrar) GetNames(key string) ([]string, error) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
names, exists := r.idx[key]
|
|
if !exists {
|
|
return nil, ErrNoSuchKey
|
|
}
|
|
|
|
ls := make([]string, 0, len(names))
|
|
ls = append(ls, names...)
|
|
return ls, nil
|
|
}
|
|
|
|
// Get returns the key that the passed in name is reserved to
|
|
func (r *Registrar) Get(name string) (string, error) {
|
|
r.mu.Lock()
|
|
key, exists := r.names[name]
|
|
r.mu.Unlock()
|
|
|
|
if !exists {
|
|
return "", ErrNameNotReserved
|
|
}
|
|
return key, nil
|
|
}
|
|
|
|
// GetAll returns all registered names
|
|
func (r *Registrar) GetAll() map[string][]string {
|
|
out := make(map[string][]string)
|
|
|
|
r.mu.Lock()
|
|
// copy index into out
|
|
for id, names := range r.idx {
|
|
out[id] = names
|
|
}
|
|
r.mu.Unlock()
|
|
return out
|
|
}
|