Merge "RIC:1060: Change in PTL"
[ric-plt/sdlgo.git] / sdl.go
diff --git a/sdl.go b/sdl.go
index 4d98904..02dae3d 100644 (file)
--- a/sdl.go
+++ b/sdl.go
    limitations under the License.
 */
 
+/*
+ * This source code is part of the near-RT RIC (RAN Intelligent Controller)
+ * platform project (RICP).
+ */
+
 package sdlgo
 
 import (
-       "errors"
-       "fmt"
-       "reflect"
-       "strings"
-
        "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
+       "time"
 )
 
-type iDatabase interface {
-       SubscribeChannelDB(cb sdlgoredis.ChannelNotificationCb, channelPrefix, eventSeparator string, channels ...string)
-       UnsubscribeChannelDB(channels ...string)
-       MSet(pairs ...interface{}) error
-       MSetPub(ns, message string, pairs ...interface{}) error
-       MGet(keys []string) ([]interface{}, error)
-       CloseDB() error
-       Del(keys []string) error
-       DelPub(channel, message 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{}) (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)
-}
-
 //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
-       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),
        }
 }
 
@@ -89,145 +89,45 @@ 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.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 {
-                               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 {
-                               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 send an event to
+//SetAndPublish function writes data to shared data layer storage and sends an event to
 //a channel. Writing is done atomically, i.e. all succeeds or fails.
 //Data to be written is given as key-value pairs. Several key-value
 //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
 //
+//If data was set successfully, an event is sent to a channel.
 //Channels and events are given as pairs is channelsAndEvents parameter.
-//Although it is possible to give sevral channel-event pairs, current implementation
-//supports sending events to one channel only due to missing support in DB backend.
+//It is possible to send several events to several channels by giving several
+//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 {
-       if len(pairs)%2 != 0 {
-               return errors.New("Invalid pairs parameter")
-       }
-
-       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.MSetPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], keyAndData...)
+       return s.storage.SetAndPublish(s.nameSpace, channelsAndEvents, pairs...)
 }
 
 //Set function writes data to shared data layer storage. Writing is done
@@ -236,184 +136,234 @@ 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)
-       }
-       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)
+       return s.storage.SetIfNotExists(s.nameSpace, key, data)
 }
 
 //RemoveAndPublish removes data from SDL. Operation is done atomically, i.e. either all succeeds or fails.
-//An event is published into a given channel if remove operation is successfull.
+//Trying to remove a nonexisting key is not considered as an 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.DelPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], 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
+       return s.storage.RemoveAllAndPublish(s.nameSpace, channelsAndEvents)
+}
+
+//AddMember adds a new members to a group.
+//
+//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.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.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.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) {
+       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) {
+       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) {
+       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) {
+       l, err := s.storage.LockResource(s.nameSpace, resource, expiration, opt)
+       if l != nil {
+               return &Lock{
+                       s:           s,
+                       storageLock: l,
+               }, err
+       }
+       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 {
+       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 {
+       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) {
+       return s.storage.CheckResource(s.nameSpace, resource)
+}
+
+//Options struct defines the behaviour for getting the resource lock.
+type Options struct {
+       //The number of time the lock will be tried.
+       //Default: 0 = no retry
+       RetryCount int
+
+       //Wait between the retries.
+       //Default: 100ms
+       RetryWait time.Duration
+}
+
+func (o *Options) getRetryCount() int {
+       if o != nil && o.RetryCount > 0 {
+               return o.RetryCount
        }
-       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.DelPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], keys)
+       return 0
+}
+
+func (o *Options) getRetryWait() time.Duration {
+       if o != nil && o.RetryWait > 0 {
+               return o.RetryWait
        }
-       return err
+       return 100 * time.Millisecond
+}
 
+//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
+       storageLock *SyncStorageLock
 }