Add TGK exec plan encoding
This commit is contained in:
parent
dde532d68f
commit
7878cd3702
|
|
@ -86,6 +86,7 @@ set(AMDUAT_ENC_SRCS
|
|||
src/near_core/fer/receipt.c
|
||||
src/near_core/enc/asl_log.c
|
||||
src/near_core/enc/asl_core_index.c
|
||||
src/near_core/enc/asl_tgk_exec_plan.c
|
||||
src/near_core/enc/pel_program_dag.c
|
||||
src/near_core/enc/pel_program_dag_desc.c
|
||||
src/near_core/enc/pel_trace_dag.c
|
||||
|
|
@ -292,6 +293,17 @@ target_link_libraries(amduat_test_asl_core_index
|
|||
)
|
||||
add_test(NAME asl_core_index COMMAND amduat_test_asl_core_index)
|
||||
|
||||
add_executable(amduat_test_asl_tgk_exec_plan
|
||||
tests/enc/test_asl_tgk_exec_plan.c)
|
||||
target_include_directories(amduat_test_asl_tgk_exec_plan
|
||||
PRIVATE ${AMDUAT_INTERNAL_DIR}
|
||||
PRIVATE ${AMDUAT_INCLUDE_DIR}
|
||||
)
|
||||
target_link_libraries(amduat_test_asl_tgk_exec_plan
|
||||
PRIVATE amduat_enc amduat_hash_asl1 amduat_asl amduat_util
|
||||
)
|
||||
add_test(NAME asl_tgk_exec_plan COMMAND amduat_test_asl_tgk_exec_plan)
|
||||
|
||||
add_executable(amduat_test_tgk1_edge tests/enc/test_tgk1_edge.c)
|
||||
target_include_directories(amduat_test_tgk1_edge
|
||||
PRIVATE ${AMDUAT_INTERNAL_DIR}
|
||||
|
|
|
|||
115
include/amduat/enc/asl_tgk_exec_plan.h
Normal file
115
include/amduat/enc/asl_tgk_exec_plan.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#ifndef AMDUAT_ENC_ASL_TGK_EXEC_PLAN_H
|
||||
#define AMDUAT_ENC_ASL_TGK_EXEC_PLAN_H
|
||||
|
||||
#include "amduat/asl/core.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum { AMDUAT_ASL_TGK_EXEC_PLAN_VERSION = 1 };
|
||||
|
||||
typedef enum {
|
||||
AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN = 0,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_INDEX_FILTER = 1,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_MERGE = 2,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_PROJECTION = 3,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_TGK_TRAVERSAL = 4,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_AGGREGATION = 5,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_LIMIT_OFFSET = 6,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_SHARD_DISPATCH = 7,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_SIMD_FILTER = 8,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_TOMBSTONE_SHADOW = 9
|
||||
} amduat_asl_tgk_exec_operator_type_t;
|
||||
|
||||
typedef enum {
|
||||
AMDUAT_ASL_TGK_EXEC_OP_FLAG_NONE = 0x00,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_FLAG_PARALLEL = 0x01,
|
||||
AMDUAT_ASL_TGK_EXEC_OP_FLAG_OPTIONAL = 0x02
|
||||
} amduat_asl_tgk_exec_operator_flags_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t logseq_min;
|
||||
uint64_t logseq_max;
|
||||
} amduat_asl_tgk_exec_snapshot_range_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint8_t is_asl_segment;
|
||||
uint64_t segment_start_id;
|
||||
uint64_t segment_end_id;
|
||||
} segment_scan;
|
||||
|
||||
struct {
|
||||
uint32_t artifact_type_tag;
|
||||
uint8_t has_type_tag;
|
||||
uint32_t edge_type_key;
|
||||
uint8_t has_edge_type;
|
||||
uint8_t role;
|
||||
} index_filter;
|
||||
|
||||
struct {
|
||||
uint8_t deterministic;
|
||||
} merge;
|
||||
|
||||
struct {
|
||||
uint8_t project_artifact_id;
|
||||
uint8_t project_tgk_edge_id;
|
||||
uint8_t project_node_id;
|
||||
uint8_t project_type_tag;
|
||||
} projection;
|
||||
|
||||
struct {
|
||||
uint64_t start_node_id;
|
||||
uint32_t traversal_depth;
|
||||
uint8_t direction;
|
||||
} tgk_traversal;
|
||||
|
||||
struct {
|
||||
uint8_t agg_count;
|
||||
uint8_t agg_union;
|
||||
uint8_t agg_sum;
|
||||
} aggregation;
|
||||
|
||||
struct {
|
||||
uint64_t limit;
|
||||
uint64_t offset;
|
||||
} limit_offset;
|
||||
} amduat_asl_tgk_exec_operator_params_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t op_id;
|
||||
amduat_asl_tgk_exec_operator_type_t op_type;
|
||||
amduat_asl_tgk_exec_operator_flags_t flags;
|
||||
amduat_asl_tgk_exec_snapshot_range_t snapshot;
|
||||
amduat_asl_tgk_exec_operator_params_t params;
|
||||
uint32_t input_count;
|
||||
uint32_t inputs[8];
|
||||
} amduat_asl_tgk_exec_operator_def_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t plan_version;
|
||||
uint32_t operator_count;
|
||||
amduat_asl_tgk_exec_operator_def_t *operators;
|
||||
} amduat_asl_tgk_exec_plan_t;
|
||||
|
||||
bool amduat_enc_asl_tgk_exec_plan_encode_v1(
|
||||
const amduat_asl_tgk_exec_plan_t *plan,
|
||||
amduat_octets_t *out_bytes);
|
||||
|
||||
bool amduat_enc_asl_tgk_exec_plan_decode_v1(
|
||||
amduat_octets_t bytes,
|
||||
amduat_asl_tgk_exec_plan_t *out_plan);
|
||||
|
||||
void amduat_enc_asl_tgk_exec_plan_free(
|
||||
amduat_asl_tgk_exec_plan_t *plan);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* AMDUAT_ENC_ASL_TGK_EXEC_PLAN_H */
|
||||
|
|
@ -44,12 +44,12 @@ static bool amduat_asl_index_bloom_hash_pair(amduat_hash_id_t hash_id,
|
|||
header[2] = (uint8_t)(digest_len & 0xffu);
|
||||
header[3] = (uint8_t)((digest_len >> 8) & 0xffu);
|
||||
|
||||
hash = 1469598103934665603ull ^ 0x9e3779b97f4a7c15ull;
|
||||
hash = 14695981039346656037ull ^ 0x9e3779b97f4a7c15ull;
|
||||
hash = amduat_asl_index_bloom_hash_update(hash, header, sizeof(header));
|
||||
hash = amduat_asl_index_bloom_hash_update(hash, digest.data, digest.len);
|
||||
*out_h1 = hash;
|
||||
|
||||
hash = 1469598103934665603ull ^ 0xbf58476d1ce4e5b9ull;
|
||||
hash = 14695981039346656037ull ^ 0xbf58476d1ce4e5b9ull;
|
||||
hash = amduat_asl_index_bloom_hash_update(hash, header, sizeof(header));
|
||||
hash = amduat_asl_index_bloom_hash_update(hash, digest.data, digest.len);
|
||||
if (hash == 0u) {
|
||||
|
|
|
|||
494
src/near_core/enc/asl_tgk_exec_plan.c
Normal file
494
src/near_core/enc/asl_tgk_exec_plan.c
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
#include "amduat/enc/asl_tgk_exec_plan.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum {
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_HEADER_SIZE = 8,
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_INPUT_CAP = 8,
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_PARAMS_SIZE = 65,
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_OPERATOR_SIZE = 129,
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_OP_TYPE_MAX =
|
||||
AMDUAT_ASL_TGK_EXEC_OP_TOMBSTONE_SHADOW,
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_OP_FLAG_MASK =
|
||||
AMDUAT_ASL_TGK_EXEC_OP_FLAG_PARALLEL |
|
||||
AMDUAT_ASL_TGK_EXEC_OP_FLAG_OPTIONAL
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *data;
|
||||
size_t len;
|
||||
size_t offset;
|
||||
} amduat_asl_tgk_exec_plan_cursor_t;
|
||||
|
||||
static void amduat_asl_tgk_exec_plan_store_u32_le(uint8_t *out,
|
||||
uint32_t value) {
|
||||
out[0] = (uint8_t)(value & 0xffu);
|
||||
out[1] = (uint8_t)((value >> 8) & 0xffu);
|
||||
out[2] = (uint8_t)((value >> 16) & 0xffu);
|
||||
out[3] = (uint8_t)((value >> 24) & 0xffu);
|
||||
}
|
||||
|
||||
static void amduat_asl_tgk_exec_plan_store_u64_le(uint8_t *out,
|
||||
uint64_t value) {
|
||||
out[0] = (uint8_t)(value & 0xffu);
|
||||
out[1] = (uint8_t)((value >> 8) & 0xffu);
|
||||
out[2] = (uint8_t)((value >> 16) & 0xffu);
|
||||
out[3] = (uint8_t)((value >> 24) & 0xffu);
|
||||
out[4] = (uint8_t)((value >> 32) & 0xffu);
|
||||
out[5] = (uint8_t)((value >> 40) & 0xffu);
|
||||
out[6] = (uint8_t)((value >> 48) & 0xffu);
|
||||
out[7] = (uint8_t)((value >> 56) & 0xffu);
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_read_u32_le(
|
||||
amduat_asl_tgk_exec_plan_cursor_t *cur,
|
||||
uint32_t *out) {
|
||||
const uint8_t *data;
|
||||
|
||||
if (cur->len - cur->offset < 4u) {
|
||||
return false;
|
||||
}
|
||||
data = cur->data + cur->offset;
|
||||
*out = (uint32_t)data[0] | ((uint32_t)data[1] << 8) |
|
||||
((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24);
|
||||
cur->offset += 4u;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_read_u64_le(
|
||||
amduat_asl_tgk_exec_plan_cursor_t *cur,
|
||||
uint64_t *out) {
|
||||
const uint8_t *data;
|
||||
|
||||
if (cur->len - cur->offset < 8u) {
|
||||
return false;
|
||||
}
|
||||
data = cur->data + cur->offset;
|
||||
*out = (uint64_t)data[0] | ((uint64_t)data[1] << 8) |
|
||||
((uint64_t)data[2] << 16) | ((uint64_t)data[3] << 24) |
|
||||
((uint64_t)data[4] << 32) | ((uint64_t)data[5] << 40) |
|
||||
((uint64_t)data[6] << 48) | ((uint64_t)data[7] << 56);
|
||||
cur->offset += 8u;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_add_size(size_t *acc, size_t add) {
|
||||
if (*acc > SIZE_MAX - add) {
|
||||
return false;
|
||||
}
|
||||
*acc += add;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_is_bool(uint8_t value) {
|
||||
return value == 0u || value == 1u;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_validate_params(
|
||||
amduat_asl_tgk_exec_operator_type_t op_type,
|
||||
const amduat_asl_tgk_exec_operator_params_t *params) {
|
||||
if (!amduat_asl_tgk_exec_plan_is_bool(params->segment_scan.is_asl_segment)) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_asl_tgk_exec_plan_is_bool(params->index_filter.has_type_tag)) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_asl_tgk_exec_plan_is_bool(params->index_filter.has_edge_type)) {
|
||||
return false;
|
||||
}
|
||||
if (params->index_filter.role > 3u) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_asl_tgk_exec_plan_is_bool(params->merge.deterministic)) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_asl_tgk_exec_plan_is_bool(
|
||||
params->projection.project_artifact_id) ||
|
||||
!amduat_asl_tgk_exec_plan_is_bool(
|
||||
params->projection.project_tgk_edge_id) ||
|
||||
!amduat_asl_tgk_exec_plan_is_bool(params->projection.project_node_id) ||
|
||||
!amduat_asl_tgk_exec_plan_is_bool(params->projection.project_type_tag)) {
|
||||
return false;
|
||||
}
|
||||
if (params->tgk_traversal.direction > 3u) {
|
||||
return false;
|
||||
}
|
||||
if (op_type == AMDUAT_ASL_TGK_EXEC_OP_TGK_TRAVERSAL &&
|
||||
params->tgk_traversal.direction == 0u) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_asl_tgk_exec_plan_is_bool(params->aggregation.agg_count) ||
|
||||
!amduat_asl_tgk_exec_plan_is_bool(params->aggregation.agg_union) ||
|
||||
!amduat_asl_tgk_exec_plan_is_bool(params->aggregation.agg_sum)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_has_op_id(
|
||||
const amduat_asl_tgk_exec_plan_t *plan,
|
||||
uint32_t op_id) {
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < plan->operator_count; ++i) {
|
||||
if (plan->operators[i].op_id == op_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_unique_op_ids(
|
||||
const amduat_asl_tgk_exec_plan_t *plan) {
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
|
||||
for (i = 0; i < plan->operator_count; ++i) {
|
||||
for (j = i + 1u; j < plan->operator_count; ++j) {
|
||||
if (plan->operators[i].op_id == plan->operators[j].op_id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_validate_operator(
|
||||
const amduat_asl_tgk_exec_plan_t *plan,
|
||||
const amduat_asl_tgk_exec_operator_def_t *op) {
|
||||
uint32_t i;
|
||||
|
||||
if ((uint32_t)op->op_type > AMDUAT_ASL_TGK_EXEC_PLAN_OP_TYPE_MAX) {
|
||||
return false;
|
||||
}
|
||||
if (((uint32_t)op->flags & ~AMDUAT_ASL_TGK_EXEC_PLAN_OP_FLAG_MASK) != 0u) {
|
||||
return false;
|
||||
}
|
||||
if (op->input_count > AMDUAT_ASL_TGK_EXEC_PLAN_INPUT_CAP) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_asl_tgk_exec_plan_validate_params(op->op_type, &op->params)) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < op->input_count; ++i) {
|
||||
if (!amduat_asl_tgk_exec_plan_has_op_id(plan, op->inputs[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void amduat_asl_tgk_exec_plan_encode_params(
|
||||
const amduat_asl_tgk_exec_operator_params_t *params,
|
||||
uint8_t *buffer,
|
||||
size_t *offset) {
|
||||
buffer[(*offset)++] = params->segment_scan.is_asl_segment;
|
||||
amduat_asl_tgk_exec_plan_store_u64_le(
|
||||
buffer + *offset, params->segment_scan.segment_start_id);
|
||||
*offset += 8u;
|
||||
amduat_asl_tgk_exec_plan_store_u64_le(
|
||||
buffer + *offset, params->segment_scan.segment_end_id);
|
||||
*offset += 8u;
|
||||
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(
|
||||
buffer + *offset, params->index_filter.artifact_type_tag);
|
||||
*offset += 4u;
|
||||
buffer[(*offset)++] = params->index_filter.has_type_tag;
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(
|
||||
buffer + *offset, params->index_filter.edge_type_key);
|
||||
*offset += 4u;
|
||||
buffer[(*offset)++] = params->index_filter.has_edge_type;
|
||||
buffer[(*offset)++] = params->index_filter.role;
|
||||
|
||||
buffer[(*offset)++] = params->merge.deterministic;
|
||||
|
||||
buffer[(*offset)++] = params->projection.project_artifact_id;
|
||||
buffer[(*offset)++] = params->projection.project_tgk_edge_id;
|
||||
buffer[(*offset)++] = params->projection.project_node_id;
|
||||
buffer[(*offset)++] = params->projection.project_type_tag;
|
||||
|
||||
amduat_asl_tgk_exec_plan_store_u64_le(
|
||||
buffer + *offset, params->tgk_traversal.start_node_id);
|
||||
*offset += 8u;
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(
|
||||
buffer + *offset, params->tgk_traversal.traversal_depth);
|
||||
*offset += 4u;
|
||||
buffer[(*offset)++] = params->tgk_traversal.direction;
|
||||
|
||||
buffer[(*offset)++] = params->aggregation.agg_count;
|
||||
buffer[(*offset)++] = params->aggregation.agg_union;
|
||||
buffer[(*offset)++] = params->aggregation.agg_sum;
|
||||
|
||||
amduat_asl_tgk_exec_plan_store_u64_le(buffer + *offset,
|
||||
params->limit_offset.limit);
|
||||
*offset += 8u;
|
||||
amduat_asl_tgk_exec_plan_store_u64_le(buffer + *offset,
|
||||
params->limit_offset.offset);
|
||||
*offset += 8u;
|
||||
}
|
||||
|
||||
static bool amduat_asl_tgk_exec_plan_decode_params(
|
||||
amduat_asl_tgk_exec_plan_cursor_t *cur,
|
||||
amduat_asl_tgk_exec_operator_params_t *params) {
|
||||
if (cur->len - cur->offset < AMDUAT_ASL_TGK_EXEC_PLAN_PARAMS_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
params->segment_scan.is_asl_segment = cur->data[cur->offset++];
|
||||
if (!amduat_asl_tgk_exec_plan_read_u64_le(
|
||||
cur, ¶ms->segment_scan.segment_start_id) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u64_le(
|
||||
cur, ¶ms->segment_scan.segment_end_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!amduat_asl_tgk_exec_plan_read_u32_le(
|
||||
cur, ¶ms->index_filter.artifact_type_tag)) {
|
||||
return false;
|
||||
}
|
||||
params->index_filter.has_type_tag = cur->data[cur->offset++];
|
||||
if (!amduat_asl_tgk_exec_plan_read_u32_le(
|
||||
cur, ¶ms->index_filter.edge_type_key)) {
|
||||
return false;
|
||||
}
|
||||
params->index_filter.has_edge_type = cur->data[cur->offset++];
|
||||
params->index_filter.role = cur->data[cur->offset++];
|
||||
|
||||
params->merge.deterministic = cur->data[cur->offset++];
|
||||
|
||||
params->projection.project_artifact_id = cur->data[cur->offset++];
|
||||
params->projection.project_tgk_edge_id = cur->data[cur->offset++];
|
||||
params->projection.project_node_id = cur->data[cur->offset++];
|
||||
params->projection.project_type_tag = cur->data[cur->offset++];
|
||||
|
||||
if (!amduat_asl_tgk_exec_plan_read_u64_le(
|
||||
cur, ¶ms->tgk_traversal.start_node_id) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u32_le(
|
||||
cur, ¶ms->tgk_traversal.traversal_depth)) {
|
||||
return false;
|
||||
}
|
||||
params->tgk_traversal.direction = cur->data[cur->offset++];
|
||||
|
||||
params->aggregation.agg_count = cur->data[cur->offset++];
|
||||
params->aggregation.agg_union = cur->data[cur->offset++];
|
||||
params->aggregation.agg_sum = cur->data[cur->offset++];
|
||||
|
||||
if (!amduat_asl_tgk_exec_plan_read_u64_le(
|
||||
cur, ¶ms->limit_offset.limit) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u64_le(
|
||||
cur, ¶ms->limit_offset.offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool amduat_enc_asl_tgk_exec_plan_encode_v1(
|
||||
const amduat_asl_tgk_exec_plan_t *plan,
|
||||
amduat_octets_t *out_bytes) {
|
||||
size_t total_len;
|
||||
size_t offset;
|
||||
uint8_t *buffer;
|
||||
uint32_t i;
|
||||
|
||||
if (out_bytes == NULL) {
|
||||
return false;
|
||||
}
|
||||
out_bytes->data = NULL;
|
||||
out_bytes->len = 0u;
|
||||
|
||||
if (plan == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (plan->operator_count != 0u && plan->operators == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (plan->operator_count > SIZE_MAX / AMDUAT_ASL_TGK_EXEC_PLAN_OPERATOR_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
total_len = AMDUAT_ASL_TGK_EXEC_PLAN_HEADER_SIZE;
|
||||
if (!amduat_asl_tgk_exec_plan_add_size(
|
||||
&total_len,
|
||||
(size_t)plan->operator_count *
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_OPERATOR_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plan->operator_count > UINT32_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < plan->operator_count; ++i) {
|
||||
if (!amduat_asl_tgk_exec_plan_validate_operator(plan,
|
||||
&plan->operators[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!amduat_asl_tgk_exec_plan_unique_op_ids(plan)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer = (uint8_t *)malloc(total_len);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
offset = 0u;
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(buffer + offset, plan->plan_version);
|
||||
offset += 4u;
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(buffer + offset,
|
||||
plan->operator_count);
|
||||
offset += 4u;
|
||||
|
||||
for (i = 0; i < plan->operator_count; ++i) {
|
||||
const amduat_asl_tgk_exec_operator_def_t *op = &plan->operators[i];
|
||||
uint32_t j;
|
||||
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(buffer + offset, op->op_id);
|
||||
offset += 4u;
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(buffer + offset,
|
||||
(uint32_t)op->op_type);
|
||||
offset += 4u;
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(buffer + offset,
|
||||
(uint32_t)op->flags);
|
||||
offset += 4u;
|
||||
amduat_asl_tgk_exec_plan_store_u64_le(buffer + offset,
|
||||
op->snapshot.logseq_min);
|
||||
offset += 8u;
|
||||
amduat_asl_tgk_exec_plan_store_u64_le(buffer + offset,
|
||||
op->snapshot.logseq_max);
|
||||
offset += 8u;
|
||||
|
||||
amduat_asl_tgk_exec_plan_encode_params(&op->params, buffer, &offset);
|
||||
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(buffer + offset, op->input_count);
|
||||
offset += 4u;
|
||||
for (j = 0; j < AMDUAT_ASL_TGK_EXEC_PLAN_INPUT_CAP; ++j) {
|
||||
amduat_asl_tgk_exec_plan_store_u32_le(buffer + offset, op->inputs[j]);
|
||||
offset += 4u;
|
||||
}
|
||||
}
|
||||
|
||||
out_bytes->data = buffer;
|
||||
out_bytes->len = total_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool amduat_enc_asl_tgk_exec_plan_decode_v1(
|
||||
amduat_octets_t bytes,
|
||||
amduat_asl_tgk_exec_plan_t *out_plan) {
|
||||
amduat_asl_tgk_exec_plan_cursor_t cur;
|
||||
uint32_t operator_count;
|
||||
size_t expected_len;
|
||||
amduat_asl_tgk_exec_operator_def_t *operators;
|
||||
uint32_t i;
|
||||
|
||||
if (out_plan == NULL) {
|
||||
return false;
|
||||
}
|
||||
out_plan->plan_version = 0u;
|
||||
out_plan->operator_count = 0u;
|
||||
out_plan->operators = NULL;
|
||||
|
||||
if (bytes.len < AMDUAT_ASL_TGK_EXEC_PLAN_HEADER_SIZE ||
|
||||
bytes.data == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cur.data = bytes.data;
|
||||
cur.len = bytes.len;
|
||||
cur.offset = 0u;
|
||||
|
||||
if (!amduat_asl_tgk_exec_plan_read_u32_le(&cur, &out_plan->plan_version) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u32_le(&cur, &operator_count)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (operator_count > SIZE_MAX / AMDUAT_ASL_TGK_EXEC_PLAN_OPERATOR_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
expected_len = AMDUAT_ASL_TGK_EXEC_PLAN_HEADER_SIZE +
|
||||
(size_t)operator_count *
|
||||
AMDUAT_ASL_TGK_EXEC_PLAN_OPERATOR_SIZE;
|
||||
if (expected_len != bytes.len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (operator_count == 0u) {
|
||||
out_plan->operator_count = 0u;
|
||||
return true;
|
||||
}
|
||||
|
||||
operators = (amduat_asl_tgk_exec_operator_def_t *)calloc(
|
||||
operator_count, sizeof(*operators));
|
||||
if (operators == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < operator_count; ++i) {
|
||||
amduat_asl_tgk_exec_operator_def_t *op = &operators[i];
|
||||
uint32_t j;
|
||||
uint32_t op_type_raw;
|
||||
uint32_t flags_raw;
|
||||
|
||||
if (!amduat_asl_tgk_exec_plan_read_u32_le(&cur, &op->op_id) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u32_le(&cur, &op_type_raw) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u32_le(&cur, &flags_raw) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u64_le(&cur,
|
||||
&op->snapshot.logseq_min) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u64_le(&cur,
|
||||
&op->snapshot.logseq_max)) {
|
||||
free(operators);
|
||||
return false;
|
||||
}
|
||||
op->op_type = (amduat_asl_tgk_exec_operator_type_t)op_type_raw;
|
||||
op->flags = (amduat_asl_tgk_exec_operator_flags_t)flags_raw;
|
||||
|
||||
if (!amduat_asl_tgk_exec_plan_decode_params(&cur, &op->params) ||
|
||||
!amduat_asl_tgk_exec_plan_read_u32_le(&cur, &op->input_count)) {
|
||||
free(operators);
|
||||
return false;
|
||||
}
|
||||
if (op->input_count > AMDUAT_ASL_TGK_EXEC_PLAN_INPUT_CAP) {
|
||||
free(operators);
|
||||
return false;
|
||||
}
|
||||
for (j = 0; j < AMDUAT_ASL_TGK_EXEC_PLAN_INPUT_CAP; ++j) {
|
||||
if (!amduat_asl_tgk_exec_plan_read_u32_le(&cur, &op->inputs[j])) {
|
||||
free(operators);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out_plan->operator_count = operator_count;
|
||||
out_plan->operators = operators;
|
||||
|
||||
if (!amduat_asl_tgk_exec_plan_unique_op_ids(out_plan)) {
|
||||
amduat_enc_asl_tgk_exec_plan_free(out_plan);
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < operator_count; ++i) {
|
||||
if (!amduat_asl_tgk_exec_plan_validate_operator(out_plan,
|
||||
&operators[i])) {
|
||||
amduat_enc_asl_tgk_exec_plan_free(out_plan);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void amduat_enc_asl_tgk_exec_plan_free(amduat_asl_tgk_exec_plan_t *plan) {
|
||||
if (plan == NULL) {
|
||||
return;
|
||||
}
|
||||
free(plan->operators);
|
||||
plan->operators = NULL;
|
||||
plan->operator_count = 0u;
|
||||
plan->plan_version = 0u;
|
||||
}
|
||||
231
tests/enc/test_asl_tgk_exec_plan.c
Normal file
231
tests/enc/test_asl_tgk_exec_plan.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
#include "amduat/enc/asl_tgk_exec_plan.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum {
|
||||
k_plan_header_size = 8,
|
||||
k_params_size = 65,
|
||||
k_operator_size = 129,
|
||||
k_input_offset = 97
|
||||
};
|
||||
|
||||
static void store_u32_le(uint8_t *out, uint32_t value) {
|
||||
out[0] = (uint8_t)(value & 0xffu);
|
||||
out[1] = (uint8_t)((value >> 8) & 0xffu);
|
||||
out[2] = (uint8_t)((value >> 16) & 0xffu);
|
||||
out[3] = (uint8_t)((value >> 24) & 0xffu);
|
||||
}
|
||||
|
||||
static void fill_default_params(amduat_asl_tgk_exec_operator_params_t *params) {
|
||||
memset(params, 0, sizeof(*params));
|
||||
params->tgk_traversal.direction = 1u;
|
||||
}
|
||||
|
||||
static int test_round_trip(void) {
|
||||
amduat_asl_tgk_exec_operator_def_t operators[2];
|
||||
amduat_asl_tgk_exec_plan_t plan;
|
||||
amduat_octets_t encoded;
|
||||
amduat_asl_tgk_exec_plan_t decoded;
|
||||
int exit_code = 1;
|
||||
|
||||
memset(operators, 0, sizeof(operators));
|
||||
fill_default_params(&operators[0].params);
|
||||
fill_default_params(&operators[1].params);
|
||||
|
||||
operators[0].op_id = 1u;
|
||||
operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN;
|
||||
operators[0].flags = AMDUAT_ASL_TGK_EXEC_OP_FLAG_NONE;
|
||||
operators[0].snapshot.logseq_min = 0u;
|
||||
operators[0].snapshot.logseq_max = 10u;
|
||||
operators[0].input_count = 0u;
|
||||
|
||||
operators[1].op_id = 2u;
|
||||
operators[1].op_type = AMDUAT_ASL_TGK_EXEC_OP_TGK_TRAVERSAL;
|
||||
operators[1].flags = AMDUAT_ASL_TGK_EXEC_OP_FLAG_PARALLEL;
|
||||
operators[1].snapshot.logseq_min = 1u;
|
||||
operators[1].snapshot.logseq_max = 10u;
|
||||
operators[1].params.tgk_traversal.direction = 2u;
|
||||
operators[1].params.tgk_traversal.traversal_depth = 3u;
|
||||
operators[1].params.tgk_traversal.start_node_id = 42u;
|
||||
operators[1].input_count = 1u;
|
||||
operators[1].inputs[0] = 1u;
|
||||
|
||||
plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION;
|
||||
plan.operator_count = 2u;
|
||||
plan.operators = operators;
|
||||
|
||||
if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) {
|
||||
fprintf(stderr, "encode failed\n");
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
if (!amduat_enc_asl_tgk_exec_plan_decode_v1(encoded, &decoded)) {
|
||||
fprintf(stderr, "decode failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (decoded.plan_version != plan.plan_version ||
|
||||
decoded.operator_count != plan.operator_count) {
|
||||
fprintf(stderr, "header mismatch\n");
|
||||
goto cleanup_decoded;
|
||||
}
|
||||
if (decoded.operators[1].op_type != operators[1].op_type ||
|
||||
decoded.operators[1].params.tgk_traversal.direction != 2u ||
|
||||
decoded.operators[1].params.tgk_traversal.traversal_depth != 3u ||
|
||||
decoded.operators[1].params.tgk_traversal.start_node_id != 42u) {
|
||||
fprintf(stderr, "operator fields mismatch\n");
|
||||
goto cleanup_decoded;
|
||||
}
|
||||
if (decoded.operators[1].input_count != 1u ||
|
||||
decoded.operators[1].inputs[0] != 1u) {
|
||||
fprintf(stderr, "inputs mismatch\n");
|
||||
goto cleanup_decoded;
|
||||
}
|
||||
|
||||
exit_code = 0;
|
||||
|
||||
cleanup_decoded:
|
||||
amduat_enc_asl_tgk_exec_plan_free(&decoded);
|
||||
cleanup:
|
||||
free((void *)encoded.data);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static int test_invalid_input_ref(void) {
|
||||
amduat_asl_tgk_exec_operator_def_t operators[1];
|
||||
amduat_asl_tgk_exec_plan_t plan;
|
||||
amduat_octets_t encoded;
|
||||
int exit_code = 1;
|
||||
size_t op_offset;
|
||||
size_t input_offset;
|
||||
|
||||
memset(operators, 0, sizeof(operators));
|
||||
fill_default_params(&operators[0].params);
|
||||
operators[0].op_id = 1u;
|
||||
operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN;
|
||||
operators[0].input_count = 0u;
|
||||
|
||||
plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION;
|
||||
plan.operator_count = 1u;
|
||||
plan.operators = operators;
|
||||
|
||||
if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) {
|
||||
fprintf(stderr, "encode failed\n");
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
op_offset = k_plan_header_size;
|
||||
if (encoded.len < op_offset + k_input_offset + 4u) {
|
||||
fprintf(stderr, "encoded buffer too small\n");
|
||||
goto cleanup;
|
||||
}
|
||||
store_u32_le((uint8_t *)encoded.data + op_offset + k_params_size + 28u, 1u);
|
||||
input_offset = op_offset + k_input_offset;
|
||||
store_u32_le((uint8_t *)encoded.data + input_offset, 99u);
|
||||
|
||||
if (amduat_enc_asl_tgk_exec_plan_decode_v1(encoded, &(amduat_asl_tgk_exec_plan_t){0})) {
|
||||
fprintf(stderr, "decode unexpectedly succeeded\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
exit_code = 0;
|
||||
|
||||
cleanup:
|
||||
free((void *)encoded.data);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static int test_truncated_decode(void) {
|
||||
amduat_asl_tgk_exec_operator_def_t operators[1];
|
||||
amduat_asl_tgk_exec_plan_t plan;
|
||||
amduat_octets_t encoded;
|
||||
amduat_octets_t truncated;
|
||||
int exit_code = 1;
|
||||
|
||||
memset(operators, 0, sizeof(operators));
|
||||
fill_default_params(&operators[0].params);
|
||||
operators[0].op_id = 1u;
|
||||
operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN;
|
||||
|
||||
plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION;
|
||||
plan.operator_count = 1u;
|
||||
plan.operators = operators;
|
||||
|
||||
if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) {
|
||||
fprintf(stderr, "encode failed\n");
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
truncated = amduat_octets(encoded.data, encoded.len - 1u);
|
||||
if (amduat_enc_asl_tgk_exec_plan_decode_v1(truncated,
|
||||
&(amduat_asl_tgk_exec_plan_t){0})) {
|
||||
fprintf(stderr, "decode unexpectedly succeeded\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
exit_code = 0;
|
||||
|
||||
cleanup:
|
||||
free((void *)encoded.data);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static int test_invalid_input_count(void) {
|
||||
amduat_asl_tgk_exec_operator_def_t operators[1];
|
||||
amduat_asl_tgk_exec_plan_t plan;
|
||||
amduat_octets_t encoded;
|
||||
int exit_code = 1;
|
||||
size_t op_offset;
|
||||
size_t input_count_offset;
|
||||
|
||||
memset(operators, 0, sizeof(operators));
|
||||
fill_default_params(&operators[0].params);
|
||||
operators[0].op_id = 1u;
|
||||
operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN;
|
||||
|
||||
plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION;
|
||||
plan.operator_count = 1u;
|
||||
plan.operators = operators;
|
||||
|
||||
if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) {
|
||||
fprintf(stderr, "encode failed\n");
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
op_offset = k_plan_header_size;
|
||||
input_count_offset = op_offset + k_params_size + 28u;
|
||||
if (encoded.len < input_count_offset + 4u) {
|
||||
fprintf(stderr, "encoded buffer too small\n");
|
||||
goto cleanup;
|
||||
}
|
||||
store_u32_le((uint8_t *)encoded.data + input_count_offset, 9u);
|
||||
|
||||
if (amduat_enc_asl_tgk_exec_plan_decode_v1(encoded,
|
||||
&(amduat_asl_tgk_exec_plan_t){0})) {
|
||||
fprintf(stderr, "decode unexpectedly succeeded\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
exit_code = 0;
|
||||
|
||||
cleanup:
|
||||
free((void *)encoded.data);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
if (test_round_trip() != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (test_invalid_input_ref() != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (test_truncated_decode() != 0) {
|
||||
return 1;
|
||||
}
|
||||
return test_invalid_input_count();
|
||||
}
|
||||
Loading…
Reference in a new issue