static void testConfigDiff(void) { VBUCKET_CONFIG_HANDLE vb1 = vbucket_config_parse_file(configPath("config-diff1")); VBUCKET_CONFIG_HANDLE vb2 = vbucket_config_parse_file(configPath("config-diff2")); VBUCKET_CONFIG_DIFF *diff; assert(vb2); diff = vbucket_compare(vb1, vb2); assert(vb1); assert(diff); assert(diff->sequence_changed); assert(diff->n_vb_changes == 1); assert(strcmp(diff->servers_added[0], "server4:11211") == 0); assert(diff->servers_added[1] == NULL); assert(strcmp(diff->servers_removed[0], "server3:11211") == 0); assert(diff->servers_removed[1] == NULL); vbucket_free_diff(diff); vbucket_config_destroy(vb2); vb2 = vbucket_config_parse_file(configPath("config-diff3")); assert(vb2); diff = vbucket_compare(vb1, vb2); assert(diff); assert(diff->sequence_changed); assert(diff->n_vb_changes == -1); assert(diff->servers_added[0] == NULL); assert(strcmp(diff->servers_removed[0], "server3:11211") == 0); assert(diff->servers_removed[1] == NULL); }
/* Returns true if curr_version could be updated with next_version in * a low-impact stable manner (server-list is the same), allowing the * same connections to be reused. Or returns false if the delta was * too large for an in-place updating of curr_version with information * from next_version. * * The next_version may be destroyed in this call, and the caller * should afterwards only call mcs_free() on the next_version. */ bool lvb_stable_update(mcs_st *curr_version, mcs_st *next_version) { assert(curr_version->kind == MCS_KIND_LIBVBUCKET); assert(curr_version->data != NULL); assert(next_version->kind == MCS_KIND_LIBVBUCKET); assert(next_version->data != NULL); bool rv = false; VBUCKET_CONFIG_DIFF *diff = vbucket_compare((VBUCKET_CONFIG_HANDLE) curr_version->data, (VBUCKET_CONFIG_HANDLE) next_version->data); if (diff != NULL) { if (!diff->sequence_changed) { vbucket_config_destroy((VBUCKET_CONFIG_HANDLE) curr_version->data); curr_version->data = next_version->data; next_version->data = 0; rv = true; } vbucket_free_diff(diff); } return rv; }
static void testConfigUserPassword(void) { VBUCKET_CONFIG_HANDLE vb1; VBUCKET_CONFIG_HANDLE vb2; VBUCKET_CONFIG_DIFF *diff; vb1 = vbucket_config_parse_file(configPath("config-user-password1")); assert(vb1); assert(strcmp(vbucket_config_get_user(vb1), "theUser") == 0); assert(strcmp(vbucket_config_get_password(vb1), "thePassword") == 0); vb2 = vbucket_config_parse_file(configPath("config-user-password2")); assert(vb2); assert(strcmp(vbucket_config_get_user(vb2), "theUserIsDifferent") == 0); assert(strcmp(vbucket_config_get_password(vb2), "thePasswordIsDifferent") == 0); diff = vbucket_compare(vb1, vb2); assert(diff); assert(diff->sequence_changed); assert(diff->n_vb_changes == 0); assert(diff->servers_added[0] == NULL); assert(diff->servers_removed[0] == NULL); vbucket_free_diff(diff); diff = vbucket_compare(vb1, vb1); assert(diff); assert(diff->sequence_changed == 0); assert(diff->n_vb_changes == 0); assert(diff->servers_added[0] == NULL); assert(diff->servers_removed[0] == NULL); vbucket_free_diff(diff); vbucket_config_destroy(vb1); vbucket_config_destroy(vb2); }
static void testConfigDiffKetamaSame(void) { VBUCKET_CONFIG_HANDLE vb1 = vbucket_config_parse_file(configPath("ketama-eight-nodes")); VBUCKET_CONFIG_HANDLE vb2 = vbucket_config_parse_file(configPath("ketama-ordered-eight-nodes")); VBUCKET_CONFIG_DIFF *diff; assert(vb1); assert(vb2); diff = vbucket_compare(vb1, vb2); assert(diff); assert(diff->sequence_changed == 0); assert(diff->n_vb_changes == 0); assert(diff->servers_added[0] == NULL); assert(diff->servers_removed[0] == NULL); vbucket_free_diff(diff); vbucket_config_destroy(vb1); vbucket_config_destroy(vb2); }
static int is_new_config(lcb_t instance, VBUCKET_CONFIG_HANDLE oldc, VBUCKET_CONFIG_HANDLE newc) { VBUCKET_CONFIG_DIFF *diff; VBUCKET_CHANGE_STATUS chstatus = VBUCKET_NO_CHANGES; diff = vbucket_compare(oldc, newc); if (diff) { chstatus = vbucket_what_changed(diff); log_vbdiff(instance, diff); vbucket_free_diff(diff); } if (diff == NULL || chstatus == VBUCKET_NO_CHANGES) { lcb_log(LOGARGS(instance, DEBUG), "Ignoring config update. No server changes; DIFF=%p", (void*)diff); return 0; } return 1; }
static lcb_error_t set_next_config(struct htvb_st *vbs) { VBUCKET_CONFIG_HANDLE new_config = NULL; new_config = vbucket_config_create(); if (!new_config) { return LCB_CLIENT_ENOMEM; } if (vbucket_config_parse(new_config, LIBVBUCKET_SOURCE_MEMORY, vbs->input.base)) { vbucket_config_destroy(new_config); return LCB_PROTOCOL_ERROR; } if (vbs->config) { /** We have a previous configuration... */ VBUCKET_CHANGE_STATUS chstatus = VBUCKET_NO_CHANGES; VBUCKET_CONFIG_DIFF *diff = NULL; VBUCKET_CONFIG_HANDLE old_config = vbs->config->vbc; diff = vbucket_compare(old_config, new_config); if (diff) { chstatus = vbucket_what_changed(diff); vbucket_free_diff(diff); } if (chstatus == VBUCKET_NO_CHANGES) { vbs->config->cmpclock = gethrtime(); vbucket_config_destroy(new_config); return LCB_SUCCESS; } } if (vbs->config) { lcb_clconfig_decref(vbs->config); } vbs->config = lcb_clconfig_create(new_config, &vbs->input, LCB_CLCONFIG_HTTP); vbs->config->cmpclock = gethrtime(); vbs->generation++; return LCB_SUCCESS; }
static int load_cache(file_provider *provider) { lcb_string str; char line[1024]; lcb_ssize_t nr; int fail; FILE *fp = NULL; VBUCKET_CONFIG_HANDLE config = NULL; char *end; struct stat st; int status = -1; lcb_string_init(&str); if (provider->filename == NULL) { return -1; } fp = fopen(provider->filename, "r"); if (fp == NULL) { LOG(provider, ERROR, "Couldn't open filename"); return -1; } if (fstat(fileno(fp), &st)) { provider->last_errno = errno; goto GT_DONE; } if (provider->last_mtime == st.st_mtime) { LOG(provider, INFO, "Rejecting file. Modification time too old"); goto GT_DONE; } config = vbucket_config_create(); if (config == NULL) { goto GT_DONE; } lcb_string_init(&str); while ((nr = fread(line, 1, sizeof(line), fp)) > 0) { if (lcb_string_append(&str, line, nr)) { goto GT_DONE; } } if (ferror(fp)) { goto GT_DONE; } fclose(fp); fp = NULL; if (!str.nused) { status = -1; goto GT_DONE; } end = strstr(str.base, CONFIG_CACHE_MAGIC); if (end == NULL) { LOG(provider, ERROR, "Couldn't find magic in file"); remove(provider->filename); status = -1; goto GT_DONE; } fail = vbucket_config_parse(config, LIBVBUCKET_SOURCE_MEMORY, str.base); if (fail) { status = -1; LOG(provider, ERROR, "Couldn't parse configuration"); remove(provider->filename); goto GT_DONE; } if (vbucket_config_get_distribution_type(config) != VBUCKET_DISTRIBUTION_VBUCKET) { status = -1; LOG(provider, ERROR, "Not applying cached memcached config"); goto GT_DONE; } if (provider->config) { VBUCKET_CHANGE_STATUS chstatus; VBUCKET_CONFIG_DIFF *diff = vbucket_compare(provider->config->vbc, config); if (diff == NULL) { goto GT_DONE; } chstatus = vbucket_what_changed(diff); vbucket_free_diff(diff); if (chstatus == VBUCKET_NO_CHANGES) { goto GT_DONE; } } if (provider->config) { lcb_clconfig_decref(provider->config); } provider->config = lcb_clconfig_create(config, &str, LCB_CLCONFIG_FILE); provider->config->cmpclock = gethrtime(); provider->config->origin = provider->base.type; status = 0; config = NULL; GT_DONE: if (fp != NULL) { fclose(fp); } if (config != NULL) { vbucket_config_destroy(config); } lcb_string_release(&str); return status; }