示例#1
0
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;
}
示例#2
0
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);
}
示例#3
0
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;
}
示例#4
0
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;
}
示例#5
0
// 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);
}
示例#6
0
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);
}