Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions src/btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2966,15 +2966,15 @@ btree_lookup_node_async(btree_lookup_async_state *state, uint64 depth)
state->__async_result = STATUS_OK;
async_await_call(state,
cache_get_async,
&state->cache_get_state,
&state->work.cache_get_state,
state->cc,
state->node.addr,
state->type,
state->callback,
state->callback_arg);
{
platform_status rc = cache_get_async_state_result(&state->cache_get_state,
&state->node.page);
platform_status rc = cache_get_async_state_result(
&state->work.cache_get_state, &state->node.page);
if (!SUCCESS(rc)) {
async_return(state, rc);
}
Expand Down Expand Up @@ -3058,14 +3058,14 @@ btree_lookup_node_async(btree_lookup_async_state *state, uint64 depth)

async_await_call(state,
cache_get_async,
&state->cache_get_state,
&state->work.cache_get_state,
state->cc,
state->child_node.addr,
state->type,
state->callback,
state->callback_arg);
platform_status get_rc = cache_get_async_state_result(
&state->cache_get_state, &state->child_node.page);
&state->work.cache_get_state, &state->child_node.page);
if (!SUCCESS(get_rc)) {
btree_node_unget(state->cc, state->cfg, &state->node);
async_return(state, get_rc);
Expand Down Expand Up @@ -3114,8 +3114,8 @@ btree_lookup_node_async(btree_lookup_async_state *state, uint64 depth)
*
* OUT Parameters:
* - state->node: the node found
* - state->found_key: the key found in the leaf, or NULL_KEY otherwise.
* - state->msg: the message of the target
* - state->work.found_key: the key found in the leaf, or NULL_KEY otherwise.
* - state->work.msg: the message of the target
*
* LOCAL Variables:
* - state->stats: the stats of the node found
Expand All @@ -3136,7 +3136,7 @@ btree_lookup_with_ref_async(btree_lookup_async_state *state, uint64 depth)
async_return(state);
}

state->found_key = NULL_KEY;
state->work.found_key = NULL_KEY;
bool32 found;
int64 idx;
const leaf_entry *entry = NULL;
Expand All @@ -3163,12 +3163,12 @@ btree_lookup_with_ref_async(btree_lookup_async_state *state, uint64 depth)
} else {
entry = btree_get_leaf_entry(state->cfg, state->node.hdr, idx);
}
state->found_key = state->node.hdr->prefix_length == 0
? leaf_entry_key((leaf_entry *)entry)
: key_create(FALSE,
key_length(state->target),
key_data(state->target));
state->msg = leaf_entry_message(state->cc, (leaf_entry *)entry);
state->work.found_key = state->node.hdr->prefix_length == 0
? leaf_entry_key((leaf_entry *)entry)
: key_create(FALSE,
key_length(state->target),
key_data(state->target));
state->work.msg = leaf_entry_message(state->cc, (leaf_entry *)entry);
} else {
btree_node_unget(state->cc, state->cfg, &state->node);
}
Expand Down Expand Up @@ -3300,15 +3300,15 @@ btree_lookup_and_merge(cache *cc, // IN
* - state->target: the key to look up
*
* OUT Parameters:
* - state->found_key: the key found in the leaf, or NULL_KEY otherwise.
* - state->work.found_key: the key found in the leaf, or NULL_KEY otherwise.
*
* LOCAL Variables:
* - state->node: the node found
* - state->stats: the stats of the node found
* - state->stop_at_height: the height to stop at
* - state->h: the height of the current node
* - state->child_node: the child node
* - state->msg: the message of the target
* - state->work.msg: the message of the target
*/
async_status
btree_lookup_and_merge_async(btree_lookup_async_state *state)
Expand All @@ -3328,16 +3328,16 @@ btree_lookup_and_merge_async(btree_lookup_async_state *state)
}

