/** * Callback function to use with INI-H. * @arg user Opaque user value. We use the statsite_config pointer * @arg section The INI seciton * @arg name The config name * @arg value The config value * @return 1 on success. */ static int config_callback(void* user, const char* section, const char* name, const char* value) { // Specially handle histogram sections if (strncasecmp("histogram", section, 9) == 0) { return histogram_callback(user, section, name, value); } // Ignore any non-statsite sections if (strcasecmp("statsite", section) != 0) { return 0; } // Cast the user handle statsite_config *config = (statsite_config*)user; // Switch on the config #define NAME_MATCH(param) (strcasecmp(param, name) == 0) // Handle the int cases if (NAME_MATCH("port")) { return value_to_int(value, &config->tcp_port); } else if (NAME_MATCH("tcp_port")) { return value_to_int(value, &config->tcp_port); } else if (NAME_MATCH("udp_port")) { return value_to_int(value, &config->udp_port); } else if (NAME_MATCH("flush_interval")) { return value_to_int(value, &config->flush_interval); } else if (NAME_MATCH("daemonize")) { return value_to_bool(value, &config->daemonize); } else if (NAME_MATCH("binary_stream")) { return value_to_bool(value, &config->binary_stream); // Handle the double cases } else if (NAME_MATCH("timer_eps")) { return value_to_double(value, &config->timer_eps); } else if (NAME_MATCH("set_eps")) { return value_to_double(value, &config->set_eps); // Copy the string values } else if (NAME_MATCH("log_level")) { config->log_level = strdup(value); } else if (NAME_MATCH("stream_cmd")) { config->stream_cmd = strdup(value); } else if (NAME_MATCH("pid_file")) { config->pid_file = strdup(value); } else if (NAME_MATCH("input_counter")) { config->input_counter = strdup(value); } else if (NAME_MATCH("bind_address")) { config->bind_address = strdup(value); // Unknown parameter? } else { // Log it, but ignore syslog(LOG_NOTICE, "Unrecognized config parameter: %s", value); } // Success return 1; }
kj_internal kj_bool vm_comp_lte(value_t const *lhs, value_t const *rhs) { switch (lhs->type) { case KJ_TYPE_NIL: return true; case KJ_TYPE_BOOL: return lhs->boolean <= value_to_int(rhs); case KJ_TYPE_INT: return lhs->integer <= value_to_int(rhs); case KJ_TYPE_REAL: return lhs->real <= value_to_real(rhs); case KJ_TYPE_STRING: return rhs->type == KJ_TYPE_STRING && (lhs->string->length < rhs->string->length || (lhs->string->length == rhs->string->length && memcmp(lhs->string->data, rhs->string->data, lhs->string->length) <= 0)); case KJ_TYPE_TABLE: return rhs->type == KJ_TYPE_TABLE && lhs->table <= rhs->table; default: assert(!"implement me"); } return false; }
kj_internal void vm_op_mul(vm_t *vm, value_t *dest, value_t const *lhs, value_t const *rhs) { switch (lhs->type) { case KJ_TYPE_STRING: { if (rhs->type != KJ_TYPE_INT && rhs->type != KJ_TYPE_REAL) goto error; kj_integer repetitions = value_to_int(rhs); if (repetitions < 0) { vm_throw(vm, "rhs value of string by integer multiplication must be non negative, it is " KJ_INTEGER_PRF ".", repetitions); } uint dest_length = (uint)(lhs->string->length * repetitions); value_t temp = { 0 }; value_new_string(&temp, vm->allocator, dest_length); /* copy lhs into dest 'rhs' times */ for (kj_integer i = 0; i < repetitions; ++i) { memcpy(temp.string->data + lhs->string->length * i, lhs->string->data, lhs->string->length); } temp.string->data[dest_length] = '\0'; value_destroy(dest, vm->allocator); *dest = temp; break; } DEFAULT_BINOP_CASES(*) } }
static Value _lib_char_code_at(VMState *vm, Value value) { Hash *args = value_to_ptr(value); CString *string = value_to_string(hash_find(args, 1)); int index = value_to_int(hash_find(args, 2)); if (index < 0 || index >= string->length) { error_f("Out of range when get char_at(%.*s, %d)", string->length, string->content, index); return value_undefined(); } return value_from_int(string->content[index]); }
static Value _lib_to_string(VMState *vm, Value value) { Hash *args = value_to_ptr(value); Value query_val = hash_find(args, 1); if (value_is_int(query_val)) { char buffer[30]; sprintf(buffer, "%d", value_to_int(query_val)); return cvm_get_cstring_value(vm, buffer); } else { return _lib_typeof(vm, value); } }
static Value _lib_char_at(VMState *vm, Value value) { Hash *args = value_to_ptr(value); CString *string = value_to_string(hash_find(args, 1)); int index = value_to_int(hash_find(args, 2)); if (index < 0 || index >= string->length) { error_f("Out of range when get char_at(%.*s, %d)", string->length, string->content, index); return value_undefined(); } char buffer[2]; buffer[0] = string->content[index]; buffer[1] = 0; return cvm_get_cstring_value(vm, buffer); }
/* * This function implements the "target = object[key]" syntax in the language. * The semantics depend on the type of target, but the idea is that the sub-element with specified * @key in @object will be put in in @target */ kj_internal void vm_get_property(vm_t *vm, value_t *target, value_t const *object, value_t const *key) { switch (object->type) { case KJ_TYPE_TABLE: value_set(target, vm->allocator, table_get(&object->table->table, key)); break; case KJ_TYPE_STRING: // #todo add short string optimization value_new_string(target, vm->allocator, 1); target->string->data[0] = object->string->data[value_to_int(key)]; target->string->data[1] = '\0'; break; default: vm_throw(vm, "invalid get operation performed on value of type %s.", VALUE_TYPE_STRING[object->type]); } }
static Value _lib_print(VMState *vm, Value value) { Hash *args = value_to_ptr(value); for (uintptr_t i = 1; i < hash_size(args); ++i) { Value val = hash_find(args, i); if (value_is_int(val)) { printf("%d", value_to_int(val)); } else { CString *string = value_to_string(val); printf("%.*s", string->length, string->content); } } return value_undefined(); }
/*-----------------------------------------------------------------------------------------------*/ kj_internal kj_bool vm_comp_eq(value_t const *lhs, value_t const *rhs) { switch (lhs->type) { case KJ_TYPE_NIL: return rhs->type == KJ_TYPE_NIL; case KJ_TYPE_BOOL: return rhs->type == KJ_TYPE_BOOL && lhs->boolean == rhs->boolean; case KJ_TYPE_INT: return rhs->type == KJ_TYPE_REAL ? lhs->integer == rhs->real : lhs->integer == value_to_int(rhs); case KJ_TYPE_REAL: return lhs->real == value_to_real(rhs); case KJ_TYPE_STRING: return rhs->type == KJ_TYPE_STRING && lhs->string->length == rhs->string->length && memcmp(lhs->string->data, rhs->string->data, lhs->string->length); case KJ_TYPE_TABLE: return rhs->type == KJ_TYPE_TABLE && lhs->table == rhs->table; default: assert(!"implement me"); } return false; }
/** * Callback function to use with INI-H. * @arg user Opaque user value. We use the statsite_config pointer * @arg section The INI seciton * @arg name The config name * @arg value The config value * @return 1 on success. */ static int config_callback(void* user, const char* section, const char* name, const char* value) { // Specially handle histogram sections if (strncasecmp("histogram", section, 9) == 0) { return histogram_callback(user, section, name, value); } if (strncasecmp("sink", section, 4) == 0) { return sink_callback(user, section, name, value); } // Ignore any non-statsite sections if (strcasecmp("statsite", section) != 0) { syslog(LOG_NOTICE, "Unknown values in section ignored: %s", section); return 0; } // Cast the user handle statsite_config *config = (statsite_config*)user; // Handle the int cases if (NAME_MATCH("port")) { return value_to_int(value, &config->tcp_port); } else if (NAME_MATCH("tcp_port")) { return value_to_int(value, &config->tcp_port); } else if (NAME_MATCH("udp_port")) { return value_to_int(value, &config->udp_port); } else if (NAME_MATCH("flush_interval")) { return value_to_int(value, &config->flush_interval); } else if (NAME_MATCH("parse_stdin")) { return value_to_bool(value, &config->parse_stdin); } else if (NAME_MATCH("daemonize")) { return value_to_bool(value, &config->daemonize); } else if (NAME_MATCH("use_type_prefix")) { return value_to_bool(value, &config->use_type_prefix); } else if (NAME_MATCH("extended_counters")) { return value_to_bool(value, &config->extended_counters); } else if (NAME_MATCH("prefix_binary_stream")) { return value_to_bool(value, &config->prefix_binary_stream); // Handle the double cases } else if (NAME_MATCH("timer_eps")) { return value_to_double(value, &config->timer_eps); } else if (NAME_MATCH("set_eps")) { return value_to_double(value, &config->set_eps); // Handle quantiles as a comma-separated list of doubles } else if (NAME_MATCH("quantiles")) { return value_to_list_of_doubles(value, &config->quantiles, &config->num_quantiles); // Copy the string values } else if (NAME_MATCH("log_level")) { config->log_level = strdup(value); } else if (NAME_MATCH("log_facility")) { config->log_facility = strdup(value); } else if (NAME_MATCH("pid_file")) { config->pid_file = strdup(value); } else if (NAME_MATCH("input_counter")) { config->input_counter = strdup(value); } else if (NAME_MATCH("bind_address")) { config->bind_address = strdup(value); } else if (NAME_MATCH("global_prefix")) { config->global_prefix = strdup(value); } else if (NAME_MATCH("counts_prefix")) { config->prefixes[COUNTER] = strdup(value); } else if (NAME_MATCH("gauges_prefix")) { config->prefixes[GAUGE] = strdup(value); } else if (NAME_MATCH("timers_prefix")) { config->prefixes[TIMER] = strdup(value); } else if (NAME_MATCH("sets_prefix")) { config->prefixes[SET] = strdup(value); } else if (NAME_MATCH("kv_prefix")) { config->prefixes[KEY_VAL] = strdup(value); // Copy the multi-case variables } else if (NAME_MATCH("log_facility")) { return name_to_facility(value, &config->syslog_log_facility); // Unknown parameter? } else { // Log it, but ignore syslog(LOG_NOTICE, "Unrecognized config parameter: %s", name); } // Success return 1; }
/** * Callback function to use with INIH for parsing sink configurations. * The sink type is currently encoded into the section name to * simplify instantiating the correct configuration type. */ static int sink_callback(void* user, const char* section, const char* name, const char* value) { statsite_config *all_config = (statsite_config*)user; /* The sink section does not match - lets commit since we're on to a new one now */ if (sink_in_progress && strcasecmp(sink_section, section)) { sink_commit(all_config); } /* Nothing in progress? Create it! */ if (!sink_in_progress) { if (!sink_section) sink_section = strdup(section); char* section_to_tokenize = strdup(section); char* tok = NULL; char* header = strtok_r(section_to_tokenize, "_", &tok); char* type = strtok_r(NULL, "_", &tok); char* name = strtok_r(NULL, "_", &tok); if (header == NULL || type == NULL || name == NULL) { free(section_to_tokenize); syslog(LOG_WARNING, "Sink section %s is not of the form \"sink_[type]_[name]\"", section); return 0; } /* Match various sink types to find their type */ if (strcasecmp(type, "stream") == 0) { sink_config_stream* config = calloc(1, sizeof(sink_config_stream)); sink_in_progress = (sink_config*)config; config->super.type = SINK_TYPE_STREAM; config->super.name = strdup(name); config->stream_cmd = DEFAULT_SINK.stream_cmd; } else if (strcasecmp(type, "http") == 0) { sink_config_http* config = malloc(sizeof(sink_config_http)); memcpy(config, &DEFAULT_HTTP_SINK, sizeof(sink_config_http)); sink_in_progress = (sink_config*)config; config->super.name = strdup(name); } else { free(section_to_tokenize); /* Unknown sink type - abort! */ syslog(LOG_WARNING, "Unknown sink type: %s for sink: %s", type, name); return 0; } free(section_to_tokenize); } switch(sink_in_progress->type) { case SINK_TYPE_STREAM: { sink_config_stream* config = (sink_config_stream*)sink_in_progress; if (NAME_MATCH("binary")) { return value_to_bool(value, &config->binary_stream); } else if (NAME_MATCH("command")) { config->stream_cmd = strdup(value); } else { syslog(LOG_NOTICE, "Unrecognized stream sink parameter: %s", name); return 0; } break; } case SINK_TYPE_HTTP: { sink_config_http* config = (sink_config_http*)sink_in_progress; if (NAME_MATCH("url")) { config->post_url = strdup(value); } else if (NAME_MATCH("metrics_name")) { config->metrics_name = strdup(value); } else if (NAME_MATCH("timestamp_name")) { config->timestamp_name = strdup(value); } else if (NAME_MATCH("timestamp_format")) { config->timestamp_format = strdup(value); } else if (NAME_MATCH("ciphers")) { config->ciphers = strdup(value); } else if (NAME_MATCH("oauth_key")) { config->oauth_key = strdup(value); } else if (NAME_MATCH("oauth_secret")) { config->oauth_secret = strdup(value); } else if (NAME_MATCH("oauth_token_url")) { config->oauth_token_url = strdup(value); } else if (NAME_MATCH("max_buffer_size")) { value_to_int(value, &config->max_buffer_size); } else if (NAME_MATCH("send_backoff_ms")) { value_to_int(value, &config->send_backoff_ms); } else { /* Attempt to locate keys * of the form param_PNAME */ char* param_tok = strdup(name); char* tok = NULL; char* header = strtok_r(param_tok, "_", &tok); char* param = strtok_r(NULL, "_", &tok); if (header == NULL || param == NULL || strcasecmp("param", header) != 0) { syslog(LOG_NOTICE, "Unrecognized http sink parameters: %s: %s", name, header); free(param_tok); return 0; } kv_config* last_kv = config->params; config->params = calloc(1, sizeof(kv_config)); config->params->k = strdup(param); config->params->v = strdup(value); config->params->next = last_kv; free(param_tok); } break; } default: syslog(LOG_WARNING, "Grevious state problem"); return 0; } return 1; }
/** * Callback function to use with INI-H. * @arg user Opaque user value. We use the hlld_config pointer * @arg section The INI seciton * @arg name The config name * @arg value The config value * @return 1 on success. */ static int config_callback(void* user, const char* section, const char* name, const char* value) { // Ignore any non-hlld sections if (strcasecmp("hlld", section) != 0) { return 0; } // Cast the user handle hlld_config *config = (hlld_config*)user; // Switch on the config #define NAME_MATCH(param) (strcasecmp(param, name) == 0) // Handle the int cases if (NAME_MATCH("port")) { return value_to_int(value, &config->tcp_port); } else if (NAME_MATCH("tcp_port")) { return value_to_int(value, &config->tcp_port); } else if (NAME_MATCH("udp_port")) { return value_to_int(value, &config->udp_port); } else if (NAME_MATCH("flush_interval")) { return value_to_int(value, &config->flush_interval); } else if (NAME_MATCH("cold_interval")) { return value_to_int(value, &config->cold_interval); } else if (NAME_MATCH("in_memory")) { return value_to_int(value, &config->in_memory); } else if (NAME_MATCH("use_mmap")) { return value_to_int(value, &config->use_mmap); } else if (NAME_MATCH("workers")) { return value_to_int(value, &config->worker_threads); } else if (NAME_MATCH("default_precision")) { int res = value_to_int(value, &config->default_precision); // Compute expected error given precision config->default_eps = hll_error_for_precision(config->default_precision); return res; // Handle the double cases } else if (NAME_MATCH("default_eps")) { int res = value_to_double(value, &config->default_eps); // Compute required precision given error config->default_precision = hll_precision_for_error(config->default_eps); // Compute error given precision. This is kinda strange but it is done // since its not possible to hit all epsilons perfectly, but we try to get // the eps provided to be the upper bound. This value is the actual eps. config->default_eps = hll_error_for_precision(config->default_precision); return res; // Copy the string values } else if (NAME_MATCH("data_dir")) { config->data_dir = strdup(value); } else if (NAME_MATCH("log_level")) { config->log_level = strdup(value); // Unknown parameter? } else { // Log it, but ignore syslog(LOG_NOTICE, "Unrecognized config parameter: %s", value); } // Success return 1; }
X(bool, "Booleans can be stored inline") \ X(ptr, "Boxed values should be heap-allocated and a pointer stored") \ X(value_type, "Value type should be not depend on whether or not the value is boxed") \ X(gray_bit, "Boxed values should maintain a gray bit") \ X(hash, "Value hashes should be well-distributed") \ X(hash_tuple, "Hashes from equal tuples should be equal") \ X(equal, "Only equal values should be equal") TEST(double) value_t x = value_from_double(42.101010); PT_ASSERT_EQ(value_to_double(x), 42.101010); END(double) TEST(fixnum) value_t x = value_from_int(322); PT_ASSERT_EQ(value_to_int(x), 322); END(fixnum) TEST(bool) value_t x = value_true(); PT_ASSERT(value_to_bool(x)); x = value_false(); PT_ASSERT(!value_to_bool(x)); END(bool) TEST(ptr) struct arena_handle *a = arena_new((yu_allocator *)&mctx); struct boxed_value *v = arena_alloc_val(a); value_t x = value_from_ptr(&v); PT_ASSERT_EQ(value_get_ptr(x), v); PT_ASSERT_EQ(boxed_value_owner(v), a);