Make DB instance visible
[ric-plt/sdlgo.git] / doc.go
1 /*
2    Copyright (c) 2019 AT&T Intellectual Property.
3    Copyright (c) 2018-2019 Nokia.
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16 */
17
18 /*
19 Package sdlgo provides a lightweight, high-speed interface for accessing shared data storage.
20
21 Shared Data Layer (SDL) is a concept where applications can use and share data using a common
22 storage. The storage must be optimised for very high tranactional throughput and very low
23 latency. Sdlgo is a library which provides applications an API to read and write data
24 to a common storage using key-value paradigm. In addition to this, sdlgo provides an
25 event mechanism that can be used to notify listeners that data was changed.
26
27 This SDL version assumes that the DBAAS service provided by O-RAN community is
28 working as a storage backend.
29
30 All functions except receiving of notifications are safe for concurrent usage by
31 multiple goroutines.
32
33 Namespace
34
35 A shared data layer connection is instantiated to a namespace and data is
36 always read and modified within the namespace. Namespace provides data isolation across clients.
37 Namespace instantiation happens when the sdlgo instance is created.
38 E.g. the following code sets the SDL instance to use "example" as a namespace
39   sdl := sdlgo.NewSdlInstance("example", sdlgo.NewDatabase())
40 Applications can use several namespaces at the same time by creating several sdlgo instances.
41
42 Database connection
43
44 In addition to creating the SDL instance, application is responsible for creating the backend
45 database connection with NewDatabase() method. When the connection is created, sdlgo shall open a
46 tcp connection to backend database immediatelly. The resulting connection may be used with several
47 SDL instances if application needs to use several namespaces at a time. E.g.
48   connection := sdlgo.NewDatabase()
49   ns1 := sdlgo.NewSdlInstance("ns1", connection)
50   ns2 := sdlgo.NewSdlInstance("ns2", connection)
51 For the backend database connection a circuit breaker design is used. If the connection fails,
52 an error is returned immediatelly to application. Restoration of the connection happens
53 automatically by SDL and application should retry the operation again after a while.
54
55 Database service is discovered by using environment variables DBAAS_SERVICE_HOST and
56 DBAAS_SERVICE_PORT. If not set, localhost and port 6379 are used by default.
57
58 Keys and data
59
60 Clients save key-value pairs. Keys are allways strings. The types of the values must be of a basic
61 type, i.e. string, integer or byte array or slice. This means that the internal structures, like
62 protobufs or JSON objects, must be serialised to a byte array or slice before passing it to SDL.
63 Clients are responsible for managing the keys within a namespace.
64
65 Some examples on how to set the data using different kind of input parameters:
66
67 Basic usage, keys and values are given as own parameters (with mixed data types)
68   err := s.Set("key1", "value1", "key2", 2)
69
70 Keys and values inside a slice (again with mixed types, thus empty interface used as a type)
71   exampleSlice := []interface{"key1", "value1", "key2", 2}
72   err := s.Set(exampleSlice)
73
74 Data stored to a byte array
75   data := make([]byte), 3
76   data[0] = 1
77   data[1] = 2
78   data[2] = 3
79   s.Set("key", data)
80
81 Keys and values stored into a map (byte array "data" used from previous example)
82   mapData := map[string]interface{
83     "key1" : "data",
84     "key2" : 2,
85     "key3" : data,
86   }
87
88 When data is read from SDL storage, a map is returned where the requested key works as map key.
89 If the key was not found, the value for the given key is nil. It is possible to request several
90 key with one Get() call.
91
92 Groups
93
94 SDL groups are unordered collections of members where each member is unique. Using the SDL API
95 it is possible to add/remove members from a group, remove the whole group or do queries like the
96 size of a group and if member belongs to a group. Like key-value storage, groups are per namespace.
97
98 Events
99
100 Events are a publish-subscribe pattern to indicate interested parties that there has been a change
101 in data. Delivery of the events are not guaranteed. In SDL, events are happening via channels and
102 channels are per namespace. It is possible to publish several kinds of events through one channel.
103
104 In order to publish changes to SDL data, the publisher need to call an API function that supports
105 publishing. E.g.
106    err := sdl.SetAndPublish([]string{"channel1", "event1", "channel2", "event2"}, "key", "value")
107 This example will publish event1 to channel1 and event2 in channel2 after writing the data.
108
109 When subscribing the channels, the application needs to first create an SDL instance for the desired
110 namespace. The subscription happens using the SubscribeChannel() API function. The parameters for
111 the function takes a callback function and one or many channels to be subscribed. When an event is
112 received for the given channel, the given callback function shall be called with one or many events.
113 It is possible to make several subscriptions for different channels using different callback
114 functions if different kind of handling is required.
115
116   sdl := sdlgo.NewSdlInstance("namespace", sdlgo.NewDatabase())
117
118   cb1 := func(channel string, event ...string) {
119     fmt.Printf("cb1: Received %s from channel %s\n", event, channel)
120   }
121
122   cb2 := func(channel string, event ...string) {
123     fmt.Printf("cb2: Received %s from channel %s\n", event, channel)
124   }
125
126   sdl.SubscribeChannel(cb1, "channel1", "channel2")
127   sdl.SubscribeChannel(cb2, "channel3")
128
129 This example subscribes three channels from "namespace" and assigns cb1 for channel1 and channel2
130 whereas channel3 is assigned to cb2.
131
132 The callbacks are called from a context of a goroutine that is listening for the events. When
133 application receives events, the preferred way to do the required processing of an event (e.g. read
134 from SDL) is to do it in another context, e.g. by triggering applications own goroutine using Go
135 channels. By doing like this, blocking the receive routine and possibly loosing events, can be
136 avoided.
137 */
138 package sdlgo