Make DB instance visible 39/1139/5 v0.5.0
authorMarco Tallskog <marco.tallskog@nokia.com>
Fri, 11 Oct 2019 10:24:04 +0000 (13:24 +0300)
committerMarco Tallskog <marco.tallskog@nokia.com>
Mon, 14 Oct 2019 14:24:50 +0000 (17:24 +0300)
Make underlying DB instance visible to clients. This change makes it
easier for the clients to e.g. share the same DB instance between
multiple SDL instances (multiple namespaces is used). The DB instance
can be created once and reuse it every time a new SDL instance is
created. The DB instance is created with Newdatabase() method.

Update the documentation so that it is mentioned that subscribing the
channels is not safe for concurrent usage.

Change-Id: I1b09500eda44b6b095a3bf564c38e794d02f9d95
Signed-off-by: Marco Tallskog <marco.tallskog@nokia.com>
doc.go
internal/sdlgoredis/sdlgoredis.go
sdl.go
sdl_private_fn_test.go [new file with mode: 0644]
sdl_test.go

diff --git a/doc.go b/doc.go
index 038ee11..840cba6 100644 (file)
--- a/doc.go
+++ b/doc.go
@@ -27,6 +27,9 @@ event mechanism that can be used to notify listeners that data was changed.
 This SDL version assumes that the DBAAS service provided by O-RAN community is
 working as a storage backend.
 
+All functions except receiving of notifications are safe for concurrent usage by
+multiple goroutines.
+
 Namespace
 
 A shared data layer connection is instantiated to a namespace and data is
index f1c7e62..8e2a2ef 100644 (file)
@@ -183,7 +183,7 @@ func (db *DB) UnsubscribeChannelDB(channels ...string) {
        }
 }
 
-func (db *DB) SubscribeChannelDB(cb ChannelNotificationCb, channelPrefix, eventSeparator string, channels ...string) {
+func (db *DB) SubscribeChannelDB(cb func(string, ...string), channelPrefix, eventSeparator string, channels ...string) {
        if len(db.cbMap) == 0 {
                for _, v := range channels {
                        db.cbMap[v] = cb
diff --git a/sdl.go b/sdl.go
index 426c2c4..f2cdacb 100644 (file)
--- a/sdl.go
+++ b/sdl.go
@@ -42,21 +42,31 @@ type SdlInstance struct {
        iDatabase
 }
 
+//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 {
+       instance 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.
+func NewDatabase() *Database {
+       return &Database{
+               instance: sdlgoredis.Create(),
+       }
 }
 
 //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 {
+func NewSdlInstance(NameSpace string, db *Database) *SdlInstance {
        return &SdlInstance{
                nameSpace:      NameSpace,
                nsPrefix:       "{" + NameSpace + "},",
                eventSeparator: "___",
-               iDatabase:      db,
+               iDatabase:      db.instance,
        }
 }
 
@@ -78,6 +88,8 @@ 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.
+//
+//This function is NOT SAFE FOR CONCURRENT USE by multiple goroutines.
 func (s *SdlInstance) SubscribeChannel(cb func(string, ...string), channels ...string) error {
        s.SubscribeChannelDB(cb, s.nsPrefix, s.eventSeparator, s.setNamespaceToChannels(channels...)...)
        return nil
@@ -590,7 +602,7 @@ type Lock struct {
 }
 
 type iDatabase interface {
-       SubscribeChannelDB(cb sdlgoredis.ChannelNotificationCb, channelPrefix, eventSeparator string, channels ...string)
+       SubscribeChannelDB(cb func(string, ...string), channelPrefix, eventSeparator string, channels ...string)
        UnsubscribeChannelDB(channels ...string)
        MSet(pairs ...interface{}) error
        MSetMPub(channelsAndEvents []string, pairs ...interface{}) error
diff --git a/sdl_private_fn_test.go b/sdl_private_fn_test.go
new file mode 100644 (file)
index 0000000..4a4e43e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package sdlgo
+
+//NewSdlInstanceForTest is used in unit tests only in order to replace the
+//underlying redis implementation with mock
+func NewSdlInstanceForTest(NameSpace string, instance iDatabase) *SdlInstance {
+       return &SdlInstance{
+               nameSpace:      NameSpace,
+               nsPrefix:       "{" + NameSpace + "},",
+               eventSeparator: "___",
+               iDatabase:      instance,
+       }
+}
index 832e8eb..944edaa 100644 (file)
@@ -24,7 +24,6 @@ import (
        "time"
 
        "gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
-       "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/mock"
 )
@@ -33,7 +32,7 @@ type mockDB struct {
        mock.Mock
 }
 
-func (m *mockDB) SubscribeChannelDB(cb sdlgoredis.ChannelNotificationCb, channelPrefix, eventSeparator string, channels ...string) {
+func (m *mockDB) SubscribeChannelDB(cb func(string, ...string), channelPrefix, eventSeparator string, channels ...string) {
        m.Called(cb, channelPrefix, eventSeparator, channels)
 }
 
@@ -142,7 +141,7 @@ func (m *mockDB) PExpireIE(key string, data interface{}, expiration time.Duratio
 
 func setup() (*mockDB, *sdlgo.SdlInstance) {
        m := new(mockDB)
-       i := sdlgo.NewSdlInstance("namespace", m)
+       i := sdlgo.NewSdlInstanceForTest("namespace", m)
        return m, i
 }
 
@@ -171,7 +170,7 @@ func TestSubscribeChannel(t *testing.T) {
        expectedCB := func(channel string, events ...string) {}
        expectedChannels := []string{"{namespace},channel1", "{namespace},channel2"}
 
-       m.On("SubscribeChannelDB", mock.AnythingOfType("sdlgoredis.ChannelNotificationCb"), "{namespace},", "___", expectedChannels).Return()
+       m.On("SubscribeChannelDB", mock.AnythingOfType("func(string, ...string)"), "{namespace},", "___", expectedChannels).Return()
        i.SubscribeChannel(expectedCB, "channel1", "channel2")
        m.AssertExpectations(t)
 }