In rDSN, both applications and frameworks must implement a base abstract called dsn_app, which are registered into rDSN's service kernel via dsn_register_app.
Here is an example where we register two applications into rDSN; note we use the C++ wrappers atop our C API in this example.
int main(int argc, char** argv)
{
// register all app types
dsn::register_app<test_client>("test");
dsn::register_app<test_server>("server");
// run rDSN
dsn_run(argc, argv, true);
return 0;
}
After the applications and frameworks are registered, developers specify the concrete instances in config files, and rDSN creates them accordingly on start-up.
[apps.client]
arguments = localhost 20101
delay_seconds = 1
pools = THREAD_POOL_DEFAULT
type = test
[apps.server]
pools = THREAD_POOL_TEST_SERVER
ports = 20101
type = server
Developers usually run this using ./app config.ini
, or ./app
for more options.
|
typedef void *(* | dsn_app_create) (const char *app_name, dsn_gpid id) |
|
typedef dsn_error_t(* | dsn_app_start) (void *app, int argc, char **argv) |
|
typedef dsn_error_t(* | dsn_app_destroy) (void *app, bool cleanup) |
|
typedef void(* | dsn_framework_rpc_request_handler) (void *app, dsn_gpid gpid, bool is_write_operation, dsn_message_t request) |
|
typedef void(* | dsn_app_on_batched_write_requests) (void *app, int64_t decree, dsn_message_t *requests, int request_count) |
|
typedef int(* | dsn_app_get_physical_error) (void *app) |
|
typedef dsn_error_t(* | dsn_app_sync_checkpoint) (void *app, int64_t last_decree) |
|
typedef dsn_error_t(* | dsn_app_async_checkpoint) (void *app, int64_t last_decree) |
|
typedef int64_t(* | dsn_app_get_last_checkpoint_decree) (void *app) |
|
typedef dsn_error_t(* | dsn_app_prepare_get_checkpoint) (void *app, void *request_buffer, int capacity, int *used_size) |
|
typedef dsn_error_t(* | dsn_app_get_checkpoint) (void *app, int64_t learn_start_decree, int64_t local_last_decree, void *learn_request, int learn_request_size, dsn_app_learn_state *learn_state_buffer, int capacity) |
|
typedef dsn_error_t(* | dsn_app_apply_checkpoint) (void *app, dsn_chkpt_apply_mode mode, int64_t local_last_decree, const dsn_app_learn_state *learn_state) |
|
typedef dsn_error_t(* | dsn_app_bridge_t) (int, const char **) |
|
typedef union dsn_app_callbacks | dsn_app_callbacks |
|
typedef struct dsn_app | dsn_app |
|
typedef struct dsn_app_info | dsn_app_info |
|
typedef void*(* dsn_app_create) (const char *app_name, dsn_gpid id) |
callback to create the app context
- Parameters
-
app_name | type name registered on dsn_register_app |
id | assigned global partition id |
- Returns
- the app context used by other APIs to reference this application instance
typedef dsn_error_t(* dsn_app_start) (void *app, int argc, char **argv) |
callback to run the app with the app context, similar to main(argc, argv)
- Parameters
-
app | context returned by dsn_app_create |
argc | as in traditional main(argc, argv) |
argv | as in traditional main(argc, argv) |
- Returns
- error code for app start
typedef dsn_error_t(* dsn_app_destroy) (void *app, bool cleanup) |
callback to stop and destroy the app
- Parameters
-
app | context returned by dsn_app_create |
cleanup | whether to cleanup the state belonging to this app |
- Returns
- error code for app destroy
typedef void(* dsn_framework_rpc_request_handler) (void *app, dsn_gpid gpid, bool is_write_operation, dsn_message_t request) |
callback for framework to handle incoming rpc request, implemented by frameworks
- Parameters
-
app | context returned by dsn_app_create |
gpid | global partition id |
is_write_operation | whether the incoming rpc reqeust is a write operation or not |
request | incoming rpc request message |
typedef void(* dsn_app_on_batched_write_requests) (void *app, int64_t decree, dsn_message_t *requests, int request_count) |
batched rpc request from frameworks, used by frameworks, implemented by apps
- Parameters
-
app | context returned by dsn_app_create |
decree | sequence number for this request batch (when request batches are sent to the apps in order) |
requests | incoming rpc request array ptr |
request_count | request count in this array |
typedef int(* dsn_app_get_physical_error) (void *app) |
get physical error (e.g., disk failure) from the app, used by frameworks, implemented by apps
- Parameters
-
app | context returned by dsn_app_create |
- Returns
- physical error code, e.g., disk failure, that is not always reproducible on another machine with the same input
typedef dsn_error_t(* dsn_app_sync_checkpoint) (void *app, int64_t last_decree) |
checkpoint the application synchronously, used by frameworks, implemented by apps
- Parameters
-
app | context returned by dsn_app_create |
last_decree | decree of the last request/request-batch applied to this app |
- Returns
- error code for the checkpoint operation
typedef dsn_error_t(* dsn_app_async_checkpoint) (void *app, int64_t last_decree) |
checkpoint the application asynchronously, used by frameworks, implemented by apps
- Parameters
-
app | context returned by dsn_app_create |
last_decree | decree of the last request/request-batch applied to this app |
- Returns
- error code for the checkpoint operation
typedef int64_t(* dsn_app_get_last_checkpoint_decree) (void *app) |
get the decree of last done checkpoint, used by frameworks, implemented by apps
- Parameters
-
app | context returned by dsn_app_create |
- Returns
- decree of the last successfully done checkpoint (see last_decree parameter when doing checkpoint)
typedef dsn_error_t(* dsn_app_prepare_get_checkpoint) (void *app, void *request_buffer, int capacity, int *used_size) |
learner prepares a get checkpoint request for better fitting the local state (e.g., for delta learning), the request will be used by dsn_app_get_checkpoint below, used by frameworks, implemented by apps
- Parameters
-
app | context returned by dsn_app_create |
request_buffer | a memory buffer to be filled with a custom learn request |
capcity | buffer size, in bytes |
used_size | this is the output value telling how many bytes are written by this custom learn request |
- Returns
- error code for this operation
typedef dsn_error_t(* dsn_app_get_checkpoint) (void *app, int64_t learn_start_decree, int64_t local_last_decree, void *learn_request, int learn_request_size, dsn_app_learn_state *learn_state_buffer, int capacity) |
get checkpoint information from learnee, used by frameworks, implemented by apps
can be used for both delta checkpoint [learn_start_decree, infinite), or full checkpoint.
- Parameters
-
app | context returned by dsn_app_create |
learn_start_decree | the first start decree we want to get for this (if delta) checkpoint |
local_last_decree | decree of the last request/request-batched that are applied locally |
learn_request | learn reqeust as prepared by dsn_app_prepare_get_checkpoint above |
learn_request_size | buffer size (in bytes) of the learn request |
learn_state_buffer | output learn state, see dsn_app_learn_state, to be used by dsn_app_apply_checkpoint below |
capacity | output learn state buffer size (in bytes) |
- Returns
- error code for this operation
apply checkpoint from remote nodes, used by frameworks, implemented by apps
- Parameters
-
- Returns
- error code for this operation
developers define the following dsn_app data structure, and passes it to rDSN through dsn_register_app so that the latter can manage the app appropriately.
Click into the corresponding types for what are the callback means.
checkpoint apply mode, see dsn_app_apply_checkpoint, used by frameworks
Enumerator |
---|
DSN_CHKPT_COPY |
simply a checkpoint from remote machine is given, do not change the local state
|
DSN_CHKPT_LEARN |
given a checkpoint from remote machine, prepare to change the local state
|
DSN_API bool dsn_register_app |
( |
dsn_app * |
app_type | ) |
|
register application/framework into rDSN runtime
- Parameters
-
app_type | requried app type information. |
- Returns
- true if it succeeds, false if it fails.
An example is as follows:
dsn_app app;
memset(&app, 0, sizeof(app));
app.mask = DSN_APP_MASK_APP;
strncpy(app.type_name, type_name, sizeof(app.type_name));
app.layer1.create = service_app::app_create<TServiceApp>;
app.layer1.start = service_app::app_start;
app.layer1.destroy = service_app::app_destroy;
dsn_register_app(&app);
DSN_API bool dsn_get_app_callbacks |
( |
const char * |
name, |
|
|
dsn_app_callbacks * |
callbacks |
|
) |
| |
get application callbacks registered into rDSN runtime
- Parameters
-
name | app type name |
callbacks | output callbacks |
- Returns
- true it it exists, false otherwise
DSN_API bool dsn_mimic_app |
( |
const char * |
app_name, |
|
|
int |
index |
|
) |
| |
mimic an app as if the following execution in the current thread are executed in the target app's threads.
- Parameters
-
app_name | name of the application, note it is not the type name |
index | one-based index of the application instances |
- Returns
- true if it succeeds, false if it fails.
This is useful when we want to leverage 3rd party library into rDSN application and call rDSN service API in the threads that are created by the 3rd party code.
For cases we simply want to use a rDSN-based client library in a non-rDSN application, developers can simply set [core] enable_default_app_mimic = true in configuration file. See more details at enable_default_app_mimic.
- Parameters
-
app_name | specified in config file as [apps.${app_name}] |
index | start from 1, when there are multiple instances |
DSN_API bool dsn_run_config |
( |
const char * |
config, |
|
|
bool sleep_after_init |
DEFAULTfalse |
|
) |
| |
start the system with given configuration
- Parameters
-
config | the configuration file for this run |
sleep_after_init | whether to sleep after rDSN initialization, default is false |
- Returns
- true if it succeeds, false if it fails.
DSN_API void dsn_run |
( |
int |
argc, |
|
|
char ** |
argv, |
|
|
bool sleep_after_init |
DEFAULTfalse |
|
) |
| |
start the system with given arguments
- Parameters
-
argc | argc in C main convention |
argv | argv in C main convention |
sleep_after_init | whether to sleep after rDSN initialization, default is false |
- Returns
- true if it succeeds, false if it fails.
Usage: config-file [-cargs k1=v1;k2=v2] [-app_list app_name1;app_name2]
Examples:
- config.ini -app_list replica@1 to start the first replica as a new process
- config.ini -app_list replica to start ALL replicas (count specified in config) as a new process
- config.ini -app_list replica -cargs replica-port=34556 to start ALL replicas with given port variable specified in config.ini
- config.ini to start ALL apps as a new process
Note the argc, argv folllows the C main convention that argv[0] is the executable name.
NORETURN DSN_API void dsn_exit |
( |
int |
code | ) |
|
exit the process with the given exit code
- Parameters
-
code | exit code for the process |
rDSN runtime does not provide elegant exit routines. Thereafter, developers call dsn_exit to exit the current process to avoid exceptions happending during normal exit.
DSN_API int dsn_get_all_apps |
( |
dsn_app_info * |
info_buffer, |
|
|
int |
count |
|
) |
| |
get rDSN application (instance)s information in the current process
- Parameters
-
info_buffer | buffer for storing information data. |
count | capacity of the buffer |
- Returns
- how many rDSN application( instance)s are running in the current processs.
The returned value may be larger than count - in this casse, developers need to allocate a new buffer that is enough to hold the information of returned number of applications.
DSN_API bool dsn_get_current_app_info |
( |
dsn_app_info * |
app_info | ) |
|
get current rDSN application information.
- Parameters
-
app_info | buffer for storing information data. |
- Returns
- true if it succeeds, false if the current thread does not belong to any rDSN app.
DSN_API const char* dsn_get_app_data_dir |
( |
dsn_gpid gpid |
DEFAULTdsn_gpid{0} | ) |
|
get current application data dir.
- Returns
- null if it fails, else a pointer to the data path string.
DSN_API void dsn_app_loader_signal |
( |
| ) |
|
signal the application loader that application types are registered.
in rDSN, app types must be registered via dsn_app_register. before dsn_run is invoked. in certain cases, a synchonization is needed to ensure this order. for example, we want to register an app role in python while the main program is in C++ to call dsn_run. in this case, we need to do as follows (in C++)
new thread([]{
[ python program
dsn_app_register(...)
dsn_app_loader_signal()
]
});
dsn_app_loader_wait();
dsn_run(...)
].
DSN_API void dsn_app_loader_wait |
( |
| ) |
|