blob: fb2c8130dc9bf03f08cb8dc2d54a3a40b57f5493 [file] [log] [blame]
Scott Baker2c1c4822019-10-16 11:02:41 -07001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package model
18
19import (
20 "errors"
21 "fmt"
Scott Baker2c1c4822019-10-16 11:02:41 -070022 "github.com/opencord/voltha-lib-go/pkg/db/kvstore"
Scott Bakere73f91e2019-10-17 12:58:11 -070023 "github.com/opencord/voltha-lib-go/pkg/log"
Scott Baker2c1c4822019-10-16 11:02:41 -070024 "strconv"
25 "sync"
26 "time"
27)
28
29//TODO: missing cache stuff
30//TODO: missing retry stuff
31//TODO: missing proper logging
32
33// Backend structure holds details for accessing the kv store
34type Backend struct {
35 sync.RWMutex
36 Client kvstore.Client
37 StoreType string
38 Host string
39 Port int
40 Timeout int
41 PathPrefix string
42}
43
44// NewBackend creates a new instance of a Backend structure
45func NewBackend(storeType string, host string, port int, timeout int, pathPrefix string) *Backend {
46 var err error
47
48 b := &Backend{
49 StoreType: storeType,
50 Host: host,
51 Port: port,
52 Timeout: timeout,
53 PathPrefix: pathPrefix,
54 }
55
56 address := host + ":" + strconv.Itoa(port)
57 if b.Client, err = b.newClient(address, timeout); err != nil {
58 log.Errorw("failed-to-create-kv-client",
59 log.Fields{
60 "type": storeType, "host": host, "port": port,
61 "timeout": timeout, "prefix": pathPrefix,
62 "error": err.Error(),
63 })
64 }
65
66 return b
67}
68
69func (b *Backend) newClient(address string, timeout int) (kvstore.Client, error) {
70 switch b.StoreType {
71 case "consul":
72 return kvstore.NewConsulClient(address, timeout)
73 case "etcd":
74 return kvstore.NewEtcdClient(address, timeout)
75 }
76 return nil, errors.New("unsupported-kv-store")
77}
78
79func (b *Backend) makePath(key string) string {
80 path := fmt.Sprintf("%s/%s", b.PathPrefix, key)
81 return path
82}
83
84// List retrieves one or more items that match the specified key
85func (b *Backend) List(key string, lock ...bool) (map[string]*kvstore.KVPair, error) {
86 b.Lock()
87 defer b.Unlock()
88
89 formattedPath := b.makePath(key)
90 log.Debugw("listing-key", log.Fields{"key": key, "path": formattedPath, "lock": lock})
91
92 return b.Client.List(formattedPath, b.Timeout, lock...)
93}
94
95// Get retrieves an item that matches the specified key
96func (b *Backend) Get(key string, lock ...bool) (*kvstore.KVPair, error) {
97 b.Lock()
98 defer b.Unlock()
99
100 formattedPath := b.makePath(key)
101 log.Debugw("getting-key", log.Fields{"key": key, "path": formattedPath, "lock": lock})
102
103 start := time.Now()
104 err, pair := b.Client.Get(formattedPath, b.Timeout, lock...)
105 stop := time.Now()
106
107 GetProfiling().AddToDatabaseRetrieveTime(stop.Sub(start).Seconds())
108
109 return err, pair
110}
111
112// Put stores an item value under the specifed key
113func (b *Backend) Put(key string, value interface{}, lock ...bool) error {
114 b.Lock()
115 defer b.Unlock()
116
117 formattedPath := b.makePath(key)
118 log.Debugw("putting-key", log.Fields{"key": key, "value": string(value.([]byte)), "path": formattedPath, "lock": lock})
119
120 return b.Client.Put(formattedPath, value, b.Timeout, lock...)
121}
122
123// Delete removes an item under the specified key
124func (b *Backend) Delete(key string, lock ...bool) error {
125 b.Lock()
126 defer b.Unlock()
127
128 formattedPath := b.makePath(key)
129 log.Debugw("deleting-key", log.Fields{"key": key, "path": formattedPath, "lock": lock})
130
131 return b.Client.Delete(formattedPath, b.Timeout, lock...)
132}
133
134// CreateWatch starts watching events for the specified key
135func (b *Backend) CreateWatch(key string) chan *kvstore.Event {
136 b.Lock()
137 defer b.Unlock()
138
139 formattedPath := b.makePath(key)
140 log.Debugw("creating-key-watch", log.Fields{"key": key, "path": formattedPath})
141
142 return b.Client.Watch(formattedPath)
143}
144
145// DeleteWatch stops watching events for the specified key
146func (b *Backend) DeleteWatch(key string, ch chan *kvstore.Event) {
147 b.Lock()
148 defer b.Unlock()
149
150 formattedPath := b.makePath(key)
151 log.Debugw("deleting-key-watch", log.Fields{"key": key, "path": formattedPath})
152
153 b.Client.CloseWatch(formattedPath, ch)
154}