int process_frame_insert(avro_value_t *record_val, frame_reader_t reader, uint64_t wal_pos) { int err = 0, key_present; avro_value_t relid_val, key_val, new_val, branch_val; int64_t relid; const void *key_bin = NULL, *new_bin = NULL; size_t key_len = 0, new_len = 0; check(err, avro_value_get_by_index(record_val, 0, &relid_val, NULL)); check(err, avro_value_get_by_index(record_val, 1, &key_val, NULL)); check(err, avro_value_get_by_index(record_val, 2, &new_val, NULL)); check(err, avro_value_get_long(&relid_val, &relid)); check(err, avro_value_get_discriminant(&key_val, &key_present)); check(err, avro_value_get_bytes(&new_val, &new_bin, &new_len)); schema_list_entry *entry = schema_list_lookup(reader, relid); if (!entry) { avro_set_error("Received insert for unknown relid %u", relid); return EINVAL; } if (key_present) { check(err, avro_value_get_current_branch(&key_val, &branch_val)); check(err, avro_value_get_bytes(&branch_val, &key_bin, &key_len)); check(err, read_entirely(&entry->key_value, entry->avro_reader, key_bin, key_len)); } check(err, read_entirely(&entry->row_value, entry->avro_reader, new_bin, new_len)); if (reader->on_insert_row) { check(err, reader->on_insert_row(reader->cb_context, wal_pos, relid, key_bin, key_len, key_bin ? &entry->key_value : NULL, new_bin, new_len, &entry->row_value)); } return err; }
int process_frame_table_schema(avro_value_t *record_val, frame_reader_t reader, uint64_t wal_pos) { int err = 0, key_schema_present; avro_value_t relid_val, hash_val, key_schema_val, row_schema_val, branch_val; int64_t relid; const void *hash; const char *key_schema_json = NULL, *row_schema_json; size_t hash_len, key_schema_len = 1, row_schema_len; avro_schema_t key_schema = NULL, row_schema; check(err, avro_value_get_by_index(record_val, 0, &relid_val, NULL)); check(err, avro_value_get_by_index(record_val, 1, &hash_val, NULL)); check(err, avro_value_get_by_index(record_val, 2, &key_schema_val, NULL)); check(err, avro_value_get_by_index(record_val, 3, &row_schema_val, NULL)); check(err, avro_value_get_long(&relid_val, &relid)); check(err, avro_value_get_fixed(&hash_val, &hash, &hash_len)); check(err, avro_value_get_discriminant(&key_schema_val, &key_schema_present)); check(err, avro_value_get_string(&row_schema_val, &row_schema_json, &row_schema_len)); check(err, avro_schema_from_json_length(row_schema_json, row_schema_len - 1, &row_schema)); schema_list_entry *entry = schema_list_replace(reader, relid); entry->relid = relid; entry->hash = *((uint64_t *) hash); entry->row_schema = row_schema; entry->row_iface = avro_generic_class_from_schema(row_schema); avro_generic_value_new(entry->row_iface, &entry->row_value); avro_generic_value_new(entry->row_iface, &entry->old_value); entry->avro_reader = avro_reader_memory(NULL, 0); if (key_schema_present) { check(err, avro_value_get_current_branch(&key_schema_val, &branch_val)); check(err, avro_value_get_string(&branch_val, &key_schema_json, &key_schema_len)); check(err, avro_schema_from_json_length(key_schema_json, key_schema_len - 1, &key_schema)); entry->key_schema = key_schema; entry->key_iface = avro_generic_class_from_schema(key_schema); avro_generic_value_new(entry->key_iface, &entry->key_value); } else { entry->key_schema = NULL; } if (reader->on_table_schema) { check(err, reader->on_table_schema(reader->cb_context, wal_pos, relid, key_schema_json, key_schema_len - 1, key_schema, row_schema_json, row_schema_len - 1, row_schema)); } return err; }
int process_frame(avro_value_t *frame_val, frame_reader_t reader, uint64_t wal_pos) { int err = 0, msg_type; size_t num_messages; avro_value_t msg_val, union_val, record_val; check(err, avro_value_get_by_index(frame_val, 0, &msg_val, NULL)); check(err, avro_value_get_size(&msg_val, &num_messages)); for (int i = 0; i < num_messages; i++) { check(err, avro_value_get_by_index(&msg_val, i, &union_val, NULL)); check(err, avro_value_get_discriminant(&union_val, &msg_type)); check(err, avro_value_get_current_branch(&union_val, &record_val)); switch (msg_type) { case PROTOCOL_MSG_BEGIN_TXN: check(err, process_frame_begin_txn(&record_val, reader, wal_pos)); break; case PROTOCOL_MSG_COMMIT_TXN: check(err, process_frame_commit_txn(&record_val, reader, wal_pos)); break; case PROTOCOL_MSG_TABLE_SCHEMA: check(err, process_frame_table_schema(&record_val, reader, wal_pos)); break; case PROTOCOL_MSG_INSERT: check(err, process_frame_insert(&record_val, reader, wal_pos)); break; case PROTOCOL_MSG_UPDATE: check(err, process_frame_update(&record_val, reader, wal_pos)); break; case PROTOCOL_MSG_DELETE: check(err, process_frame_delete(&record_val, reader, wal_pos)); break; default: avro_set_error("Unknown message type %d", msg_type); return EINVAL; } } return err; }
int avro_value_equal_fast(avro_value_t *val1, avro_value_t *val2) { avro_type_t type1 = avro_value_get_type(val1); avro_type_t type2 = avro_value_get_type(val2); if (type1 != type2) { return 0; } switch (type1) { case AVRO_BOOLEAN: { int v1; int v2; check_return(0, avro_value_get_boolean(val1, &v1)); check_return(0, avro_value_get_boolean(val2, &v2)); return (v1 == v2); } case AVRO_BYTES: { const void *buf1; const void *buf2; size_t size1; size_t size2; check_return(0, avro_value_get_bytes(val1, &buf1, &size1)); check_return(0, avro_value_get_bytes(val2, &buf2, &size2)); if (size1 != size2) { return 0; } return (memcmp(buf1, buf2, size1) == 0); } case AVRO_DOUBLE: { double v1; double v2; check_return(0, avro_value_get_double(val1, &v1)); check_return(0, avro_value_get_double(val2, &v2)); return (v1 == v2); } case AVRO_FLOAT: { float v1; float v2; check_return(0, avro_value_get_float(val1, &v1)); check_return(0, avro_value_get_float(val2, &v2)); return (v1 == v2); } case AVRO_INT32: { int32_t v1; int32_t v2; check_return(0, avro_value_get_int(val1, &v1)); check_return(0, avro_value_get_int(val2, &v2)); return (v1 == v2); } case AVRO_INT64: { int64_t v1; int64_t v2; check_return(0, avro_value_get_long(val1, &v1)); check_return(0, avro_value_get_long(val2, &v2)); return (v1 == v2); } case AVRO_NULL: { check_return(0, avro_value_get_null(val1)); check_return(0, avro_value_get_null(val2)); return 1; } case AVRO_STRING: { const char *buf1; const char *buf2; size_t size1; size_t size2; check_return(0, avro_value_get_string(val1, &buf1, &size1)); check_return(0, avro_value_get_string(val2, &buf2, &size2)); if (size1 != size2) { return 0; } return (memcmp(buf1, buf2, size1) == 0); } case AVRO_ARRAY: { size_t count1; size_t count2; check_return(0, avro_value_get_size(val1, &count1)); check_return(0, avro_value_get_size(val2, &count2)); if (count1 != count2) { return 0; } size_t i; for (i = 0; i < count1; i++) { avro_value_t child1; avro_value_t child2; check_return(0, avro_value_get_by_index (val1, i, &child1, NULL)); check_return(0, avro_value_get_by_index (val2, i, &child2, NULL)); if (!avro_value_equal_fast(&child1, &child2)) { return 0; } } return 1; } case AVRO_ENUM: { int v1; int v2; check_return(0, avro_value_get_enum(val1, &v1)); check_return(0, avro_value_get_enum(val2, &v2)); return (v1 == v2); } case AVRO_FIXED: { const void *buf1; const void *buf2; size_t size1; size_t size2; check_return(0, avro_value_get_fixed(val1, &buf1, &size1)); check_return(0, avro_value_get_fixed(val2, &buf2, &size2)); if (size1 != size2) { return 0; } return (memcmp(buf1, buf2, size1) == 0); } case AVRO_MAP: { size_t count1; size_t count2; check_return(0, avro_value_get_size(val1, &count1)); check_return(0, avro_value_get_size(val2, &count2)); if (count1 != count2) { return 0; } size_t i; for (i = 0; i < count1; i++) { avro_value_t child1; avro_value_t child2; const char *key1; check_return(0, avro_value_get_by_index (val1, i, &child1, &key1)); check_return(0, avro_value_get_by_name (val2, key1, &child2, NULL)); if (!avro_value_equal_fast(&child1, &child2)) { return 0; } } return 1; } case AVRO_RECORD: { size_t count1; check_return(0, avro_value_get_size(val1, &count1)); size_t i; for (i = 0; i < count1; i++) { avro_value_t child1; avro_value_t child2; check_return(0, avro_value_get_by_index (val1, i, &child1, NULL)); check_return(0, avro_value_get_by_index (val2, i, &child2, NULL)); if (!avro_value_equal_fast(&child1, &child2)) { return 0; } } return 1; } case AVRO_UNION: { int disc1; int disc2; check_return(0, avro_value_get_discriminant(val1, &disc1)); check_return(0, avro_value_get_discriminant(val2, &disc2)); if (disc1 != disc2) { return 0; } avro_value_t branch1; avro_value_t branch2; check_return(0, avro_value_get_current_branch(val1, &branch1)); check_return(0, avro_value_get_current_branch(val2, &branch2)); return avro_value_equal_fast(&branch1, &branch2); } default: return 0; } }
int avro_value_copy_fast(avro_value_t *dest, const avro_value_t *src) { avro_type_t dest_type = avro_value_get_type(dest); avro_type_t src_type = avro_value_get_type(src); if (dest_type != src_type) { return 0; } int rval; check(rval, avro_value_reset(dest)); switch (dest_type) { case AVRO_BOOLEAN: { int val; check(rval, avro_value_get_boolean(src, &val)); return avro_value_set_boolean(dest, val); } case AVRO_BYTES: { avro_wrapped_buffer_t val; check(rval, avro_value_grab_bytes(src, &val)); return avro_value_give_bytes(dest, &val); } case AVRO_DOUBLE: { double val; check(rval, avro_value_get_double(src, &val)); return avro_value_set_double(dest, val); } case AVRO_FLOAT: { float val; check(rval, avro_value_get_float(src, &val)); return avro_value_set_float(dest, val); } case AVRO_INT32: { int32_t val; check(rval, avro_value_get_int(src, &val)); return avro_value_set_int(dest, val); } case AVRO_INT64: { int64_t val; check(rval, avro_value_get_long(src, &val)); return avro_value_set_long(dest, val); } case AVRO_NULL: { check(rval, avro_value_get_null(src)); return avro_value_set_null(dest); } case AVRO_STRING: { avro_wrapped_buffer_t val; check(rval, avro_value_grab_string(src, &val)); return avro_value_give_string_len(dest, &val); } case AVRO_ARRAY: { size_t count; check(rval, avro_value_get_size(src, &count)); size_t i; for (i = 0; i < count; i++) { avro_value_t src_child; avro_value_t dest_child; check(rval, avro_value_get_by_index (src, i, &src_child, NULL)); check(rval, avro_value_append (dest, &dest_child, NULL)); check(rval, avro_value_copy_fast (&dest_child, &src_child)); } return 0; } case AVRO_ENUM: { int val; check(rval, avro_value_get_enum(src, &val)); return avro_value_set_enum(dest, val); } case AVRO_FIXED: { avro_wrapped_buffer_t val; check(rval, avro_value_grab_fixed(src, &val)); return avro_value_give_fixed(dest, &val); } case AVRO_MAP: { size_t count; check(rval, avro_value_get_size(src, &count)); size_t i; for (i = 0; i < count; i++) { avro_value_t src_child; avro_value_t dest_child; const char *key; check(rval, avro_value_get_by_index (src, i, &src_child, &key)); check(rval, avro_value_add (dest, key, &dest_child, NULL, NULL)); check(rval, avro_value_copy_fast (&dest_child, &src_child)); } return 0; } case AVRO_RECORD: { size_t count; check(rval, avro_value_get_size(src, &count)); size_t i; for (i = 0; i < count; i++) { avro_value_t src_child; avro_value_t dest_child; check(rval, avro_value_get_by_index (src, i, &src_child, NULL)); check(rval, avro_value_get_by_index (dest, i, &dest_child, NULL)); check(rval, avro_value_copy_fast (&dest_child, &src_child)); } return 0; } case AVRO_UNION: { int disc; check(rval, avro_value_get_discriminant(src, &disc)); avro_value_t src_branch; avro_value_t dest_branch; check(rval, avro_value_get_current_branch(src, &src_branch)); check(rval, avro_value_set_branch(dest, disc, &dest_branch)); return avro_value_copy_fast(&dest_branch, &src_branch); } default: return 0; } }
int avro_value_cmp_fast(avro_value_t *val1, avro_value_t *val2) { avro_type_t type1 = avro_value_get_type(val1); avro_type_t type2 = avro_value_get_type(val2); if (type1 != type2) { return -1; } switch (type1) { case AVRO_BOOLEAN: { int v1; int v2; check_return(0, avro_value_get_boolean(val1, &v1)); check_return(0, avro_value_get_boolean(val2, &v2)); return cmp(!!v1, !!v2); } case AVRO_BYTES: { const void *buf1; const void *buf2; size_t size1; size_t size2; size_t min_size; int result; check_return(0, avro_value_get_bytes(val1, &buf1, &size1)); check_return(0, avro_value_get_bytes(val2, &buf2, &size2)); min_size = (size1 < size2)? size1: size2; result = memcmp(buf1, buf2, min_size); if (result != 0) { return result; } else { return cmp(size1, size2); } } case AVRO_DOUBLE: { double v1; double v2; check_return(0, avro_value_get_double(val1, &v1)); check_return(0, avro_value_get_double(val2, &v2)); return cmp(v1, v2); } case AVRO_FLOAT: { float v1; float v2; check_return(0, avro_value_get_float(val1, &v1)); check_return(0, avro_value_get_float(val2, &v2)); return cmp(v1, v2); } case AVRO_INT32: { int32_t v1; int32_t v2; check_return(0, avro_value_get_int(val1, &v1)); check_return(0, avro_value_get_int(val2, &v2)); return cmp(v1, v2); } case AVRO_INT64: { int64_t v1; int64_t v2; check_return(0, avro_value_get_long(val1, &v1)); check_return(0, avro_value_get_long(val2, &v2)); return cmp(v1, v2); } case AVRO_NULL: { check_return(0, avro_value_get_null(val1)); check_return(0, avro_value_get_null(val2)); return 0; } case AVRO_STRING: { const char *buf1; const char *buf2; size_t size1; size_t size2; size_t min_size; int result; check_return(0, avro_value_get_string(val1, &buf1, &size1)); check_return(0, avro_value_get_string(val2, &buf2, &size2)); min_size = (size1 < size2)? size1: size2; result = memcmp(buf1, buf2, min_size); if (result != 0) { return result; } else { return cmp(size1, size2); } } case AVRO_ARRAY: { size_t count1; size_t count2; size_t min_count; size_t i; check_return(0, avro_value_get_size(val1, &count1)); check_return(0, avro_value_get_size(val2, &count2)); min_count = (count1 < count2)? count1: count2; for (i = 0; i < min_count; i++) { avro_value_t child1; avro_value_t child2; int result; check_return(0, avro_value_get_by_index (val1, i, &child1, NULL)); check_return(0, avro_value_get_by_index (val2, i, &child2, NULL)); result = avro_value_cmp_fast(&child1, &child2); if (result != 0) { return result; } } return cmp(count1, count2); } case AVRO_ENUM: { int v1; int v2; check_return(0, avro_value_get_enum(val1, &v1)); check_return(0, avro_value_get_enum(val2, &v2)); return cmp(v1, v2); } case AVRO_FIXED: { const void *buf1; const void *buf2; size_t size1; size_t size2; check_return(0, avro_value_get_fixed(val1, &buf1, &size1)); check_return(0, avro_value_get_fixed(val2, &buf2, &size2)); if (size1 != size2) { return -1; } return memcmp(buf1, buf2, size1); } case AVRO_MAP: { return -1; } case AVRO_RECORD: { size_t count1; check_return(0, avro_value_get_size(val1, &count1)); size_t i; for (i = 0; i < count1; i++) { avro_value_t child1; avro_value_t child2; int result; check_return(0, avro_value_get_by_index (val1, i, &child1, NULL)); check_return(0, avro_value_get_by_index (val2, i, &child2, NULL)); result = avro_value_cmp_fast(&child1, &child2); if (result != 0) { return result; } } return 0; } case AVRO_UNION: { int disc1; int disc2; check_return(0, avro_value_get_discriminant(val1, &disc1)); check_return(0, avro_value_get_discriminant(val2, &disc2)); if (disc1 == disc2) { avro_value_t branch1; avro_value_t branch2; check_return(0, avro_value_get_current_branch(val1, &branch1)); check_return(0, avro_value_get_current_branch(val2, &branch2)); return avro_value_cmp_fast(&branch1, &branch2); } else { return cmp(disc1, disc2); } } default: return 0; } }