Bake’s client interface
A simple client example
The following code shows how to use the Bake client library to access a target on a remote Bake provider.
#include <assert.h>
#include <stdio.h>
#include <margo.h>
#include <bake-client.h>
int main(int argc, char** argv)
{
int ret;
margo_instance_id mid = margo_init("na+sm", MARGO_CLIENT_MODE, 0, 0);
assert(mid);
assert(argc == 2 || argc == 3);
const char* server_addr_str = argv[1];
const char* target_id_str = argc == 3 ? argv[2] : NULL;
hg_addr_t server_address;
hg_return_t hret = margo_addr_lookup(mid, server_addr_str, &server_address);
assert(hret == HG_SUCCESS);
bake_client_t client;
ret = bake_client_init(mid, &client);
assert(ret == 0);
bake_provider_handle_t ph;
ret = bake_provider_handle_create(client, server_address, 42, &ph);
assert(ret == 0);
bake_target_id_t tid;
if(target_id_str) {
ret = bake_target_id_from_string(target_id_str, &tid);
assert(ret == 0);
} else {
uint64_t num_targets;
ret = bake_probe(ph, 1, &tid, &num_targets);
assert(ret == 0);
assert(num_targets == 1);
}
bake_region_id_t rid;
ret = bake_create(ph, tid, 10, &rid);
assert(ret == 0);
char in_buffer[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
ret = bake_write(ph, tid, rid, 0, in_buffer, 10);
assert(ret == 0);
ret = bake_persist(ph, tid, rid, 0, 10);
assert(ret == 0);
char out_buffer[10];
uint64_t bytes_read;
ret = bake_read(ph, tid, rid, 0, out_buffer, 10, &bytes_read);
assert(ret == 0);
assert(memcmp(in_buffer, out_buffer, 10) == 0);
ret = bake_provider_handle_release(ph);
assert(ret == 0);
ret = bake_client_finalize(client);
assert(ret == 0);
hret = margo_addr_free(mid, server_address);
assert(hret == HG_SUCCESS);
margo_finalize(mid);
return 0;
}
The bake_client_init
function is used to create a bake_client
object. This client object is required to then create provider handles using
bake_provider_handle_create
.
In this example, the target ID is either passed as the program’s second argument,
in which case bake_target_id_from_string
is used to decode it into a
bake_target_id_t
object, or it is queried from the provider using the
bake_probe
function. This function takes the provider handle, the maximum
number of targets to list, a pointer to an array of target IDs (here just one target),
and a pointer to store the returned numbed of targets.
The bake_create
function is used to create a region of 10 bytes in the target.
It returns a bake_region_id_t
identifying this region. This region ID can be
used to write into the region using bake_write
, or to read from it using
bake_read
. Note that in our example, we write and read the full 10 bytes of
the region, starting from offset 0, but this is not a requirement. These operations
may access any part of the region using different offsets and sizes.
Important
Unless Bake was built with the +sizecheck
option, read and write operations
will not check that the provided offset and size fall within the requested region.
This can lead to corruption of the target if the region is accessed outside of its
bounds.
bake_write
does not guarantee that the written data is persistent on the
target (e.g., should the service crash after the write, the data may not be there
upon restarting the service). To ensure persistence or a given segment within a
given region, one has to call bake_persist
.
Note
Creating a new region, writing the entirety of its content, and persisting it,
is a very common pattern. Hence Bake provides the bake_create_write_persist
function for this purpose.
Other client functions
The Bake client library provides a number of other functions that may be useful.
On provider handles:
bake_provider_handle_ref_incr
can be used to increase the internal reference count of the provider handle.bake_provider_handle_get_info
retrieves the provider handle’s internal information (client, address, and provider id).bake_provider_handle_get/set_eager_limit
access the provider handle’s “eager limit”. This value is the number of bytes under which the client will send data using RPC arguments instead of RDMA transfer.
On regions:
bake_get_size
gets the size of a given region.bake_get_data
can be used if the caller is in the same process as the target bake provider, to obtain a direct pointer to the region’s data. Using this function is however not recommended since it strongly couples the client code with the server code (forcing them to live in the same process space).bake_remove
can be used to remove a region. Note that not all backends support removing a region.bake_proxy_write
andbake_create_write_persist_proxy
are versions ofbake_write
andbake_create_write_persist
that take a bulk handle, a remote address (as a string) and an offset, as the source of the data to be written into the region. These functions are useful in two scenarios: (1) when the data comes from another process and the calling process is only forwarding a bulk handle to the Bake server; (2) if the program needs to send data that is not contiguous in memory, by creating a bulk handle for it manually.bake_proxy_read
can similarly be used to read the content of a region into a bulk handle instead of a buffer.