github.com/portworx/kvdb@v0.0.0-20241107215734-a185a966f535/kvdb_mgr.go (about)

     1  package kvdb
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  )
     7  
     8  var (
     9  	instance          Kvdb
    10  	datastores        = make(map[string]DatastoreInit)
    11  	datastoreVersions = make(map[string]DatastoreVersion)
    12  	wrappers          = make(map[WrapperName]WrapperInit)
    13  	lock              sync.RWMutex
    14  )
    15  
    16  // Instance returns instance set via SetInstance, nil if none was set.
    17  func Instance() Kvdb {
    18  	return instance
    19  }
    20  
    21  // SetInstance sets the singleton instance.
    22  func SetInstance(kvdb Kvdb) error {
    23  	instance = kvdb
    24  	return nil
    25  }
    26  
    27  // New return a new instance of KVDB as specified by datastore name.
    28  // If domain is set all requests to KVDB are prefixed by domain.
    29  // options is interpreted by backend KVDB.
    30  func New(
    31  	name string,
    32  	domain string,
    33  	machines []string,
    34  	options map[string]string,
    35  	errorCB FatalErrorCB,
    36  ) (Kvdb, error) {
    37  	lock.RLock()
    38  	defer lock.RUnlock()
    39  	if dsInit, exists := datastores[name]; exists {
    40  		return dsInit(domain, machines, options, errorCB)
    41  	}
    42  	return nil, ErrNotSupported
    43  }
    44  
    45  // AddWrapper adds wrapper is it is not already added
    46  func AddWrapper(
    47  	wrapper WrapperName,
    48  	kvdb Kvdb,
    49  	options map[string]string,
    50  ) (Kvdb, error) {
    51  	lock.Lock()
    52  	defer lock.Unlock()
    53  
    54  	for w := kvdb; w != nil; w = w.WrappedKvdb() {
    55  		if w.WrapperName() == wrapper {
    56  			return kvdb, fmt.Errorf("wrapper %v already present in kvdb",
    57  				wrapper)
    58  		}
    59  	}
    60  	if initFn, ok := wrappers[wrapper]; !ok {
    61  		return kvdb, fmt.Errorf("wrapper %v not found", wrapper)
    62  	} else {
    63  		// keep log wrapper at the top if it exists
    64  		if kvdb.WrapperName() == Wrapper_Log {
    65  			newWrapper, err := initFn(kvdb.WrappedKvdb(), options)
    66  			if err == nil {
    67  				kvdb.SetWrappedKvdb(newWrapper)
    68  				return kvdb, nil
    69  			} else {
    70  				return kvdb, err
    71  			}
    72  		}
    73  		return initFn(kvdb, options)
    74  	}
    75  }
    76  
    77  // RemoveWrapper adds wrapper is it is not already added
    78  func RemoveWrapper(
    79  	wrapper WrapperName,
    80  	kvdb Kvdb,
    81  ) (Kvdb, error) {
    82  	var prevWrapper Kvdb
    83  	for w := kvdb; w != nil; w = w.WrappedKvdb() {
    84  		if w.WrapperName() == wrapper {
    85  			w.Removed()
    86  			if prevWrapper != nil {
    87  				prevWrapper.SetWrappedKvdb(w.WrappedKvdb())
    88  				return kvdb, nil
    89  			} else {
    90  				// removing the top-most wrapper
    91  				return w.WrappedKvdb(), nil
    92  			}
    93  		}
    94  		prevWrapper = w
    95  	}
    96  	return kvdb, nil // did not find the wrapper to remove
    97  }
    98  
    99  // Register adds specified datastore backend to the list of options.
   100  func Register(name string, dsInit DatastoreInit, dsVersion DatastoreVersion) error {
   101  	lock.Lock()
   102  	defer lock.Unlock()
   103  	if _, exists := datastores[name]; exists {
   104  		return fmt.Errorf("Datastore provider %q is already registered", name)
   105  	}
   106  	datastores[name] = dsInit
   107  
   108  	if _, exists := datastoreVersions[name]; exists {
   109  		return fmt.Errorf("Datastore provider's %q version function already registered", name)
   110  	}
   111  	datastoreVersions[name] = dsVersion
   112  	return nil
   113  }
   114  
   115  // Register wrapper
   116  func RegisterWrapper(name WrapperName, initFn WrapperInit) error {
   117  	lock.Lock()
   118  	defer lock.Unlock()
   119  	wrappers[name] = initFn
   120  	return nil
   121  }
   122  
   123  // Version returns the supported version for the provided kvdb endpoint.
   124  func Version(name string, url string, kvdbOptions map[string]string) (string, error) {
   125  	lock.RLock()
   126  	defer lock.RUnlock()
   127  
   128  	if dsVersion, exists := datastoreVersions[name]; exists {
   129  		return dsVersion(url, kvdbOptions)
   130  	}
   131  	return "", ErrNotSupported
   132  }