static uint8_t* as_admin_write_field_header(uint8_t* p, uint8_t id, int size) { *(int*)p = cf_swap_to_be32(size+1); p += 4; *p++ = id; return p; }
as_status as_command_execute(as_cluster* cluster, as_error * err, as_command_node* cn, uint8_t* command, size_t command_len, uint32_t timeout_ms, uint32_t retry, as_parse_results_fn parse_results_fn, void* parse_results_data ) { uint64_t deadline_ms = as_socket_deadline(timeout_ms); uint32_t sleep_between_retries_ms = 0; uint32_t failed_nodes = 0; uint32_t failed_conns = 0; uint32_t iterations = 0; bool release_node; // Execute command until successful, timed out or maximum iterations have been reached. while (true) { as_node* node; if (cn->node) { node = cn->node; release_node = false; } else { node = as_node_get(cluster, cn->ns, cn->digest, cn->write, cn->replica); release_node = true; } if (!node) { failed_nodes++; sleep_between_retries_ms = 10; goto Retry; } int fd; as_status status = as_node_get_connection(err, node, deadline_ms, &fd); if (status) { if (release_node) { as_node_release(node); } failed_conns++; sleep_between_retries_ms = 1; goto Retry; } // Send command. status = as_socket_write_deadline(err, fd, command, command_len, deadline_ms); if (status) { // Socket errors are considered temporary anomalies. Retry. // Close socket to flush out possible garbage. Do not put back in pool. as_close(fd); if (release_node) { as_node_release(node); } sleep_between_retries_ms = 0; goto Retry; } // Parse results returned by server. status = parse_results_fn(err, fd, deadline_ms, parse_results_data); if (status == AEROSPIKE_OK) { // Reset error code if retry had occurred. if (iterations > 0) { as_error_reset(err); } } else { switch (status) { // Retry on timeout. case AEROSPIKE_ERR_TIMEOUT: as_close(fd); if (release_node) { as_node_release(node); } sleep_between_retries_ms = 0; goto Retry; // Close socket on errors that can leave unread data in socket. case AEROSPIKE_ERR_QUERY_ABORTED: case AEROSPIKE_ERR_SCAN_ABORTED: case AEROSPIKE_ERR_CLIENT_ABORT: case AEROSPIKE_ERR_CLIENT: as_close(fd); if (release_node) { as_node_release(node); } err->code = status; return status; default: err->code = status; break; } } // Put connection back in pool. as_node_put_connection(node, fd, cluster->conn_queue_size); // Release resources. if (release_node) { as_node_release(node); } return status; Retry: // Check if max retries reached. if (++iterations > retry) { break; } // Check for client timeout. if (deadline_ms > 0) { int remaining_ms = (int)(deadline_ms - cf_getms() - sleep_between_retries_ms); if (remaining_ms <= 0) { break; } // Reset timeout in send buffer (destined for server). *(uint32_t*)(command + 22) = cf_swap_to_be32(remaining_ms); } if (sleep_between_retries_ms > 0) { // Sleep before trying again. usleep(sleep_between_retries_ms * 1000); } } return as_error_update(err, AEROSPIKE_ERR_TIMEOUT, "Client timeout: timeout=%d iterations=%u failedNodes=%u failedConns=%u", timeout_ms, iterations, failed_nodes, failed_conns); }
uint8_t* as_command_write_bin(uint8_t* begin, uint8_t operation_type, const as_bin* bin, as_buffer* buffer) { uint8_t* p = begin + AS_OPERATION_HEADER_SIZE; const char* name = bin->name; // Copy string, but do not transfer null byte. while (*name) { *p++ = *name++; } uint8_t name_len = p - begin - AS_OPERATION_HEADER_SIZE; as_val* val = (as_val*)bin->valuep; uint32_t val_len; uint8_t val_type; switch (val->type) { default: case AS_NIL: { val_len = 0; val_type = AS_BYTES_UNDEF; break; } case AS_INTEGER: { as_integer* v = as_integer_fromval(val); *(uint64_t*)p = cf_swap_to_be64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_INTEGER; break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); *(double*)p = cf_swap_to_big_float64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_DOUBLE; break; } case AS_STRING: { as_string* v = as_string_fromval(val); // v->len should have been already set by as_command_value_size(). memcpy(p, v->value, v->len); p += v->len; val_len = (uint32_t)v->len; val_type = AS_BYTES_STRING; break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); memcpy(p, v->value, v->size); p += v->size; val_len = v->size; // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...). // Otherwise, the particle type will be reassigned to a non-blob which causes a // mismatch between type and value. val_type = v->type; break; } case AS_LIST: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_LIST; break; } case AS_MAP: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_MAP; break; } } *(uint32_t*)begin = cf_swap_to_be32(name_len + val_len + 4); begin += 4; *begin++ = operation_type; *begin++ = val_type; *begin++ = 0; *begin++ = name_len; return p; }
uint8_t* as_command_write_header(uint8_t* cmd, uint8_t read_attr, uint8_t write_attr, as_policy_commit_level commit_level, as_policy_consistency_level consistency, as_policy_exists exists, as_policy_gen gen_policy, uint32_t gen, uint32_t ttl, uint32_t timeout_ms, uint16_t n_fields, uint16_t n_bins) { uint32_t generation = 0; uint8_t info_attr = 0; switch (exists) { case AS_POLICY_EXISTS_IGNORE: break; case AS_POLICY_EXISTS_UPDATE: info_attr |= AS_MSG_INFO3_UPDATE_ONLY; break; case AS_POLICY_EXISTS_CREATE_OR_REPLACE: info_attr |= AS_MSG_INFO3_CREATE_OR_REPLACE; break; case AS_POLICY_EXISTS_REPLACE: info_attr |= AS_MSG_INFO3_REPLACE_ONLY; break; case AS_POLICY_EXISTS_CREATE: write_attr |= AS_MSG_INFO2_CREATE_ONLY; break; } switch (gen_policy) { case AS_POLICY_GEN_IGNORE: break; case AS_POLICY_GEN_EQ: generation = gen; write_attr |= AS_MSG_INFO2_GENERATION; break; case AS_POLICY_GEN_GT: generation = gen; write_attr |= AS_MSG_INFO2_GENERATION_GT; break; default: break; } if (commit_level == AS_POLICY_COMMIT_LEVEL_MASTER) { info_attr |= AS_MSG_INFO3_COMMIT_MASTER; } if (consistency == AS_POLICY_CONSISTENCY_LEVEL_ALL) { read_attr |= AS_MSG_INFO1_CONSISTENCY_ALL; } cmd[8] = 22; cmd[9] = read_attr; cmd[10] = write_attr; cmd[11] = info_attr; *(uint16_t*)&cmd[12] = 0; *(uint32_t*)&cmd[14] = cf_swap_to_be32(generation); *(uint32_t*)&cmd[18] = cf_swap_to_be32(ttl); *(uint32_t*)&cmd[22] = cf_swap_to_be32(timeout_ms); *(uint16_t*)&cmd[26] = cf_swap_to_be16(n_fields); *(uint16_t*)&cmd[28] = cf_swap_to_be16(n_bins); return cmd + AS_HEADER_SIZE; }
// Byte swap field from current machine byte order to network byte order (big endian). void cl_msg_swap_field_to_be(cl_msg_field *mf) { mf->field_sz = cf_swap_to_be32(mf->field_sz); }
uint8_t* as_command_write_bin(uint8_t* begin, uint8_t operation_type, const as_bin* bin, as_buffer* buffer) { uint8_t* p = begin + AS_OPERATION_HEADER_SIZE; const char* name = bin->name; // Copy string, but do not transfer null byte. while (*name) { *p++ = *name++; } uint8_t name_len = p - begin - AS_OPERATION_HEADER_SIZE; as_val* val = (as_val*)bin->valuep; uint32_t val_len; uint8_t val_type; switch (val->type) { default: case AS_NIL: { val_len = 0; val_type = AS_BYTES_UNDEF; break; } case AS_INTEGER: { as_integer* v = as_integer_fromval(val); *(uint64_t*)p = cf_swap_to_be64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_INTEGER; break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); *(double*)p = cf_swap_to_big_float64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_DOUBLE; break; } case AS_STRING: { as_string* v = as_string_fromval(val); // v->len should have been already set by as_command_value_size(). memcpy(p, v->value, v->len); p += v->len; val_len = (uint32_t)v->len; val_type = AS_BYTES_STRING; break; } case AS_GEOJSON: { // We send a cellid placeholder so we can fill in points // in place on the server w/o changing object size. as_geojson* v = as_geojson_fromval(val); // v->len should have been already set by as_command_value_size(). // as_particle_geojson_mem::flags *p++ = 0; // as_particle_geojson_mem::ncells *(uint16_t *) p = cf_swap_to_be16(0); p += sizeof(uint16_t); // placeholder cellid // THIS LOOP EXECUTES 0 TIMES (still, it belongs here ...) for (int ii = 0; ii < 0; ++ii) { *(uint64_t *) p = cf_swap_to_be64(0); p += sizeof(uint64_t); } // json data itself memcpy(p, v->value, v->len); p += v->len; val_len = (uint32_t)(1 + 2 + (0 * 8) + v->len); val_type = AS_BYTES_GEOJSON; break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); memcpy(p, v->value, v->size); p += v->size; val_len = v->size; // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...). // Otherwise, the particle type will be reassigned to a non-blob which causes a // mismatch between type and value. val_type = v->type; break; } case AS_LIST: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_LIST; cf_free(buffer->data); break; } case AS_MAP: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_MAP; cf_free(buffer->data); break; } } *(uint32_t*)begin = cf_swap_to_be32(name_len + val_len + 4); begin += 4; *begin++ = operation_type; *begin++ = val_type; *begin++ = 0; *begin++ = name_len; return p; }
static size_t as_scan_command_init(uint8_t* cmd, const as_policy_scan* policy, const as_scan* scan, uint64_t task_id, uint16_t n_fields, as_buffer* argbuffer, uint32_t predexp_size) { uint8_t* p; if (scan->apply_each.function[0]) { p = as_command_write_header(cmd, AS_MSG_INFO1_READ, AS_MSG_INFO2_WRITE, 0, AS_POLICY_COMMIT_LEVEL_ALL, AS_POLICY_EXISTS_IGNORE, AS_POLICY_GEN_IGNORE, 0, 0, policy->base.total_timeout, n_fields, 0, policy->durable_delete); } else { uint8_t read_attr = (scan->no_bins)? AS_MSG_INFO1_READ | AS_MSG_INFO1_GET_NOBINDATA : AS_MSG_INFO1_READ; p = as_command_write_header_read(cmd, read_attr, AS_POLICY_READ_MODE_AP_ONE, AS_POLICY_READ_MODE_SC_SESSION, policy->base.total_timeout, n_fields, scan->select.size); } if (scan->ns[0]) { p = as_command_write_field_string(p, AS_FIELD_NAMESPACE, scan->ns); } if (scan->set[0]) { p = as_command_write_field_string(p, AS_FIELD_SETNAME, scan->set); } // Write scan options p = as_command_write_field_header(p, AS_FIELD_SCAN_OPTIONS, 2); uint8_t priority = scan->priority << 4; if (policy->fail_on_cluster_change) { priority |= 0x08; } *p++ = priority; *p++ = scan->percent; // Write socket timeout. p = as_command_write_field_header(p, AS_FIELD_SCAN_TIMEOUT, sizeof(uint32_t)); *(uint32_t*)p = cf_swap_to_be32(policy->base.socket_timeout); p += sizeof(uint32_t); // Write taskId field p = as_command_write_field_uint64(p, AS_FIELD_TASK_ID, task_id); // Write background function if (scan->apply_each.function[0]) { p = as_command_write_field_header(p, AS_FIELD_UDF_OP, 1); *p++ = 2; p = as_command_write_field_string(p, AS_FIELD_UDF_PACKAGE_NAME, scan->apply_each.module); p = as_command_write_field_string(p, AS_FIELD_UDF_FUNCTION, scan->apply_each.function); p = as_command_write_field_buffer(p, AS_FIELD_UDF_ARGLIST, argbuffer); } as_buffer_destroy(argbuffer); // Write predicate expressions. if (scan->predexp.size > 0) { p = as_command_write_field_header(p, AS_FIELD_PREDEXP, predexp_size); for (uint16_t ii = 0; ii < scan->predexp.size; ++ii) { as_predexp_base * bp = scan->predexp.entries[ii]; p = (*bp->write_fn)(bp, p); } } if (scan->select.size > 0) { for (uint16_t i = 0; i < scan->select.size; i++) { p = as_command_write_bin_name(p, scan->select.entries[i]); } } return as_command_write_end(cmd, p); }