X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=sdl.go;h=02dae3d892a678615de43baa8eb7bdeee96ec124;hb=HEAD;hp=426c2c46e468c2edb755f544dc2145868a73a591;hpb=a10caff26de79e06caac2d00d3c11218e2d7ee87;p=ric-plt%2Fsdlgo.git diff --git a/sdl.go b/sdl.go index 426c2c4..02dae3d 100644 --- a/sdl.go +++ b/sdl.go @@ -15,48 +15,59 @@ limitations under the License. */ +/* + * This source code is part of the near-RT RIC (RAN Intelligent Controller) + * platform project (RICP). + */ + package sdlgo import ( - "crypto/rand" - "encoding/base64" - "errors" - "fmt" - "io" - "reflect" - "strings" - "sync" - "time" - "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis" + "time" ) //SdlInstance provides an API to read, write and modify //key-value pairs in a given namespace. +//Deprecated: Will be removed in a future release, please use instead SyncStorage +//type defined in syncstorage.go. type SdlInstance struct { - nameSpace string - nsPrefix string - eventSeparator string - mutex sync.Mutex - tmp []byte - iDatabase + nameSpace string + nsPrefix string + storage *SyncStorage +} + +//Database struct is a holder for the internal database instance. Applications +//can use this exported data type to locally store a reference to database +//instance returned from NewDabase() function. +type Database struct { + instances []iDatabase } //NewDatabase creates a connection to database that will be used -//as a backend for the key-value storage. The returned value shall -//be given as a parameter when calling NewKeyValStorage -func NewDatabase() *sdlgoredis.DB { - return sdlgoredis.Create() +//as a backend for the key-value storage. The returned value +//can be reused between multiple SDL instances in which case each instance +//is using the same connection. +//Deprecated: Will be removed in a future release, because there is no need to +//create a database before NewSyncStorage function is called, database will +//be created automatically by NewSyncStorage function. +func NewDatabase() *Database { + db := &Database{} + for _, v := range sdlgoredis.Create() { + db.instances = append(db.instances, v) + } + return db } //NewSdlInstance creates a new sdl instance using the given namespace. //The database used as a backend is given as a parameter -func NewSdlInstance(NameSpace string, db iDatabase) *SdlInstance { +//Deprecated: Will be removed in a future release, please use NewSyncStorage +//function instead. +func NewSdlInstance(NameSpace string, db *Database) *SdlInstance { return &SdlInstance{ - nameSpace: NameSpace, - nsPrefix: "{" + NameSpace + "},", - eventSeparator: "___", - iDatabase: db, + nameSpace: NameSpace, + nsPrefix: "{" + NameSpace + "},", + storage: newSyncStorage(db), } } @@ -78,132 +89,25 @@ func NewSdlInstance(NameSpace string, db iDatabase) *SdlInstance { //callback as quickly as possible. E.g. reading in callback context should be avoided //and using of Go signals is recommended. Also it should be noted that in case of several //events received from different channels, callbacks are called in series one by one. +// +//Deprecated: Will be removed in a future release, please use the SubscribeChannel +//receiver function of the SyncStorage type. func (s *SdlInstance) SubscribeChannel(cb func(string, ...string), channels ...string) error { - s.SubscribeChannelDB(cb, s.nsPrefix, s.eventSeparator, s.setNamespaceToChannels(channels...)...) - return nil + return s.storage.SubscribeChannel(s.nameSpace, cb, channels...) } //UnsubscribeChannel removes subscription from one or several channels. +//Deprecated: Will be removed in a future release, please use the UnsubscribeChannel +//receiver function of the SyncStorage type. func (s *SdlInstance) UnsubscribeChannel(channels ...string) error { - s.UnsubscribeChannelDB(s.setNamespaceToChannels(channels...)...) - return nil + return s.storage.UnsubscribeChannel(s.nameSpace, channels...) } //Close connection to backend database. +//Deprecated: Will be removed in a future release, please use the Close receiver +//function of the SyncStorage type. func (s *SdlInstance) Close() error { - return s.CloseDB() -} - -func (s *SdlInstance) checkChannelsAndEvents(cmd string, channelsAndEvents []string) error { - if len(channelsAndEvents)%2 != 0 { - return fmt.Errorf("%s: Channels and events must be given as pairs", cmd) - } - for i, v := range channelsAndEvents { - if i%2 != 0 { - if strings.Contains(v, s.eventSeparator) { - return fmt.Errorf("%s: event %s contains illegal substring (\"%s\")", cmd, v, s.eventSeparator) - } - } - } - return nil -} -func (s *SdlInstance) setNamespaceToChannels(channels ...string) []string { - var retVal []string - for _, v := range channels { - retVal = append(retVal, s.nsPrefix+v) - } - return retVal -} - -func (s *SdlInstance) setNamespaceToKeys(pairs ...interface{}) ([]interface{}, error) { - retVal := make([]interface{}, 0) - shouldBeKey := true - for _, v := range pairs { - reflectType := reflect.TypeOf(v) - switch reflectType.Kind() { - case reflect.Map: - x := reflect.ValueOf(v).MapRange() - for x.Next() { - retVal = append(retVal, s.nsPrefix+x.Key().Interface().(string)) - retVal = append(retVal, x.Value().Interface()) - } - case reflect.Slice: - if shouldBeKey { - x := reflect.ValueOf(v) - if x.Len()%2 != 0 { - return []interface{}{}, errors.New("Key/value pairs doesn't match") - } - for i2 := 0; i2 < x.Len(); i2++ { - if i2%2 == 0 { - retVal = append(retVal, s.nsPrefix+x.Index(i2).Interface().(string)) - } else { - retVal = append(retVal, x.Index(i2).Interface()) - } - } - } else { - if reflectType.Elem().Kind() == reflect.Uint8 { - retVal = append(retVal, v) - shouldBeKey = true - } else { - return []interface{}{}, errors.New("Key/value pairs doesn't match") - } - } - case reflect.Array: - if shouldBeKey { - x := reflect.ValueOf(v) - if x.Len()%2 != 0 { - return []interface{}{}, errors.New("Key/value pairs doesn't match") - } - for i2 := 0; i2 < x.Len(); i2++ { - if i2%2 == 0 { - retVal = append(retVal, s.nsPrefix+x.Index(i2).Interface().(string)) - } else { - retVal = append(retVal, x.Index(i2).Interface()) - } - } - } else { - if reflectType.Elem().Kind() == reflect.Uint8 { - retVal = append(retVal, v) - shouldBeKey = true - } else { - return []interface{}{}, errors.New("Key/value pairs doesn't match") - } - } - default: - if shouldBeKey { - retVal = append(retVal, s.nsPrefix+v.(string)) - shouldBeKey = false - } else { - retVal = append(retVal, v) - shouldBeKey = true - } - } - } - if len(retVal)%2 != 0 { - return []interface{}{}, errors.New("Key/value pairs doesn't match") - } - return retVal, nil -} - -func (s *SdlInstance) prepareChannelsAndEvents(channelsAndEvents []string) []string { - channelEventMap := make(map[string]string) - for i, v := range channelsAndEvents { - if i%2 != 0 { - continue - } - _, exists := channelEventMap[v] - if exists { - channelEventMap[v] = channelEventMap[v] + s.eventSeparator + channelsAndEvents[i+1] - } else { - channelEventMap[v] = channelsAndEvents[i+1] - } - } - retVal := make([]string, 0) - for k, v := range channelEventMap { - retVal = append(retVal, s.nsPrefix+k) - retVal = append(retVal, v) - } - return retVal + return s.storage.Close() } //SetAndPublish function writes data to shared data layer storage and sends an event to @@ -219,19 +123,11 @@ func (s *SdlInstance) prepareChannelsAndEvents(channelsAndEvents []string) []str //channel-event pairs. // E.g. []{"channel1", "event1", "channel2", "event2", "channel1", "event3"} //will send event1 and event3 to channel1 and event2 to channel2. +// +//Deprecated: Will be removed in a future release, please use the SetAndPublish +//receiver function of the SyncStorage type. func (s *SdlInstance) SetAndPublish(channelsAndEvents []string, pairs ...interface{}) error { - keyAndData, err := s.setNamespaceToKeys(pairs...) - if err != nil { - return err - } - if len(channelsAndEvents) == 0 { - return s.MSet(keyAndData...) - } - if err := s.checkChannelsAndEvents("SetAndPublish", channelsAndEvents); err != nil { - return err - } - channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents) - return s.MSetMPub(channelsAndEventsPrepared, keyAndData...) + return s.storage.SetAndPublish(s.nameSpace, channelsAndEvents, pairs...) } //Set function writes data to shared data layer storage. Writing is done @@ -240,81 +136,55 @@ func (s *SdlInstance) SetAndPublish(channelsAndEvents []string, pairs ...interfa //pairs can be written with one call. //The key is expected to be string whereas value can be anything, string, //number, slice array or map +//Deprecated: Will be removed in a future release, please use the Set receiver +//function of the SyncStorage type. func (s *SdlInstance) Set(pairs ...interface{}) error { - if len(pairs) == 0 { - return nil - } - - keyAndData, err := s.setNamespaceToKeys(pairs...) - if err != nil { - return err - } - return s.MSet(keyAndData...) + return s.storage.Set(s.nameSpace, pairs...) } //Get function atomically reads one or more keys from SDL. The returned map has the //requested keys as index and data as value. If the requested key is not found -//from SDL, it's value is nil +//from SDL, it's value is nil. +//Deprecated: Will be removed in a future release, please use the Get receiver +//function of the SyncStorage type. func (s *SdlInstance) Get(keys []string) (map[string]interface{}, error) { - m := make(map[string]interface{}) - if len(keys) == 0 { - return m, nil - } - - var keysWithNs []string - for _, v := range keys { - keysWithNs = append(keysWithNs, s.nsPrefix+v) - } - val, err := s.MGet(keysWithNs) - if err != nil { - return m, err - } - for i, v := range val { - m[keys[i]] = v - } - return m, err + return s.storage.Get(s.nameSpace, keys) } //SetIfAndPublish atomically replaces existing data with newData in SDL if data matches the oldData. //If replace was done successfully, true will be returned. Also, if publishing was successfull, an event //is published to a given channel. +//Deprecated: Will be removed in a future release, please use the SetIfAndPublish +//receiver function of the SyncStorage type. func (s *SdlInstance) SetIfAndPublish(channelsAndEvents []string, key string, oldData, newData interface{}) (bool, error) { - if len(channelsAndEvents) == 0 { - return s.SetIE(s.nsPrefix+key, oldData, newData) - } - if err := s.checkChannelsAndEvents("SetIfAndPublish", channelsAndEvents); err != nil { - return false, err - } - channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents) - return s.SetIEPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], s.nsPrefix+key, oldData, newData) + return s.storage.SetIfAndPublish(s.nameSpace, channelsAndEvents, key, oldData, newData) } //SetIf atomically replaces existing data with newData in SDL if data matches the oldData. //If replace was done successfully, true will be returned. +//Deprecated: Will be removed in a future release, please use the SetIf receiver +//function of the SyncStorage type. func (s *SdlInstance) SetIf(key string, oldData, newData interface{}) (bool, error) { - return s.SetIE(s.nsPrefix+key, oldData, newData) + return s.storage.SetIf(s.nameSpace, key, oldData, newData) } //SetIfNotExistsAndPublish conditionally sets the value of a key. If key already exists in SDL, //then it's value is not changed. Checking the key existence and potential set operation //is done atomically. If the set operation was done successfully, an event is published to a //given channel. +//Deprecated: Will be removed in a future release, please use the SetIfNotExistsAndPublish +//receiver function of the SyncStorage type. func (s *SdlInstance) SetIfNotExistsAndPublish(channelsAndEvents []string, key string, data interface{}) (bool, error) { - if len(channelsAndEvents) == 0 { - return s.SetNX(s.nsPrefix+key, data, 0) - } - if err := s.checkChannelsAndEvents("SetIfNotExistsAndPublish", channelsAndEvents); err != nil { - return false, err - } - channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents) - return s.SetNXPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], s.nsPrefix+key, data) + return s.storage.SetIfNotExistsAndPublish(s.nameSpace, channelsAndEvents, key, data) } //SetIfNotExists conditionally sets the value of a key. If key already exists in SDL, //then it's value is not changed. Checking the key existence and potential set operation //is done atomically. +//Deprecated: Will be removed in a future release, please use the SetIfNotExists +//receiver function of the SyncStorage type. func (s *SdlInstance) SetIfNotExists(key string, data interface{}) (bool, error) { - return s.SetNX(s.nsPrefix+key, data, 0) + return s.storage.SetIfNotExists(s.nameSpace, key, data) } //RemoveAndPublish removes data from SDL. Operation is done atomically, i.e. either all succeeds or fails. @@ -322,109 +192,59 @@ func (s *SdlInstance) SetIfNotExists(key string, data interface{}) (bool, error) //An event is published into a given channel if remove operation is successfull and //at least one key is removed (if several keys given). If the given key(s) doesn't exist //when trying to remove, no event is published. +//Deprecated: Will be removed in a future release, please use the RemoveAndPublish +//receiver function of the SyncStorage type. func (s *SdlInstance) RemoveAndPublish(channelsAndEvents []string, keys []string) error { - if len(keys) == 0 { - return nil - } - - var keysWithNs []string - for _, v := range keys { - keysWithNs = append(keysWithNs, s.nsPrefix+v) - } - if len(channelsAndEvents) == 0 { - return s.Del(keysWithNs) - } - if err := s.checkChannelsAndEvents("RemoveAndPublish", channelsAndEvents); err != nil { - return err - } - channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents) - return s.DelMPub(channelsAndEventsPrepared, keysWithNs) + return s.storage.RemoveAndPublish(s.nameSpace, channelsAndEvents, keys) } //Remove data from SDL. Operation is done atomically, i.e. either all succeeds or fails. +//Deprecated: Will be removed in a future release, please use the Remove receiver +//function of the SyncStorage type. func (s *SdlInstance) Remove(keys []string) error { - if len(keys) == 0 { - return nil - } - - var keysWithNs []string - for _, v := range keys { - keysWithNs = append(keysWithNs, s.nsPrefix+v) - } - err := s.Del(keysWithNs) - return err + return s.storage.Remove(s.nameSpace, keys) } //RemoveIfAndPublish removes data from SDL conditionally and if remove was done successfully, //a given event is published to channel. If existing data matches given data, //key and data are removed from SDL. If remove was done successfully, true is returned. +//Deprecated: Will be removed in a future release, please use the RemoveIfAndPublish +//receiver function of the SyncStorage type. func (s *SdlInstance) RemoveIfAndPublish(channelsAndEvents []string, key string, data interface{}) (bool, error) { - if len(channelsAndEvents) == 0 { - return s.DelIE(s.nsPrefix+key, data) - } - if err := s.checkChannelsAndEvents("RemoveIfAndPublish", channelsAndEvents); err != nil { - return false, err - } - channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents) - return s.DelIEPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], s.nsPrefix+key, data) + return s.storage.RemoveIfAndPublish(s.nameSpace, channelsAndEvents, key, data) } //RemoveIf removes data from SDL conditionally. If existing data matches given data, //key and data are removed from SDL. If remove was done successfully, true is returned. +//Deprecated: Will be removed in a future release, please use the RemoveIf receiver +//function of the SyncStorage type. func (s *SdlInstance) RemoveIf(key string, data interface{}) (bool, error) { - status, err := s.DelIE(s.nsPrefix+key, data) - if err != nil { - return false, err - } - return status, nil + return s.storage.RemoveIf(s.nameSpace, key, data) } //GetAll returns all keys under the namespace. No prior knowledge about the keys in the //given namespace exists, thus operation is not guaranteed to be atomic or isolated. +//Deprecated: Will be removed in a future release, please use the GetAll receiver +//function of the SyncStorage type. func (s *SdlInstance) GetAll() ([]string, error) { - keys, err := s.Keys(s.nsPrefix + "*") - var retVal []string - if err != nil { - return retVal, err - } - for _, v := range keys { - retVal = append(retVal, strings.Split(v, s.nsPrefix)[1]) - } - return retVal, err + return s.storage.GetAll(s.nameSpace) } //RemoveAll removes all keys under the namespace. Remove operation is not atomic, thus //it is not guaranteed that all keys are removed. +//Deprecated: Will be removed in a future release, please use the RemoveAll receiver +//function of the SyncStorage type. func (s *SdlInstance) RemoveAll() error { - keys, err := s.Keys(s.nsPrefix + "*") - if err != nil { - return err - } - if (keys != nil) && (len(keys) != 0) { - err = s.Del(keys) - } - return err + return s.storage.RemoveAll(s.nameSpace) } //RemoveAllAndPublish removes all keys under the namespace and if successfull, it //will publish an event to given channel. This operation is not atomic, thus it is //not guaranteed that all keys are removed. +//Deprecated: Will be removed in a future release, please use the RemoveAllAndPublish +//receiver function of the SyncStorage type. func (s *SdlInstance) RemoveAllAndPublish(channelsAndEvents []string) error { - keys, err := s.Keys(s.nsPrefix + "*") - if err != nil { - return err - } - if (keys != nil) && (len(keys) != 0) { - if len(channelsAndEvents) == 0 { - return s.Del(keys) - } - if err := s.checkChannelsAndEvents("RemoveIfAndPublish", channelsAndEvents); err != nil { - return err - } - channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents) - err = s.DelMPub(channelsAndEventsPrepared, keys) - } - return err + return s.storage.RemoveAllAndPublish(s.nameSpace, channelsAndEvents) } //AddMember adds a new members to a group. @@ -432,128 +252,86 @@ func (s *SdlInstance) RemoveAllAndPublish(channelsAndEvents []string) error { //SDL groups are unordered collections of members where each member is //unique. It is possible to add the same member several times without the //need to check if it already exists. +//Deprecated: Will be removed in a future release, please use the AddMember +//receiver function of the SyncStorage type. func (s *SdlInstance) AddMember(group string, member ...interface{}) error { - return s.SAdd(s.nsPrefix+group, member...) + return s.storage.AddMember(s.nameSpace, group, member...) } //RemoveMember removes members from a group. +//Deprecated: Will be removed in a future release, please use the RemoveMember +//receiver function of the SyncStorage type. func (s *SdlInstance) RemoveMember(group string, member ...interface{}) error { - return s.SRem(s.nsPrefix+group, member...) + return s.storage.RemoveMember(s.nameSpace, group, member...) } //RemoveGroup removes the whole group along with it's members. +//Deprecated: Will be removed in a future release, please use the RemoveGroup +//receiver function of the SyncStorage type. func (s *SdlInstance) RemoveGroup(group string) error { - return s.Del([]string{s.nsPrefix + group}) + return s.storage.RemoveGroup(s.nameSpace, group) } //GetMembers returns all the members from a group. +//Deprecated: Will be removed in a future release, please use the GetMembers +//receiver function of the SyncStorage type. func (s *SdlInstance) GetMembers(group string) ([]string, error) { - retVal, err := s.SMembers(s.nsPrefix + group) - if err != nil { - return []string{}, err - } - return retVal, err + return s.storage.GetMembers(s.nameSpace, group) } //IsMember returns true if given member is found from a group. func (s *SdlInstance) IsMember(group string, member interface{}) (bool, error) { - retVal, err := s.SIsMember(s.nsPrefix+group, member) - if err != nil { - return false, err - } - return retVal, err + return s.storage.IsMember(s.nameSpace, group, member) } //GroupSize returns the number of members in a group. +//Deprecated: Will be removed in a future release, please use the GroupSize +//receiver function of the SyncStorage type. func (s *SdlInstance) GroupSize(group string) (int64, error) { - retVal, err := s.SCard(s.nsPrefix + group) - if err != nil { - return 0, err - } - return retVal, err -} - -func (s *SdlInstance) randomToken() (string, error) { - s.mutex.Lock() - defer s.mutex.Unlock() - - if len(s.tmp) == 0 { - s.tmp = make([]byte, 16) - } - - if _, err := io.ReadFull(rand.Reader, s.tmp); err != nil { - return "", err - } - - return base64.RawURLEncoding.EncodeToString(s.tmp), nil + return s.storage.GroupSize(s.nameSpace, group) } //LockResource function is used for locking a resource. The resource lock in //practice is a key with random value that is set to expire after a time //period. The value written to key is a random value, thus only the instance //created a lock, can release it. Resource locks are per namespace. +//Deprecated: Will be removed in a future release, please use the LockResource +//receiver function of the SyncStorage type. func (s *SdlInstance) LockResource(resource string, expiration time.Duration, opt *Options) (*Lock, error) { - value, err := s.randomToken() - if err != nil { - return nil, err - } - - var retryTimer *time.Timer - for i, attempts := 0, opt.getRetryCount()+1; i < attempts; i++ { - ok, err := s.SetNX(s.nsPrefix+resource, value, expiration) - if err != nil { - return nil, err - } else if ok { - return &Lock{s: s, key: resource, value: value}, nil - } - if retryTimer == nil { - retryTimer = time.NewTimer(opt.getRetryWait()) - defer retryTimer.Stop() - } else { - retryTimer.Reset(opt.getRetryWait()) - } - - select { - case <-retryTimer.C: - } + l, err := s.storage.LockResource(s.nameSpace, resource, expiration, opt) + if l != nil { + return &Lock{ + s: s, + storageLock: l, + }, err } - return nil, errors.New("Lock not obtained") + return nil, err } //ReleaseResource removes the lock from a resource. If lock is already //expired or some other instance is keeping the lock (lock taken after expiration), //an error is returned. +//Deprecated: Will be removed in a future release, please use the ReleaseResource +//receiver function of the SyncStorageLock type. func (l *Lock) ReleaseResource() error { - ok, err := l.s.DelIE(l.s.nsPrefix+l.key, l.value) - - if err != nil { - return err - } - if !ok { - return errors.New("Lock not held") - } - return nil + return l.storageLock.ReleaseResource(l.s.nameSpace) } //RefreshResource function can be used to set a new expiration time for the //resource lock (if the lock still exists). The old remaining expiration //time is overwritten with the given new expiration time. +//Deprecated: Will be removed in a future release, please use the RefreshResource +//receiver function of the SyncStorageLock type. func (l *Lock) RefreshResource(expiration time.Duration) error { - err := l.s.PExpireIE(l.s.nsPrefix+l.key, l.value, expiration) - return err + return l.storageLock.RefreshResource(l.s.nameSpace, expiration) } //CheckResource returns the expiration time left for a resource. //If the resource doesn't exist, -2 is returned. +//Deprecated: Will be removed in a future release, please use the CheckResource +//receiver function of the SyncStorage type. func (s *SdlInstance) CheckResource(resource string) (time.Duration, error) { - result, err := s.PTTL(s.nsPrefix + resource) - if err != nil { - return 0, err - } - if result == time.Duration(-1) { - return 0, errors.New("invalid resource given, no expiration time attached") - } - return result, nil + return s.storage.CheckResource(s.nameSpace, resource) } //Options struct defines the behaviour for getting the resource lock. @@ -583,33 +361,9 @@ func (o *Options) getRetryWait() time.Duration { //Lock struct identifies the resource lock instance. Releasing and adjusting the //expirations are done using the methods defined for this struct. +//Deprecated: Will be removed in a future release, please use instead the SyncStorageLock +//type defined in syncstorage.go. type Lock struct { - s *SdlInstance - key string - value string -} - -type iDatabase interface { - SubscribeChannelDB(cb sdlgoredis.ChannelNotificationCb, channelPrefix, eventSeparator string, channels ...string) - UnsubscribeChannelDB(channels ...string) - MSet(pairs ...interface{}) error - MSetMPub(channelsAndEvents []string, pairs ...interface{}) error - MGet(keys []string) ([]interface{}, error) - CloseDB() error - Del(keys []string) error - DelMPub(channelsAndEvents []string, keys []string) error - Keys(key string) ([]string, error) - SetIE(key string, oldData, newData interface{}) (bool, error) - SetIEPub(channel, message, key string, oldData, newData interface{}) (bool, error) - SetNX(key string, data interface{}, expiration time.Duration) (bool, error) - SetNXPub(channel, message, key string, data interface{}) (bool, error) - DelIE(key string, data interface{}) (bool, error) - DelIEPub(channel, message, key string, data interface{}) (bool, error) - SAdd(key string, data ...interface{}) error - SRem(key string, data ...interface{}) error - SMembers(key string) ([]string, error) - SIsMember(key string, data interface{}) (bool, error) - SCard(key string) (int64, error) - PTTL(key string) (time.Duration, error) - PExpireIE(key string, data interface{}, expiration time.Duration) error + s *SdlInstance + storageLock *SyncStorageLock }