Skip to content

Commit 89103f2

Browse files
authored
Enable putting bytes into the database via C++ and Python (#521)
This PR adds client API methods in C++ and Python for sending and receiving byte strings from the database. Methods for put, get, unpack, poll, exists, and delete have been implemented. [ committed by @mellis13 ] [ reviewed by @ashao ]
1 parent bc6e9d4 commit 89103f2

File tree

20 files changed

+1195
-72
lines changed

20 files changed

+1195
-72
lines changed

doc/changelog.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,20 @@ To be released at a future time.
66

77
Description
88

9+
- Add Client API functions to put, get, unpack,
10+
delete, poll, and check for existance of raw bytes for the
11+
C++ and Python clients.
12+
- Fix lint issues using make lint
913
- Reenable move semantics and fix compiler warnings.
1014

1115
Detailed Notes
1216

17+
- Add Client API functions to put, get, unpack,
18+
delete, poll, and check for existance of raw bytes for the
19+
C++ and Python clients.
20+
([PR521](https://github.com/CrayLabs/SmartRedis/pull/521))
21+
- Fix lint issues using make lint
22+
([PR522](https://github.com/CrayLabs/SmartRedis/pull/522))
1323
- Fix compiler warnings stemming from override and const
1424
keywords as well as move semantics impliclty disabled
1525
because of std::random_device.
@@ -21,14 +31,11 @@ Released on 27 September, 2024
2131

2232
Description
2333

24-
- Fix lint issues using make lint
2534
- Fix RedisAI build to allow for compilation with GCC-14
2635
- Fix a memory leak in the Fortran Dataset implementation
2736

2837
Detailed Notes
2938

30-
- Fix lint issues using make lint
31-
([PR522](https://github.com/CrayLabs/SmartRedis/pull/522))
3239
- Fix RedisAI build to allow for compilation with GCC-14. Also,
3340
we only use the Torch backend and change the compilation of
3441
RedisAI to use CMake (like SmartSim)

examples/serial/cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ list(APPEND EXECUTABLES
5050
smartredis_dataset
5151
smartredis_model
5252
smartredis_mnist
53+
smartredis_put_get_bytes
5354
)
5455

5556
# Build the examples
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* BSD 2-Clause License
3+
*
4+
* Copyright (c) 2021-2024, Hewlett Packard Enterprise
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this
11+
* list of conditions and the following disclaimer.
12+
*
13+
* 2. Redistributions in binary form must reproduce the above copyright notice,
14+
* this list of conditions and the following disclaimer in the documentation
15+
* and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
*/
28+
29+
#include "client.h"
30+
#include <vector>
31+
#include <string>
32+
33+
int main(int argc, char* argv[]) {
34+
35+
// Initialize some byte data
36+
size_t n_bytes = 255;
37+
std::vector<char> input_bytes(n_bytes);
38+
for(size_t i = 0; i < n_bytes; i++) {
39+
input_bytes[i] = i;
40+
}
41+
42+
SmartRedis::Client client("client_test_put_get_bytes");
43+
44+
std::string key = "put_get_bytes_test";
45+
46+
client.put_bytes(key, input_bytes.data(), n_bytes);
47+
48+
std::vector<char> output_bytes(n_bytes, 0);
49+
50+
size_t received_bytes = 0;
51+
client.unpack_bytes(key, output_bytes.data(), n_bytes,
52+
received_bytes);
53+
54+
if (received_bytes != n_bytes) {
55+
std::cout<<"Output byte size "<<received_bytes<<" does not match."<<std::endl;
56+
throw std::exception();
57+
}
58+
59+
for(int i = 0; i < n_bytes; i++) {
60+
if (output_bytes[i] != input_bytes[i]) {
61+
std::cout<<"Byte "<<i<<" does not match."<<std::endl;
62+
throw std::exception();
63+
}
64+
}
65+
66+
std::cout<<"Put bytes test complete"<<std::endl;
67+
68+
return 0;
69+
}

include/client.h

Lines changed: 148 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,77 @@ class Client : public SRObject
223223
const SRTensorType type,
224224
const SRMemoryLayout mem_layout);
225225

226+
/*!
227+
* \brief Puts a byte string into the database
228+
* \details The provided byte string is placed into the database
229+
* without any type associated with the bytes.
230+
* The final key under which the bytes are stored
231+
* may be formed by applying a prefix to the supplied
232+
* name. See use_bytes_ensemble_prefix() for
233+
* more details.
234+
* \param name The name for referencing the bytes in the database
235+
* \param data The data
236+
* \param n_bytes The number of bytes in the provided data
237+
* \throw SmartRedis::Exception if put bytes command fails
238+
*/
239+
void put_bytes(const std::string& name,
240+
const void* bytes,
241+
const size_t n_bytes);
242+
243+
/*!
244+
* \brief Retrieve bytes from the database and place into a new
245+
* memory buffer
246+
* \details The key used to locate the stored bytes
247+
* may be formed by applying a prefix to the supplied
248+
* name. See set_data_source()
249+
* and use_bytes_ensemble_prefix() for more details.
250+
* Unlike other "get" operations in the client, the
251+
* the byte data memeory is allocated but not managed
252+
* by the client. The caller is responsible for invoking
253+
* free() on the returned memory.
254+
* \param name The name for referencing the bytes in the database
255+
* \param data A user-provided pointer that will be modified to
256+
* point to a new block of memory containing the bytes
257+
* \param n_bytes A user-provided size_t variable that will be modified
258+
* to indicate the total number of bytes.
259+
* \throw SmartRedis::Exception if get bytes command fails
260+
*/
261+
void get_bytes(const std::string& name,
262+
void*& data,
263+
size_t& n_bytes);
264+
265+
/*!
266+
* \brief Retrieve bytes from the database and place into memory
267+
* provided by the caller
268+
* \details The key used to locate the stored bytes
269+
* may be formed by applying a prefix to the supplied
270+
* name. See set_data_source()
271+
* and use_bytes_ensemble_prefix() for more details.
272+
* \param name The name for referencing the bytes in the database
273+
* \param data A buffer into which to place byte data
274+
* \param n_bytes The number of bytes in the provided memory block
275+
* \param n_used_bytes The number of bytes in the provided
276+
* buffer that were used
277+
* \throw SmartRedis::Exception if unpack bytes command fails or
278+
* the number of provided bytes is less than the retrieved
279+
* number of bytes
280+
*/
281+
void unpack_bytes(const std::string& name,
282+
void* data,
283+
const size_t n_bytes,
284+
size_t& n_used_bytes);
285+
286+
/*!
287+
* \brief Delete bytes from the database
288+
* \details The key used to locate the bytes to be
289+
* deleted may be formed by applying a prefix to the
290+
* supplied name. See set_data_source()
291+
* and use_bytes_ensemble_prefix() for more details.
292+
* \param name The name of the bytes to delete
293+
* \throw SmartRedis::Exception if delete bytes command fails
294+
*/
295+
void delete_bytes(const std::string& name);
296+
226297
/*!
227298
* \brief Retrieve the tensor data, dimensions, and type for the
228299
* provided tensor key. This function will allocate and retain
@@ -795,18 +866,6 @@ class Client : public SRObject
795866
*/
796867
bool key_exists(const std::string& key);
797868

798-
/*!
799-
* \brief Check if a model (or script) key exists in the database
800-
* \details The model or script key used to check for existence
801-
* may be formed by applying a prefix to the supplied
802-
* name. See set_data_source()
803-
* and use_model_ensemble_prefix() for more details.
804-
* \param name The model/script name to be checked in the database
805-
* \returns Returns true if the model exists in the database
806-
* \throw SmartRedis::Exception if model exists command fails
807-
*/
808-
bool model_exists(const std::string& name);
809-
810869
/*!
811870
* \brief Check if a tensor key exists in the database
812871
* \details The tensor key used to check for existence
@@ -831,6 +890,30 @@ class Client : public SRObject
831890
*/
832891
bool dataset_exists(const std::string& name);
833892

893+
/*!
894+
* \brief Check if a model (or script) key exists in the database
895+
* \details The model or script key used to check for existence
896+
* may be formed by applying a prefix to the supplied
897+
* name. See set_data_source()
898+
* and use_model_ensemble_prefix() for more details.
899+
* \param name The model/script name to be checked in the database
900+
* \returns Returns true if the model exists in the database
901+
* \throw SmartRedis::Exception if model exists command fails
902+
*/
903+
bool model_exists(const std::string& name);
904+
905+
/*!
906+
* \brief Check if bytes exists in the database
907+
* \details The key used to check for existence
908+
* may be formed by applying a prefix to the supplied
909+
* name. See set_data_source()
910+
* and use_bytes_ensemble_prefix() for more details.
911+
* \param name The bytes name to be checked in the database
912+
* \returns Returns true if the bytes exists in the database
913+
* \throw SmartRedis::Exception if bytes exists command fails
914+
*/
915+
bool bytes_exists(const std::string& name);
916+
834917
/*!
835918
* \brief Check if a key exists in the database, repeating the check
836919
* at a specified polling interval
@@ -903,6 +986,25 @@ class Client : public SRObject
903986
int poll_frequency_ms,
904987
int num_tries);
905988

989+
/*!
990+
* \brief Check if bytes exists in the database, repeating
991+
* the check at a specified polling interval
992+
* \details The key used to check for existence
993+
* may be formed by applying a prefix to the supplied
994+
* name. See set_data_source()
995+
* and use_bytes_ensemble_prefix() for more details.
996+
* \param name The bytes name to be checked in the database
997+
* \param poll_frequency_ms The time delay between checks,
998+
* in milliseconds
999+
* \param num_tries The total number of times to check for the name
1000+
* \returns Returns true if the bytes is found within the
1001+
* specified number of tries, otherwise false.
1002+
* \throw SmartRedis::Exception if poll bytes command fails
1003+
*/
1004+
bool poll_bytes(const std::string& name,
1005+
int poll_frequency_ms,
1006+
int num_tries);
1007+
9061008
/*!
9071009
* \brief Set the data source, a key prefix for future operations.
9081010
* \details When running multiple applications, such as an ensemble
@@ -1011,6 +1113,25 @@ class Client : public SRObject
10111113
*/
10121114
void use_list_ensemble_prefix(bool use_prefix);
10131115

1116+
/*!
1117+
* \brief Control whether bytes are prefixed
1118+
* \details This function can be used to avoid key collisions in an
1119+
* ensemble by prepending the string value from the
1120+
* environment variable SSKEYIN and/or SSKEYOUT to
1121+
* raw byte names. Prefixes will only be used if
1122+
* they were previously set through the environment variables
1123+
* SSKEYOUT and SSKEYIN. Keys for raw bytes created
1124+
* before this function is called will not be retroactively
1125+
* prefixed. By default, the client prefixes raw bytes
1126+
* keys with the first prefix specified with the SSKEYIN
1127+
* and SSKEYOUT environment variables.
1128+
* \param use_prefix If set to true, all future operations
1129+
* on raw bytes will use a prefix, if available.
1130+
* \throw SmartRedis::Exception for failed activation of
1131+
* raw byte prefixing
1132+
*/
1133+
void use_bytes_ensemble_prefix(bool use_prefix);
1134+
10141135
/*!
10151136
* \brief Returns information about the given database node
10161137
* \param address The address of the database node (host:port)
@@ -1569,6 +1690,12 @@ class Client : public SRObject
15691690
*/
15701691
bool _use_list_prefix;
15711692

1693+
/*!
1694+
* \brief Flag determining whether prefixes should be used
1695+
* for raw byte keys.
1696+
*/
1697+
bool _use_bytes_prefix;
1698+
15721699
/*!
15731700
* \brief Our configuration options, used to access runtime settings
15741701
*/
@@ -1664,6 +1791,15 @@ class Client : public SRObject
16641791
*/
16651792
inline std::string _build_list_key(const std::string& list_name,
16661793
bool on_db);
1794+
/*!
1795+
* \brief Build full formatted key for bytes, based on
1796+
* current prefix settings.
1797+
* \param name Unprefixed bytes name
1798+
* \param on_db Indicates whether the key refers to an entity
1799+
* which is already in the database.
1800+
*/
1801+
inline std::string _build_bytes_key(const std::string& name,
1802+
bool on_db);
16671803

16681804
/*!
16691805
* \brief Append the Command associated with

0 commit comments

Comments
 (0)