From 5bd649776a32ed03600f5b0f147dbd5596905737 Mon Sep 17 00:00:00 2001 From: Petri Ovaska Date: Wed, 22 Sep 2021 08:09:53 +0300 Subject: [PATCH] New ListKeys API in syncstorage The ListKeys API returns all keys in the given namespace matching key search pattern. Also update sdltester -tool to test ListKeys api: listkeys - List keys in the given namespace matching key search pattern. Upgraded ci/Dockerfile golang image version tag to 1.16. This is due to expired Root CA certificates in golang:1.12 image which result an error when building docker image: fatal: unable to access 'https://gopkg.in/tomb.v1/': server certificate verification failed. CAfile: none CRLfile: none Version: 0.8.0 Issue-Id: RIC-110 Signed-off-by: Petri Ovaska Change-Id: Ic02a3f127934a1e02e01a36c573d035db34dbd6f --- ci/Dockerfile | 2 +- cmd/sdltester/sdltester.go | 19 +++++++++++ docs/release-notes.rst | 5 +++ sdl_private_fn_test.go | 8 +++++ syncstorage.go | 28 ++++++++++++++++ syncstorage_test.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 syncstorage_test.go diff --git a/ci/Dockerfile b/ci/Dockerfile index a5b8141..f9dd918 100644 --- a/ci/Dockerfile +++ b/ci/Dockerfile @@ -23,7 +23,7 @@ # This is a Dockerfile for code verification only. # Not to be pushed or used for anything else. # -FROM golang:1.12 +FROM golang:1.16 RUN mkdir -p $GOPATH/src/sdlgo COPY . $GOPATH/src/sdlgo diff --git a/cmd/sdltester/sdltester.go b/cmd/sdltester/sdltester.go index f2eb379..9f6e493 100644 --- a/cmd/sdltester/sdltester.go +++ b/cmd/sdltester/sdltester.go @@ -79,6 +79,8 @@ func main() { noexist(sdl) case "getall": getall(sdl) + case "listkeys": + listkeys(sdl) case "removeall": removeall(sdl) case "emptymap": @@ -112,6 +114,7 @@ func printHelp() { fmt.Println(" found") fmt.Println("getall Read all keys within a namespace. One can manually add keys under the used namespace and all") fmt.Println(" those keys should be returned here. Performance is measured") + fmt.Println("listkeys List keys in the given namespace matching key search pattern.") fmt.Println("removeall Remove all keys within a namespace. Performance is measured") fmt.Println("emptymap Write an empty container. Performance is measured") fmt.Println("multiple Make two writes. Performance is measured") @@ -193,6 +196,22 @@ func getall(sdl *sdlgo.SyncStorage) { } } +func listkeys(sdl *sdlgo.SyncStorage) { + start := time.Now() + ns := "tag1" + pattern := "*" + keys, err := sdl.ListKeys(ns, pattern) + elapsed := time.Since(start) + if err == nil { + fmt.Printf("ListKeys(%s, %s): %s\n", ns, pattern, elapsed) + for _, i := range keys { + fmt.Println(i) + } + } else { + fmt.Println(err) + } +} + func removeall(sdl *sdlgo.SyncStorage) { start := time.Now() err := sdl.RemoveAll("tag1") diff --git a/docs/release-notes.rst b/docs/release-notes.rst index b0a7dd6..319c497 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -30,6 +30,11 @@ This document provides the release notes of the sdlgo. Version history --------------- +[0.8.0] - 2021-09-22 + +* New ListKeys API in syncstorage +* Add deprecation warnings for SdlInstance APIs + [0.7.0] - 2021-05-11 * Add DB backend instance selection based on namespace value to balance DB load. diff --git a/sdl_private_fn_test.go b/sdl_private_fn_test.go index feef2dc..fae2a02 100644 --- a/sdl_private_fn_test.go +++ b/sdl_private_fn_test.go @@ -35,3 +35,11 @@ func NewSdlInstanceForTest(NameSpace string, instance iDatabase) *SdlInstance { storage: newSyncStorage(db), } } + +// NewSyncStorageForTest is used only in unit tests to mock database. +func NewSyncStorageForTest(dbMock iDatabase) *SyncStorage { + db := &Database{} + db.instances = append(db.instances, dbMock) + + return newSyncStorage(db) +} diff --git a/syncstorage.go b/syncstorage.go index f2f708e..850213a 100644 --- a/syncstorage.go +++ b/syncstorage.go @@ -435,6 +435,34 @@ func (s *SyncStorage) GetAll(ns string) ([]string, error) { return retVal, err } +// ListKeys returns all keys in the given namespace matching key search pattern. +// +// Supported search glob-style patterns: +// h?llo matches hello, hallo and hxllo +// h*llo matches hllo and heeeello +// h[ae]llo matches hello and hallo, but not hillo +// h[^e]llo matches hallo, hbllo, ... but not hello +// h[a-b]llo matches hallo and hbllo +// +// The \ escapes character in key search pattern and those will be treated as a normal +// character: +// h\[?llo\* matches h[ello* and h[allo* +// +// No prior knowledge about the keys in the given namespace exists, +// thus operation is not guaranteed to be atomic or isolated. +func (s *SyncStorage) ListKeys(ns string, pattern string) ([]string, error) { + nsPrefix := getNsPrefix(ns) + nsKeys, err := s.getDbBackend(ns).Keys(nsPrefix + pattern) + var keys []string + if err != nil { + return keys, err + } + for _, key := range nsKeys { + keys = append(keys, strings.Split(key, nsPrefix)[1]) + } + return keys, err +} + //RemoveAll removes all keys under the namespace. Remove operation is not atomic, thus //it is not guaranteed that all keys are removed. func (s *SyncStorage) RemoveAll(ns string) error { diff --git a/syncstorage_test.go b/syncstorage_test.go new file mode 100644 index 0000000..467275b --- /dev/null +++ b/syncstorage_test.go @@ -0,0 +1,81 @@ +/* + Copyright (c) 2021 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. + + This source code is part of the near-RT RIC (RAN Intelligent Controller) + platform project (RICP). +*/ +package sdlgo_test + +import ( + "errors" + "testing" + + "gerrit.o-ran-sc.org/r/ric-plt/sdlgo" + "github.com/stretchr/testify/assert" +) + +func setupSDL() (*mockDB, *sdlgo.SyncStorage) { + dbMock := new(mockDB) + sdl := sdlgo.NewSyncStorageForTest(dbMock) + return dbMock, sdl +} + +func TestListKeys(t *testing.T) { + dbMock, sdl := setupSDL() + + tests := []struct { + keysPatternMockDB string + keysReturnValueMockDB []string + keysPattern string + expected []string + }{ + {"{ns1},*", []string{"{ns1},key1", "{ns1},key2"}, "*", []string{"key1", "key2"}}, + {"{ns1},ke*", []string{"{ns1},key1", "{ns1},key2"}, "ke*", []string{"key1", "key2"}}, + {"{ns1},ke?2", []string{"{ns1},key2"}, "ke?2", []string{"key2"}}, + } + + for _, test := range tests { + dbMock.On("Keys", test.keysPatternMockDB).Return(test.keysReturnValueMockDB, nil) + + keys, err := sdl.ListKeys("ns1", test.keysPattern) + assert.Nil(t, err) + assert.Equal(t, test.expected, keys) + dbMock.AssertExpectations(t) + } +} + +func TestListKeysEmpty(t *testing.T) { + dbMock, sdl := setupSDL() + + dbMock.On("Keys", "{ns1},").Return([]string{}, nil) + + keys, err := sdl.ListKeys("ns1", "") + assert.Nil(t, err) + assert.Nil(t, keys) + dbMock.AssertExpectations(t) +} + +func TestListKeysError(t *testing.T) { + dbMock, sdl := setupSDL() + + errorStringMockDB := string("(empty list or set)") + dbMock.On("Keys", "{ns1},").Return([]string{}, errors.New(errorStringMockDB)) + + keys, err := sdl.ListKeys("ns1", "") + assert.NotNil(t, err) + assert.EqualError(t, err, errorStringMockDB) + assert.Nil(t, keys) + dbMock.AssertExpectations(t) +} -- 2.16.6