-Werror \
-Wextra \
-Wno-missing-field-initializers \
+ -Wno-error=deprecated-declarations \
-I$(top_srcdir)/include \
-I$(builddir)/include \
-DSDL_CONF_DIR='"@SDL_CONF_DIR@"' \
# Change the numbers just before release.
m4_define([SDL_MAJOR], [1])
-m4_define([SDL_MINOR], [4])
+m4_define([SDL_MINOR], [5])
m4_define([SDL_MICRO], [0])
# SDL ABI version with libtool
#
# Change the numbers just before release.
-m4_define([SDL_CURRENT], [4])
-m4_define([SDL_REVISION], [11])
+m4_define([SDL_CURRENT], [5])
+m4_define([SDL_REVISION], [12])
m4_define([SDL_AGE], [0])
AC_INIT([shareddatalayer], [SDL_MAJOR.SDL_MINOR.SDL_MICRO], [], [], [https://gerrit.o-ran-sc.org/r/admin/repos/ric-plt/sdl])
+sdl (1.5.0-1) UNRELEASED; urgency=low
+
+ * New listKeys API to support glob-style search pattern
+ * Deprecated old findKeys and findKeysAsync API
+
+ -- Petri Ovaska <petri.ovaska@nokia.com> Fri, 17 Sep 2021 11:54:21 +0300
+
sdl (1.4.0-1) UNRELEASED; urgency=low
* Add synchronous readiness check API
Version history
---------------
+[1.5.0] - 2021-09-17
+
+* New listKeys API to support glob-style search pattern
+* Deprecated old findKeys and findKeysAsync API
+
[1.4.0] - 2021-08-11
* Add synchronous readiness check API
void findKeysAsync(const Namespace& ns, const std::string& keyPrefix, const FindKeysAck& findKeysAck) override;
+ void listKeys(const Namespace& ns, const std::string& pattern, const FindKeysAck& findKeysAck) override;
+
void removeAllAsync(const Namespace& ns, const ModifyAck& modifyAck) override;
private:
void findKeysAsync(const Namespace& ns, const std::string& keyPrefix, const FindKeysAck& findKeysAck) override;
+ void listKeys(const Namespace& ns, const std::string& pattern, const FindKeysAck& findKeysAck) override;
+
void removeAllAsync(const Namespace& ns, const ModifyAck& modifyAck) override;
//public for UT
void findKeysAsync(const Namespace& ns, const std::string& keyPrefix, const FindKeysAck& findKeysAck) override;
+ void listKeys(const Namespace& ns, const std::string& pattern, const FindKeysAck& findKeysAck) override;
+
void removeAllAsync(const Namespace& ns, const ModifyAck& modifyAck) override;
redis::DatabaseInfo& getDatabaseInfo();
std::string buildKeyPrefixSearchPattern(const Namespace& ns, const std::string& keyPrefix) const;
+ std::string buildNamespaceKeySearchPattern(const Namespace& ns, const std::string& pattern) const;
+
private:
std::shared_ptr<Engine> engine;
std::shared_ptr<redis::AsyncCommandDispatcher> dispatcher;
void modificationCommandCallback(const std::error_code& error, const redis::Reply&, const ModifyAck&);
void conditionalCommandCallback(const std::error_code& error, const redis::Reply&, const ModifyIfAck&);
+
+ void findKeys(const std::string& ns, const std::string& keyPattern, const FindKeysAck& findKeysAck);
};
AsyncRedisStorage::ErrorCode& operator++ (AsyncRedisStorage::ErrorCode& ecEnum);
virtual Keys findKeys(const Namespace& ns, const std::string& keyPrefix) override;
+ virtual Keys listKeys(const Namespace& ns, const std::string& pattern) override;
+
virtual void removeAll(const Namespace& ns) override;
virtual void setOperationTimeout(const std::chrono::steady_clock::duration& timeout) override;
MOCK_METHOD3(findKeysAsync, void(const Namespace& ns, const std::string& keyPrefix, const FindKeysAck& findKeysAck));
+ MOCK_METHOD3(listKeys, void(const Namespace& ns, const std::string& pattern, const FindKeysAck& findKeysAck));
+
MOCK_METHOD2(removeAllAsync, void(const Namespace& ns, const ModifyAck& modifyAck));
MOCK_METHOD2(waitReadyAsync, void(const Namespace& ns, const ReadyAck& readyAck));
* @param findKeysAck The acknowledgement to be called once the request has been handled.
* The given function is called in the context of handleEvents() function.
*/
+ [[deprecated("Use listKeys() instead.")]]
virtual void findKeysAsync(const Namespace& ns,
const std::string& keyPrefix,
const FindKeysAck& findKeysAck) = 0;
+ /**
+ * List all keys matching search glob-style pattern under the namespace.
+ *
+ * Supported 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(s) in key search pattern and those will be treated as a normal
+ * character(s):
+ * h\[?llo\* matches h[ello* and h[allo*
+ *
+ * @param ns Namespace under which this operation is targeted.
+ * @param pattern Find keys matching a given glob-style pattern.
+ * @param findKeysAck The acknowledgement to be called once the request has been handled.
+ * The given function is called in the context of handleEvents() function.
+ */
+ virtual void listKeys(const Namespace& ns,
+ const std::string& pattern,
+ const FindKeysAck& findKeysAck) = 0;
+
/**
* Remove all keys under the namespace. Found keys are removed atomically, i.e.
* either all succeeds or all fails.
* @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
* @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
*/
+ [[deprecated("Use listKeys() instead.")]]
virtual Keys findKeys(const Namespace& ns,
const std::string& keyPrefix) = 0;
+ /**
+ * List all keys matching search glob-style pattern under the namespace.
+ *
+ * Supported 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(s) in key search pattern and those will be treated as a normal
+ * character(s):
+ * h\[?llo\* matches h[ello* and h[allo*
+ *
+ * @param ns Namespace under which this operation is targeted.
+ * @param pattern Find keys matching a given glob-style pattern.
+ *
+ * @return Found keys.
+ *
+ * @throw BackendError if the backend data storage fails to process the request.
+ * @throw NotConnected if shareddatalayer is not connected to the backend data storage.
+ * @throw OperationInterrupted if shareddatalayer does not receive a reply from the backend data storage.
+ * @throw InvalidNamespace if given namespace does not meet the namespace format restrictions.
+ */
+ virtual Keys listKeys(const Namespace& ns,
+ const std::string& pattern) = 0;
+
/**
* Remove all keys under the namespace. Found keys are removed atomically, i.e.
* either all succeeds or all fails.
virtual void findKeysAsync(const Namespace&, const std::string&, const FindKeysAck&) override { logAndAbort(__PRETTY_FUNCTION__); }
+ virtual void listKeys(const Namespace&, const std::string&, const FindKeysAck&) override { logAndAbort(__PRETTY_FUNCTION__); }
+
virtual void removeAllAsync(const Namespace&, const ModifyAck&) override { logAndAbort(__PRETTY_FUNCTION__); }
private:
virtual Keys findKeys(const Namespace&, const std::string&) override { logAndAbort(__PRETTY_FUNCTION__); }
+ virtual Keys listKeys(const Namespace&, const std::string&) override { logAndAbort(__PRETTY_FUNCTION__); }
+
virtual void removeAll(const Namespace&) override { logAndAbort(__PRETTY_FUNCTION__); }
virtual void setOperationTimeout(const std::chrono::steady_clock::duration&) override { logAndAbort(__PRETTY_FUNCTION__); }
Name: sdl
-Version: 1.4.0
+Version: 1.5.0
Release: 1%{?dist}
Summary: C++ API library for Shared Data Layer clients
%{_includedir}/sdl
%changelog
+* Fri Sep 17 2021 Petri Ovaska <petri.ovaska@nokia.com> - 1.5.0-1
+- New listKeys API to support glob-style search pattern
+- Deprecated old findKeys and findKeysAsync API
+
* Thu Aug 11 2021 Timo Tietavainen <timo.tietavainen@nokia.com> - 1.4.0-1
- Add synchronous readiness check API
postCallback(std::bind(findKeysAck, std::error_code(), Keys()));
}
+void AsyncDummyStorage::listKeys(const Namespace&, const std::string&, const FindKeysAck& findKeysAck)
+{
+ postCallback(std::bind(findKeysAck, std::error_code(), Keys()));
+}
+
void AsyncDummyStorage::removeAllAsync(const Namespace&, const ModifyAck& modifyAck)
{
postCallback(std::bind(modifyAck, std::error_code()));
getOperationHandler(ns).findKeysAsync(ns, keyPrefix, findKeysAck);
}
+void AsyncStorageImpl::listKeys(const Namespace& ns,
+ const std::string& pattern,
+ const FindKeysAck& findKeysAck)
+{
+ getOperationHandler(ns).listKeys(ns, pattern, findKeysAck);
+}
+
void AsyncStorageImpl::removeAllAsync(const Namespace& ns,
const ModifyAck& modifyAck)
{
contentsBuilder->build("DEL", ns, keys));
}
-void AsyncRedisStorage::findKeysAsync(const Namespace& ns,
- const std::string& keyPrefix,
- const FindKeysAck& findKeysAck)
+void AsyncRedisStorage::findKeys(const Namespace& ns,
+ const std::string& keyPattern,
+ const FindKeysAck& findKeysAck)
{
//TODO: update to more optimal solution than current KEYS-based one.
std::error_code ec;
findKeysAck(std::error_code(), getKeys(*reply.getArray()));
},
ns,
- contentsBuilder->build("KEYS", buildKeyPrefixSearchPattern(ns, keyPrefix)));
+ contentsBuilder->build("KEYS", keyPattern));
+}
+
+void AsyncRedisStorage::findKeysAsync(const Namespace& ns,
+ const std::string& keyPrefix,
+ const FindKeysAck& findKeysAck)
+{
+ auto keyPattern(buildKeyPrefixSearchPattern(ns, keyPrefix));
+ findKeys(ns, keyPattern, findKeysAck);
+}
+
+void AsyncRedisStorage::listKeys(const Namespace& ns,
+ const std::string& pattern,
+ const FindKeysAck& findKeysAck)
+{
+ auto keyPattern(buildNamespaceKeySearchPattern(ns, pattern));
+ findKeys(ns, keyPattern, findKeysAck);
}
void AsyncRedisStorage::removeAllAsync(const Namespace& ns,
oss << '{' << ns << '}' << SEPARATOR << escapedKeyPrefix << "*";
return oss.str();
}
+
+std::string AsyncRedisStorage::buildNamespaceKeySearchPattern(const Namespace& ns,
+ const std::string& pattern) const
+{
+ std::ostringstream oss;
+ oss << '{' << ns << '}' << SEPARATOR << pattern;
+ return oss.str();
+}
return localKeys;
}
+SyncStorageImpl::Keys SyncStorageImpl::listKeys(const Namespace& ns, const std::string& pattern)
+{
+ handlePendingEvents();
+ waitSdlToBeReady(ns);
+ synced = false;
+ asyncStorage->listKeys(ns,
+ pattern,
+ std::bind(&shareddatalayer::SyncStorageImpl::findKeysAck,
+ this,
+ std::placeholders::_1,
+ std::placeholders::_2));
+ waitForOperationCallback();
+ verifyBackendResponse();
+ return localKeys;
+}
+
void SyncStorageImpl::removeAll(const Namespace& ns)
{
handlePendingEvents();
savedCommandCb(getWellKnownErrorCode(), replyMock);
}
+TEST_F(AsyncRedisStorageTest, ListKeysPatternSuccessfullyAndErrorIsTranslated)
+{
+ InSequence dummy;
+ expectContentsBuild("KEYS", "{tag1},key[12]");
+ expectDispatchAsync();
+ sdlStorage->listKeys(ns,
+ "key[12]",
+ std::bind(&AsyncRedisStorageTest::findKeysAck,
+ this,
+ std::placeholders::_1,
+ std::placeholders::_2));
+ expectGetArray();
+ auto expectedDataItem1(Reply::DataItem { key1, ReplyStringLength(key1.size()) });
+ auto expectedDataItem2(Reply::DataItem { key2, ReplyStringLength(key2.size()) });
+ expectGetDataString(expectedDataItem1);
+ expectGetType(Reply::Type::NIL);
+ expectGetDataString(expectedDataItem2);
+ expectFindKeysAck(std::error_code(), { key1, key2 });
+ savedCommandCb(std::error_code(), replyMock);
+ expectFindKeysAck(getWellKnownErrorCode(), { });
+ savedCommandCb(getWellKnownErrorCode(), replyMock);
+}
+
TEST_F(AsyncRedisStorageTest, RemoveAllAsyncSuccessfully)
{
InSequence dummy;
ASSERT_STREQ(expectedKeyPrefixSearchPattern.c_str(), builtKeyPrefixSearchPattern.c_str());
}
+TEST_F(AsyncRedisStorageTest, BuildNamespaceKeySearchPatternIsCorrect)
+{
+ InSequence dummy;
+ const std::string nsPrefix = '{' + ns + '}' + AsyncStorage::SEPARATOR;
+ std::string buildPattern;
+ std::string expectedPattern;
+
+ expectedPattern = nsPrefix;
+ buildPattern = sdlStorage->buildNamespaceKeySearchPattern(ns, "");
+ ASSERT_STREQ(expectedPattern.c_str(), buildPattern.c_str());
+
+ expectedPattern = nsPrefix + '*';
+ buildPattern = sdlStorage->buildNamespaceKeySearchPattern(ns, "*");
+ ASSERT_STREQ(expectedPattern.c_str(), buildPattern.c_str());
+
+ expectedPattern = nsPrefix + "h?llo";
+ buildPattern = sdlStorage->buildNamespaceKeySearchPattern(ns, "h?llo");
+ ASSERT_STREQ(expectedPattern.c_str(), buildPattern.c_str());
+}
+
TEST_F(AsyncRedisStorageTestDispatcherNotCreated, ReadyAckNotForwardedIfDispatcherNotYetCreated)
{
InSequence dummy;
.WillOnce(SaveArg<2>(&savedFindKeysAck));
}
+ void expectListKeys()
+ {
+ EXPECT_CALL(*asyncStorageMockRawPtr, listKeys(ns, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<2>(&savedFindKeysAck));
+ }
+
void expectRemoveAsync(const SyncStorage::Keys& keys)
{
EXPECT_CALL(*asyncStorageMockRawPtr, removeAsync(ns, keys, _))
EXPECT_EQ(ids, keys);
}
+TEST_F(SyncStorageImplTest, ListKeysSuccessfully)
+{
+ InSequence dummy;
+ expectSdlReadinessCheck(SyncStorageImpl::NO_TIMEOUT);
+ expectListKeys();
+ expectPollWait(SyncStorageImpl::NO_TIMEOUT);
+ expectFindKeysAck();
+ auto ids(syncStorage->listKeys(ns, "*"));
+ EXPECT_EQ(ids, keys);
+}
+
TEST_F(SyncStorageImplTest, FindKeysWithReadinessTimeoutSuccessfully)
{
InSequence dummy;