Bootstrap method: view

The “view” bootstrap method allows you to initialize a Flock group from a pre-constructed group view. This is useful when you have a known set of members that have coordinated between themselves ahead of initializing flock, and want to initialize their flock provider with the same view of the group.

When to use

Use the “view” bootstrap method when:

  • You have a predetermined list of group members, and you already know their address

  • You want to programmatically construct a group view

  • You’re initializing multiple processes with a shared view

  • You need fine-grained control over the initial group membership

Configuration

In a Bedrock configuration, you can’t directly specify the view bootstrap method because views must be constructed programmatically.

In C code

To use the view bootstrap method programmatically, you can load a view from a file: Bootstrapping from a view assumes that you have a way of creating a consistent view across members beforehand. Here is an example where such a view is provided in a JSON file, read using flock_group_view_init_from_file.

/*
 * (C) 2024 The University of Chicago
 *
 * See COPYRIGHT in top-level directory.
 */
#include <assert.h>
#include <stdio.h>
#include <margo.h>
#include <flock/flock-server.h>
#include <flock/flock-bootstrap.h>

int main(int argc, char** argv)
{
    if(argc != 2) {
        fprintf(stderr, "Usage: %s <view_file>\n", argv[0]);
        return -1;
    }

    const char* view_file = argv[1];

    // Initialize Margo
    margo_instance_id mid = margo_init("na+sm", MARGO_SERVER_MODE, 0, 0);
    assert(mid);

    // Initialize provider args
    struct flock_provider_args args = FLOCK_PROVIDER_ARGS_INIT;
    flock_group_view_t initial_view = FLOCK_GROUP_VIEW_INITIALIZER;
    args.initial_view = &initial_view;

    // Bootstrap from view file
    uint16_t provider_id = 42;
    int ret = flock_group_view_init_from_file(view_file, &initial_view);
    if(ret != FLOCK_SUCCESS) {
        fprintf(stderr, "Failed to initialize view from file: %s\n", view_file);
        margo_finalize(mid);
        return -1;
    }

    printf("Bootstrapped group from view file: %s\n", view_file);
    printf("Group size: %zu\n", initial_view.members.size);

    // Print all members
    for(size_t i = 0; i < initial_view.members.size; i++) {
        printf("  Member %zu: %s (provider_id=%u)\n",
               i,
               initial_view.members.data[i].address,
               initial_view.members.data[i].provider_id);
    }

    // Configure with static backend
    const char* config = "{ \"group\":{ \"type\":\"static\", \"config\":{} } }";

    // Register provider
    flock_provider_t provider;
    ret = flock_provider_register(mid, provider_id, config, &args, &provider);
    assert(ret == FLOCK_SUCCESS);

    printf("Flock provider registered\n");

    // Wait for finalize
    margo_wait_for_finalize(mid);

    return 0;
}

Sharing views between processes

Once you have a group view, you can:

  1. Serialize to JSON: Convert the view to JSON format for easy sharing

  2. Write to file: Save the view to a file that other processes can read

  3. Send via RPC: Transmit the view to other processes using Mercury RPC

Other processes can then use the “file” bootstrap method to initialize from this view.

View operations

The group view API provides several operations:

  • flock_group_view_add_member: Add a member to the view

  • flock_group_view_add_metadata: Add metadata key-value pair

  • flock_group_view_serialize: Convert view to JSON string

  • flock_group_view_deserialize: Parse view from JSON string

  • flock_group_view_clear: Free view resources

  • flock_group_view_copy: Create a copy of a view