platform_status rc = STATUS_OK;
if (!key_is_null(state->found_key)) {
if (!key_is_null(state->work.found_key)) {
ondisk_ref blob_ref = ONDISK_REF_NULL;
if (message_is_blob(state->msg)) {
if (message_is_blob(state->work.msg)) {
rc = btree_blob_ref_init(
&blob_ref, state->cc, state->cfg, state->root_addr, state->type);
}
if (SUCCESS(rc)) {
rc = lookup_result_update(state->result,
state->found_key,
state->msg,
state->work.found_key,
state->work.msg,
ondisk_ref_is_null(&blob_ref) ? NULL
: &blob_ref);
}
Expand Down
14 changes: 11 additions & 3 deletions src/btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,16 @@ btree_lookup_and_merge(cache *cc,
lookup_result *result,
bool32 *local_found);

/* Traversal has consumed the cache result before the leaf tuple is decoded.
* Keep node ownership outside this union until the tuple has been merged. */
typedef union btree_lookup_scratch {
page_get_async_state_buffer cache_get_state;
struct {
key found_key;
message msg;
};
} btree_lookup_scratch;

// clang-format off
DEFINE_ASYNC_STATE(btree_lookup_async_state, 3,
param, cache *, cc,
Expand All @@ -392,9 +402,7 @@ DEFINE_ASYNC_STATE(btree_lookup_async_state, 3,
local, btree_node, node,
local, btree_node, child_node,
local, uint32, h,
local, key, found_key,
local, message, msg,
local, page_get_async_state_buffer, cache_get_state)
local, btree_lookup_scratch, work)
// clang-format on

static inline void
Expand Down
2 changes: 1 addition & 1 deletion src/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ cache_config_extent_page(const cache_config *cfg, uint64 extent_addr, uint64 i)
return extent_addr + i * cache_config_page_size(cfg);
}

#define PAGE_GET_ASYNC_STATE_BUFFER_SIZE (2048)
#define PAGE_GET_ASYNC_STATE_BUFFER_SIZE (320)
typedef union page_get_async_state_payload {
uint8 bytes[PAGE_GET_ASYNC_STATE_BUFFER_SIZE];
uint64 align_uint64;
Expand Down
132 changes: 69 additions & 63 deletions src/clockcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1257,8 +1257,8 @@ clockcache_try_claim_writeback(clockcache *cc,
}

struct async_io_state {
clockcache *cc;
io_async_state_buffer iostate;
clockcache *cc;
io_async_state_extent_buffer iostate;
};

/* Bounded by the width of the bitvector that tracks the reserve. */
Expand Down Expand Up @@ -1467,13 +1467,14 @@ clockcache_batch_start_writeback(clockcache *cc, uint64 batch, bool32 is_urgent)

async_io_state *state = clockcache_io_state_acquire(cc);

state->cc = cc;
platform_status rc = io_async_state_init(state->iostate,
cc->io,
io_async_pwritev,
first_addr,
clockcache_write_callback,
state);
state->cc = cc;
platform_status rc =
io_async_state_init_extent(state->iostate,
cc->io,
io_async_pwritev,
first_addr,
clockcache_write_callback,
state);
if (!SUCCESS(rc)) {
platform_error_log("clockcache_batch_start_writeback: "
"io_async_state_init failed: %s\n",
Expand Down Expand Up @@ -2512,6 +2513,13 @@ clockcache_get(clockcache *cc,
* Get addr if addr is at entry_number. Returns TRUE if successful.
*/

/* Waiting for another loader and issuing our own read are separate branches.
* An issued read completes this get; it never returns to the waiter arm. */
typedef union clockcache_get_scratch {
io_async_state_page_buffer iostate;
async_waiter wait_node;
} clockcache_get_scratch;

// clang-format off
DEFINE_ASYNC_STATE(clockcache_get_async_state, 3,
param, clockcache *, cc,
Expand All @@ -2525,10 +2533,8 @@ DEFINE_ASYNC_STATE(clockcache_get_async_state, 3,
local, threadid, tid,
local, uint64, entry_number,
local, clockcache_entry *, entry,
local, platform_status, rc,
local, io_async_state_buffer, iostate,
local, uint64, io_start_time,
local, async_waiter, wait_node)
local, clockcache_get_scratch, work)
// clang-format on

_Static_assert(sizeof(clockcache_get_async_state)
Expand Down Expand Up @@ -2581,7 +2587,7 @@ clockcache_get_in_cache_async(clockcache_get_async_state *state, uint64 depth)
!clockcache_test_flag(state->cc, state->entry_number, CC_LOADING),
state,
&state->entry->waiters,
&state->wait_node,
&state->work.wait_node,
state->callback,
state->callback_arg);

Expand Down Expand Up @@ -2623,10 +2629,10 @@ clockcache_get_from_disk_async_callback(void *arg)

// Check whether we are done. If not, this will enqueue us for a future
// callback so we can check again.
if (io_async_run(state->iostate) != ASYNC_STATUS_DONE) {
if (io_async_run(state->work.iostate) != ASYNC_STATUS_DONE) {
return;
}
platform_status rc = io_async_state_get_result(state->iostate);
platform_status rc = io_async_state_get_result(state->work.iostate);
if (!SUCCESS(rc)) {
platform_error_log("clockcache_get_from_disk_async_callback: async read "
"failed for addr %lu, entry %lu: %s\n",
Expand All @@ -2643,6 +2649,8 @@ clockcache_get_from_disk_async(clockcache_get_async_state *state, uint64 depth)
{
async_begin(state, depth);

platform_status rc;

/* A miss must be allocated before it can reserve a cache entry or issue I/O.
* Resident hits inherit allocation validity from their existing mapping.
*/
Expand All @@ -2663,28 +2671,26 @@ clockcache_get_from_disk_async(clockcache_get_async_state *state, uint64 depth)
// The normal idiom for async functions is to just pass the callback to the
// async child, but we pass a wrapper function so that we can always clear
// the CC_LOADING flag, even if our caller abandoned us.
state->rc = io_async_state_init(state->iostate,
state->cc->io,
io_async_preadv,
state->addr,
clockcache_get_from_disk_async_callback,
state);
if (!SUCCESS(state->rc)) {
clockcache_finish_load(
state->cc, state->addr, state->entry_number, state->rc);
state->result_status = state->rc;
rc = io_async_state_init_page(state->work.iostate,
state->cc->io,
io_async_preadv,
state->addr,
clockcache_get_from_disk_async_callback,
state);
if (!SUCCESS(rc)) {
clockcache_finish_load(state->cc, state->addr, state->entry_number, rc);
state->result_status = rc;
clockcache_dec_ref(state->cc, state->entry_number, state->tid);
state->succeeded = TRUE;
async_return(state);
}

state->rc =
io_async_state_append_page(state->iostate, state->entry->page.data);
if (!SUCCESS(state->rc)) {
io_async_state_deinit(state->iostate);
clockcache_finish_load(
state->cc, state->addr, state->entry_number, state->rc);
state->result_status = state->rc;
rc =
io_async_state_append_page(state->work.iostate, state->entry->page.data);
if (!SUCCESS(rc)) {
io_async_state_deinit(state->work.iostate);
clockcache_finish_load(state->cc, state->addr, state->entry_number, rc);
state->result_status = rc;
clockcache_dec_ref(state->cc, state->entry_number, state->tid);
state->succeeded = TRUE;
async_return(state);
Expand All @@ -2694,25 +2700,24 @@ clockcache_get_from_disk_async(clockcache_get_async_state *state, uint64 depth)
state->io_start_time = platform_get_timestamp();
}

async_await(state, io_async_run(state->iostate) == ASYNC_STATUS_DONE);
state->rc = io_async_state_get_result(state->iostate);
async_await(state, io_async_run(state->work.iostate) == ASYNC_STATUS_DONE);
rc = io_async_state_get_result(state->work.iostate);
/* Hard submission failures complete synchronously without invoking the
* callback. On a callback-driven completion, the wrapper already published
* readiness before notifying our caller. */
if (clockcache_test_flag(state->cc, state->entry_number, CC_LOADING)) {
clockcache_finish_load(
state->cc, state->addr, state->entry_number, state->rc);
clockcache_finish_load(state->cc, state->addr, state->entry_number, rc);
}
if (!SUCCESS(state->rc)) {
if (!SUCCESS(rc)) {
platform_error_log("clockcache_get_from_disk_async: async read failed "
"for addr %lu, entry %lu: %s\n",
state->addr,
state->entry_number,
platform_status_to_string(state->rc));
platform_status_to_string(rc));
}
io_async_state_deinit(state->iostate);
if (!SUCCESS(state->rc)) {
state->result_status = state->rc;
io_async_state_deinit(state->work.iostate);
if (!SUCCESS(rc)) {
state->result_status = rc;
clockcache_dec_ref(state->cc, state->entry_number, state->tid);
state->succeeded = TRUE;
async_return(state);
Expand Down Expand Up @@ -3078,12 +3083,12 @@ clockcache_writeback_page(clockcache *cc,

state = clockcache_io_state_acquire(cc);
state->cc = cc;
status = io_async_state_init(state->iostate,
cc->io,
io_async_pwritev,
addr,
clockcache_write_callback,
state);
status = io_async_state_init_extent(state->iostate,
cc->io,
io_async_pwritev,
addr,
clockcache_write_callback,
state);
if (!SUCCESS(status)) {
platform_error_log("clockcache_writeback_page: io_async_state_init "
"failed for addr %lu, entry %u, type %u: %s\n",
Expand Down Expand Up @@ -3173,15 +3178,16 @@ clockcache_writeback_extent(clockcache *cc,
}

if (state == NULL) {
req_addr = page_addr;
state = clockcache_io_state_acquire(cc);
state->cc = cc;
platform_status rc = io_async_state_init(state->iostate,
cc->io,
io_async_pwritev,
req_addr,
clockcache_write_callback,
state);
req_addr = page_addr;
state = clockcache_io_state_acquire(cc);
state->cc = cc;
platform_status rc =
io_async_state_init_extent(state->iostate,
cc->io,
io_async_pwritev,
req_addr,
clockcache_write_callback,
state);
if (!SUCCESS(rc)) {
platform_error_log("clockcache_writeback_extent: "
"io_async_state_init failed for extent addr "
Expand Down Expand Up @@ -3582,12 +3588,12 @@ clockcache_prefetch_pages(clockcache *cc,
}
state->cc = cc;
platform_status rc =
io_async_state_init(state->iostate,
cc->io,
io_async_preadv,
addr,
clockcache_prefetch_callback,
state);
io_async_state_init_extent(state->iostate,
cc->io,
io_async_preadv,
addr,
clockcache_prefetch_callback,
state);
if (!SUCCESS(rc)) {
platform_error_log("clockcache_prefetch_pages: "
"io_async_state_init failed for first "
Expand Down Expand Up @@ -4112,7 +4118,7 @@ clockcache_get_async_state_init_virtual(void *payload,
// the waiter on the wait queue, because the async wait system has internal
// instrumentation that can catch double enqueues, which could break if we
// re-init before submission.
async_waiter_init(&state->wait_node);
async_waiter_init(&state->work.wait_node);
}

static async_status
Expand Down
1 change: 0 additions & 1 deletion src/platform_linux/async.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,6 @@ async_call_sync_callback_function(void *arg)
#define DEFINE_ASYNC_STATE(name, height, ...) \
_Static_assert(0 < height, "height must be greater than 0"); \
typedef struct name { \
int __async_state_lock; \
async_state __async_state_stack[height]; \
DEFINE_STATE_STRUCT_FIELDS(__VA_ARGS__) \
} name; \
Expand Down
Loading
Loading