/** * check if the entry exists in the database and what info * must be retrieved. */ int EntryProc_get_info_db( struct entry_proc_op_t *p_op, lmgr_t * lmgr ) { int rc = 0; int next_stage = -1; /* -1 = skip */ attr_mask_t attr_allow_cached = null_mask; attr_mask_t attr_need_fresh = null_mask; uint32_t status_scope = 0; /* status mask only */ attr_mask_t tmp; const pipeline_stage_t *stage_info = &entry_proc_pipeline[p_op->pipeline_stage]; /* check if entry is in policies scope */ add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true, &status_scope); /* XXX also retrieve needed attributes to check the scope? */ /* get diff attributes from DB and FS (to allow comparison) */ p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &diff_mask); tmp = attr_mask_and_not(&diff_mask, &p_op->fs_attrs.attr_mask); p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp); if (entry_proc_conf.detect_fake_mtime) attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_creation_time); attr_allow_cached = attrs_for_status_mask(status_scope, false); attr_need_fresh = attrs_for_status_mask(status_scope, true); /* XXX check if entry is in policy scope? */ /* what must be retrieved from DB: */ tmp = attr_mask_and_not(&attr_allow_cached, &p_op->fs_attrs.attr_mask); p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &tmp); /* no dircount for non-dirs */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type) && !strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR)) { attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_dircount); } /* no readlink for non symlinks */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type)) /* likely */ { if (!strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_LINK)) { attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_link); /* check if it is known */ /* no stripe for symlinks */ attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_info); attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_items); } else attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_link); } if (!attr_mask_is_null(p_op->db_attr_need)) { p_op->db_attrs.attr_mask = p_op->db_attr_need; rc = ListMgr_Get(lmgr, &p_op->entry_id, &p_op->db_attrs); if (rc == DB_SUCCESS) { p_op->db_exists = 1; } else if (rc == DB_NOT_EXISTS ) { p_op->db_exists = 0; ATTR_MASK_INIT( &p_op->db_attrs ); } else { /* ERROR */ DisplayLog(LVL_CRIT, ENTRYPROC_TAG, "Error %d retrieving entry "DFID" from DB: %s.", rc, PFID(&p_op->entry_id), lmgr_err2str(rc)); p_op->db_exists = 0; ATTR_MASK_INIT( &p_op->db_attrs ); } } else { p_op->db_exists = ListMgr_Exists( lmgr, &p_op->entry_id ); } /* get status for all policies with a matching scope */ add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true, &p_op->fs_attr_need.status); tmp = attr_mask_and_not(&attr_need_fresh, &p_op->fs_attrs.attr_mask); p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp); if ( !p_op->db_exists ) { /* new entry */ p_op->db_op_type = OP_TYPE_INSERT; /* set creation time if it was not set by scan module */ if (!ATTR_MASK_TEST(&p_op->fs_attrs, creation_time)) { ATTR_MASK_SET( &p_op->fs_attrs, creation_time ); ATTR( &p_op->fs_attrs, creation_time ) = time(NULL); /* XXX min(atime,mtime,ctime)? */ } #ifdef _LUSTRE if (ATTR_MASK_TEST(&p_op->fs_attrs, type) && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_FILE ) /* only if it was not retrieved during the scan */ && !(ATTR_MASK_TEST(&p_op->fs_attrs, stripe_info) && ATTR_MASK_TEST(&p_op->fs_attrs, stripe_items))) { attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_info); attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_items); } #endif /* readlink for symlinks (if not already known) */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type) && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_LINK) && !ATTR_MASK_TEST(&p_op->fs_attrs, link)) { attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_link); } else { attr_mask_unset_index(&p_op->fs_attr_need, ATTR_INDEX_link); } #ifdef ATTR_INDEX_status /** @FIXME RBHv3 drop old-style status reference */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type) #ifdef _LUSTRE_HSM && !strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_FILE )) #elif defined (_HSM_LITE) && (strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR ) != 0) && !p_op->extra_info.not_supp) #endif { p_op->fs_attr_need |= ATTR_MASK_status; #ifdef _HSM_LITE p_op->fs_attr_need |= (attr_need_fresh & ~p_op->fs_attrs.attr_mask); #endif } else {
/** * Main daemon routine */ int main(int argc, char **argv) { int c, i, option_index = 0; const char *bin; int rc; char err_msg[4096]; bool chgd = false; char badcfg[RBH_PATH_MAX]; char tag_name[256] = ""; bin = rh_basename(argv[0]); start_time = time(NULL); zero_options(&options); /* parse command line options */ while ((c = getopt_long(argc, argv, SHORT_OPT_STRING, option_tab, &option_index)) != -1) { switch (c) { case 's': options.partial_scan = 1; rh_strncpy(options.partial_scan_path, optarg, RBH_PATH_MAX); /* clean final slash */ if (FINAL_SLASH(options.partial_scan_path)) REMOVE_FINAL_SLASH(options.partial_scan_path); break; case 'd': if (parse_diff_mask(optarg, &options.diff_arg.diff_mask, err_msg)) { fprintf(stderr, "Invalid argument for --diff: %s\n", err_msg); exit(1); } break; case 'a': if (optarg) { if (!strcasecmp(optarg, "fs")) options.diff_arg.apply = APPLY_FS; else if (!strcasecmp(optarg, "db")) options.diff_arg.apply = APPLY_DB; else { fprintf(stderr, "Invalid argument for --apply: '%s' (fs or db expected)\n", optarg); exit(1); } } else options.diff_arg.apply = APPLY_DB; break; case 'D': options.flags |= RUNFLG_DRY_RUN; break; case 'f': rh_strncpy(options.config_file, optarg, MAX_OPT_LEN); break; #ifdef _HSM_LITE case 'b': options.diff_arg.recov_from_backend = 1; break; #endif #ifdef _HAVE_FID /* only for lustre 2.x */ case 'o': rh_strncpy(options.output_dir, optarg, MAX_OPT_LEN); break; #endif case 'l': { int log_level = str2debuglevel(optarg); if (log_level == -1) { fprintf(stderr, "Unsupported log level '%s'. CRIT, MAJOR, EVENT, VERB, DEBUG or FULL expected.\n", optarg); exit(1); } force_debug_level(log_level); break; } case 'h': display_help(bin); exit(0); break; case 'V': display_version(bin); exit(0); break; case ':': case '?': default: fprintf(stderr, "Run '%s --help' for more details.\n", bin); exit(1); break; } } /* check there is no extra arguments */ if (optind != argc) { fprintf(stderr, "Error: unexpected argument on command line: %s\n", argv[optind]); exit(1); } /* initialize internal resources (glib, llapi, internal resources...) */ rc = rbh_init_internals(); if (rc != 0) exit(rc); /* get default config file, if not specified */ if (SearchConfig(options.config_file, options.config_file, &chgd, badcfg, MAX_OPT_LEN) != 0) { fprintf(stderr, "No config file (or too many) found matching %s\n", badcfg); exit(2); } else if (chgd) { fprintf(stderr, "Using config file '%s'.\n", options.config_file); } if (rbh_cfg_load(MODULE_MASK_FS_SCAN | MODULE_MASK_ENTRY_PROCESSOR, options.config_file, err_msg)) { fprintf(stderr, "Error reading configuration file '%s': %s\n", options.config_file, err_msg); exit(1); } if (!log_config.force_debug_level) log_config.debug_level = LVL_CRIT; /* least messages as possible */ /* Set logging to stderr */ strcpy(log_config.log_file, "stderr"); strcpy(log_config.report_file, "stderr"); strcpy(log_config.alert_file, "stderr"); /* Initialize logging */ rc = InitializeLogs(bin); if (rc) { fprintf(stderr, "Error opening log files: rc=%d, errno=%d: %s\n", rc, errno, strerror(errno)); exit(rc); } /* Initialize filesystem access */ rc = InitFS(); if (rc) exit(rc); /* Initialize status managers */ rc = smi_init_all(options.flags); if (rc) exit(rc); /* Initialize list manager */ rc = ListMgr_Init(0); if (rc) { DisplayLog(LVL_CRIT, DIFF_TAG, "Error initializing list manager: %s (%d)", lmgr_err2str(rc), rc); exit(rc); } else DisplayLog(LVL_VERB, DIFF_TAG, "ListManager successfully initialized"); if (CheckLastFS() != 0) exit(1); if (attr_mask_is_null(options.diff_arg.diff_mask)) { /* parse "all" */ char tmpstr[] = "all"; rc = parse_diff_mask(tmpstr, &options.diff_arg.diff_mask, err_msg); if (rc) { DisplayLog(LVL_CRIT, DIFF_TAG, "unexpected error parsing diff mask: %s", err_msg); exit(1); } } options.diff_arg.diff_mask = translate_all_status_mask(options.diff_arg.diff_mask); #ifdef LUSTRE_DUMP_FILES if (options.diff_arg.apply == APPLY_FS && !(options.flags & RUNFLG_DRY_RUN)) { /* open the file to write LOV EA and FID remapping */ if (!EMPTY_STRING(options.output_dir)) { char fname[RBH_PATH_MAX]; if (mkdir(options.output_dir, 0700) && (errno != EEXIST)) { DisplayLog(LVL_CRIT, DIFF_TAG, "Failed to create directory %s: %s", options.output_dir, strerror(errno)); exit(1); } snprintf(fname, RBH_PATH_MAX - 1, "%s/" LOVEA_FNAME, options.output_dir); options.diff_arg.lovea_file = fopen(fname, "w"); if (options.diff_arg.lovea_file == NULL) { DisplayLog(LVL_CRIT, DIFF_TAG, "Failed to open %s for writing: %s", fname, strerror(errno)); exit(1); } snprintf(fname, RBH_PATH_MAX - 1, "%s/" FIDREMAP_FNAME, options.output_dir); options.diff_arg.fid_remap_file = fopen(fname, "w"); if (options.diff_arg.fid_remap_file == NULL) { DisplayLog(LVL_CRIT, DIFF_TAG, "Failed to open %s for writing: %s", fname, strerror(errno)); exit(1); } } } #endif /* if no DB apply action is specified, can't use md_update field for * checking removed entries. So, create a special tag for that. */ if ((options.diff_arg.apply != APPLY_DB) || (options.flags & RUNFLG_DRY_RUN)) { fprintf(stderr, "Preparing diff table...\n"); /* create a connexion to the DB. this is safe to use the global lmgr var * as statistics thread is not running */ if (!ensure_db_access()) exit(1); /* create a tag to clear entries after the scan */ /* There could be several diff running in parallel, * so set a suffix to avoid conflicts */ sprintf(tag_name, "DIFF_%u", (unsigned int)getpid()); options.diff_arg.db_tag = tag_name; /* add filter for partial scan */ if (options.partial_scan) { lmgr_filter_t filter; filter_value_t val; lmgr_simple_filter_init(&filter); char tmp[RBH_PATH_MAX]; strcpy(tmp, options.partial_scan_path); strcat(tmp, "/*"); val.value.val_str = tmp; lmgr_simple_filter_add(&filter, ATTR_INDEX_fullpath, LIKE, val, 0); rc = ListMgr_CreateTag(&lmgr, tag_name, &filter, false); lmgr_simple_filter_free(&filter); } else rc = ListMgr_CreateTag(&lmgr, tag_name, NULL, false); if (rc) exit(rc); } /* Initialise Pipeline */ rc = EntryProcessor_Init(DIFF_PIPELINE, options.flags, &options.diff_arg); if (rc) { DisplayLog(LVL_CRIT, DIFF_TAG, "Error %d initializing EntryProcessor pipeline", rc); goto clean_tag; } else DisplayLog(LVL_VERB, DIFF_TAG, "EntryProcessor successfully initialized"); fprintf(stderr, "Starting scan\n"); /* print header to indicate the content of diff * #<diff cmd> * ---fs[=/subdir] * +++db */ for (i = 0; i < argc; i++) printf("%s%s", i == 0 ? "# " : " ", argv[i]); printf("\n"); if (options.diff_arg.apply == APPLY_FS) { if (options.partial_scan) printf("---fs=%s\n", options.partial_scan_path); else printf("---fs\n"); printf("+++db\n"); } else { printf("---db\n"); if (options.partial_scan) printf("+++fs=%s\n", options.partial_scan_path); else printf("+++fs\n"); } /* Start FS scan */ if (options.partial_scan) rc = FSScan_Start(options.flags, options.partial_scan_path); else rc = FSScan_Start(options.flags, NULL); if (rc) { DisplayLog(LVL_CRIT, DIFF_TAG, "Error %d initializing FS Scan module", rc); goto clean_tag; } else DisplayLog(LVL_VERB, DIFF_TAG, "FS Scan module successfully initialized"); /* Flush logs now, to have a trace in the logs */ FlushLogs(); /* both pipeline and scan are now running, can now trap events and * display stats */ /* create signal handling thread */ rc = pthread_create(&sig_thr, NULL, signal_handler_thr, NULL); if (rc) { DisplayLog(LVL_CRIT, DIFF_TAG, "Error starting signal handler thread: %s", strerror(errno)); goto clean_tag; } else DisplayLog(LVL_VERB, DIFF_TAG, "Signal handler thread started successfully"); pthread_create(&stat_thread, NULL, stats_thr, NULL); /* wait for FS scan to end */ FSScan_Wait(); DisplayLog(LVL_MAJOR, DIFF_TAG, "FS Scan finished"); /* Pipeline must be flushed */ EntryProcessor_Terminate(true); #ifdef LUSTRE_DUMP_FILES /* flush the lovea file */ if (options.diff_arg.lovea_file) { fprintf(stderr, " > LOV EA information written to %s/" LOVEA_FNAME "\n", options.output_dir); fclose(options.diff_arg.lovea_file); } if (options.diff_arg.fid_remap_file) { fprintf(stderr, " > FID remapping written to %s/" FIDREMAP_FNAME "\n", options.output_dir); fclose(options.diff_arg.fid_remap_file); } #endif fprintf(stderr, "End of scan\n"); DisplayLog(LVL_MAJOR, DIFF_TAG, "All tasks done! Exiting."); rc = 0; clean_tag: /* destroy the tag before exit */ if (options.diff_arg.db_tag != NULL && ensure_db_access()) { fprintf(stderr, "Cleaning diff table...\n"); ListMgr_DestroyTag(&lmgr, options.diff_arg.db_tag); } exit(rc); return rc; /* for compiler */ }
/** * Get the list of children of a given parent (or list of parents). * \param parent_list [in] list of parents to get the child of * \param parent_count [in] number of ids in parent list * \param attr_mask [in] required attributes for children * \param child_id_list [out] ptr to array of child ids * \param child_attr_list [out] ptr to array of child attrs * \param child_count [out] number of returned children */ int ListMgr_GetChild(lmgr_t *p_mgr, const lmgr_filter_t *p_filter, const wagon_t *parent_list, unsigned int parent_count, attr_mask_t attr_mask, wagon_t **child_id_list, attr_set_t **child_attr_list, unsigned int *child_count) { result_handle_t result; char *path = NULL; int path_len; int rc, i; GString *req = NULL; GString *fields = NULL; GString *from = NULL; GString *where = NULL; struct field_count field_cnt = {0}; struct field_count filter_cnt = {0}; table_enum query_tab = T_DNAMES; bool distinct = false; int retry_status; /* XXX: querying children from several parent cannot work, since * we need to get the paths of the children. Or we could do a * lookup into parent_list to find the right one. In the meantime, * try not to mess up the code. */ if (unlikely(parent_count != 1)) RBH_BUG("cannot get children for several parent simultaneously"); /* always request for name to build fullpath in wagon */ attr_mask_set_index(&attr_mask, ATTR_INDEX_name); fields = g_string_new(NULL); /* append fields for all tables */ if (!attr_mask_is_null(attr_mask)) { /* retrieve source info for generated fields */ add_source_fields_for_gen(&attr_mask.std); field_cnt.nb_names = attrmask2fieldlist(fields, attr_mask, T_DNAMES, DNAMES_TABLE".", "", AOF_LEADING_SEP); field_cnt.nb_main = attrmask2fieldlist(fields, attr_mask, T_MAIN, MAIN_TABLE".", "", AOF_LEADING_SEP); field_cnt.nb_annex = attrmask2fieldlist(fields, attr_mask, T_ANNEX, ANNEX_TABLE".", "", AOF_LEADING_SEP); } else { /* no returned attrs */ if (child_attr_list != NULL) *child_attr_list = NULL; } where = g_string_new(NULL); /* starts with condition on parent */ rc = append_parent_cond(p_mgr, where, parent_list, parent_count, DNAMES_TABLE"."); if (rc != DB_SUCCESS) goto free_str; /* check filters on other tables */ if (!no_filter(p_filter)) { if (unlikely(dir_filter(p_mgr, NULL, p_filter, NULL, NULL) != FILTERDIR_NONE)) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Directory filter not supported in %s()", __func__); rc = DB_NOT_SUPPORTED; goto free_str; } else if (unlikely(func_filter(p_mgr, NULL, p_filter, T_MAIN, 0))) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Function filter not supported in %s()", __func__); rc = DB_NOT_SUPPORTED; goto free_str; } /* There is always a filter on T_DNAMES, which is the parent condition. * Look for optional filters. */ filter_where(p_mgr, p_filter, &filter_cnt, where, AOF_LEADING_SEP | AOF_SKIP_NAME); /** @FIXME process other filters on NAMES */ } from = g_string_new(DNAMES_TABLE); /* add filter_count + field_count to build the FROM clause. * Preserve field count which is needed to interpret the result. */ filter_cnt.nb_main += field_cnt.nb_main; filter_cnt.nb_annex += field_cnt.nb_annex; filter_cnt.nb_names += field_cnt.nb_names; /* query tab is DNAMES, skip_name=true, is_first_tab=T_DNAMES */ filter_from(p_mgr, &filter_cnt, from, &query_tab, &distinct, AOF_LEADING_SEP | AOF_SKIP_NAME); /* request is always on the DNAMES table (which contains [parent_id, id] relationship */ if (distinct) req = g_string_new("SELECT DISTINCT("DNAMES_TABLE".id) as id"); else req = g_string_new("SELECT "DNAMES_TABLE".id as id"); /* build the whole request */ g_string_append_printf(req, "%s FROM %s WHERE %s", fields->str, from->str, where->str); retry: rc = db_exec_sql(&p_mgr->conn, req->str, &result); retry_status = lmgr_delayed_retry(p_mgr, rc); if (retry_status == 1) goto retry; else if (retry_status == 2) { rc = DB_RBH_SIG_SHUTDOWN; goto free_str; } else if (rc) goto free_str; /* copy result to output structures */ *child_count = db_result_nb_records(&p_mgr->conn, &result); /* allocate entry_id array */ *child_id_list = MemCalloc(*child_count, sizeof(wagon_t)); if (*child_id_list == NULL) { rc = DB_NO_MEMORY; goto free_str; } if (child_attr_list) { *child_attr_list = MemCalloc(*child_count, sizeof(attr_set_t)); if (*child_attr_list == NULL) { rc = DB_NO_MEMORY; goto array_free; } } /* Allocate a string long enough to contain the parent path and a * child name. */ path_len = strlen(parent_list[0].fullname) + RBH_NAME_MAX + 2; path = malloc(path_len); if (!path) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Can't alloc enough memory (%d bytes)", path_len); rc = DB_NO_MEMORY; goto array_free; } for (i = 0; i < *child_count; i++) { char *res[128]; /* 128 fields per record is large enough */ rc = db_next_record(&p_mgr->conn, &result, res, sizeof(res)/sizeof(*res)); if (rc) goto array_free; /* copy id to array */ pk2entry_id(p_mgr, res[0], &((*child_id_list)[i].id)); /* copy attributes to array */ if (child_attr_list) { unsigned int shift = 1; /* first was NAMES.id */ (*child_attr_list)[i].attr_mask = attr_mask; /* first id, then dnames attrs, then main attrs, then annex attrs */ if (field_cnt.nb_names > 0) { /* shift of 1 for id */ rc = result2attrset(T_DNAMES, res + shift, field_cnt.nb_names, &((*child_attr_list)[i])); if (rc) goto array_free; shift += field_cnt.nb_names; } if (field_cnt.nb_main > 0) { /* first id, then main attrs, then annex attrs */ /* shift of 1 for id */ rc = result2attrset(T_MAIN, res + shift, field_cnt.nb_main, &((*child_attr_list)[i])); if (rc) goto array_free; shift += field_cnt.nb_main; } if (field_cnt.nb_annex > 0) { /* shift of main_attrs count */ rc = result2attrset(T_ANNEX, res + shift, field_cnt.nb_annex, &((*child_attr_list)[i])); if (rc) goto array_free; shift += field_cnt.nb_annex; } #ifdef _LUSTRE if (stripe_fields(attr_mask)) { if (get_stripe_info(p_mgr, res[0], &ATTR(&(*child_attr_list)[i], stripe_info), &ATTR(&(*child_attr_list)[i], stripe_items))) { ATTR_MASK_UNSET(&(*child_attr_list)[i], stripe_info); ATTR_MASK_UNSET(&(*child_attr_list)[i], stripe_items); } } #endif generate_fields(&((*child_attr_list)[i])); /* Note: path is properly sized already to not overflow. */ snprintf(path, path_len, "%s/%s", parent_list[0].fullname, (*child_attr_list)[i].attr_values.name); (*child_id_list)[i].fullname = strdup(path); } } if (path) free(path); db_result_free(&p_mgr->conn, &result); g_string_free(req, TRUE); g_string_free(fields, TRUE); g_string_free(from, TRUE); g_string_free(where, TRUE); return 0; array_free: if (path) free(path); if (child_attr_list && *child_attr_list) { MemFree(*child_attr_list); *child_attr_list = NULL; } MemFree(*child_id_list); *child_id_list = NULL; free_str: g_string_free(req, TRUE); g_string_free(fields, TRUE); g_string_free(from, TRUE); g_string_free(where, TRUE); return rc; }
int batch_insert_stripe_info(lmgr_t *p_mgr, pktype *pklist, int *validators, attr_set_t **p_attrs, unsigned int count, bool update_if_exists) { bool first; int i, rc = 0; int total_si; GString *req = g_string_new(""); attr_mask_t tmp_mask = { ATTR_MASK_stripe_info, 0, 0LL }; if (!attr_mask_is_null(sum_masks(p_attrs, count, tmp_mask))) { /* build batch request for STRIPE_INFO table */ g_string_assign(req, "INSERT INTO " STRIPE_INFO_TABLE " (" STRIPE_INFO_FIELDS ") VALUES "); first = true; for (i = 0; i < count; i++) { /* no request if the entry has no stripe info */ if (!ATTR_MASK_TEST(p_attrs[i], stripe_info)) continue; g_string_append_printf(req, "%s(" DPK ",%d,%u,%u,'%s')", first ? "" : ",", pklist[i], validators[i], ATTR(p_attrs[i], stripe_info).stripe_count, (unsigned int)ATTR(p_attrs[i], stripe_info).stripe_size, ATTR(p_attrs[i], stripe_info).pool_name); first = false; } if (update_if_exists) /* append "on duplicate key ..." */ g_string_append(req, " ON DUPLICATE KEY UPDATE " STRIPE_INFO_SET_VALUES); if (!first) { /* do nothing if no entry had stripe info */ rc = db_exec_sql(&p_mgr->conn, req->str, NULL); if (rc) goto out; } /* reset the string */ g_string_assign(req, ""); } /* Stripe items more tricky because we want to delete previous items * on update. */ /* If update_if_exists is false, insert them all as a batch. * For the update case, remove previous items before bluk insert. */ if (update_if_exists) { for (i = 0; i < count; i++) { /* no request if the entry has no stripe items */ if (!ATTR_MASK_TEST(p_attrs[i], stripe_items)) continue; g_string_printf(req, "DELETE FROM " STRIPE_ITEMS_TABLE " WHERE id=" DPK, pklist[i]); rc = db_exec_sql(&p_mgr->conn, req->str, NULL); if (rc) goto out; } } /* bulk insert stripe items (if any is set) */ tmp_mask.std = ATTR_MASK_stripe_items; if (attr_mask_is_null(sum_masks(p_attrs, count, tmp_mask))) goto out; total_si = 0; first = true; g_string_assign(req, "INSERT INTO " STRIPE_ITEMS_TABLE " (" STRIPE_ITEMS_FIELDS ") VALUES "); /* loop on all entries and all stripe items */ for (i = 0; i < count; i++) { int s; const stripe_items_t *p_items; /* skip the entry if it has no stripe items */ if (!ATTR_MASK_TEST(p_attrs[i], stripe_items)) continue; p_items = &ATTR(p_attrs[i], stripe_items); for (s = 0; s < p_items->count; s++) { char buff[2 * STRIPE_DETAIL_SZ + 1]; total_si++; if (buf2hex (buff, sizeof(buff), (unsigned char *)(&p_items->stripe[s].ost_gen), STRIPE_DETAIL_SZ) < 0) { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Buffer too small to store details stripe info"); memset(buff, 0, sizeof(buff)); } g_string_append_printf(req, "%s(" DPK ",%u,%u,x'%s')", first && (s == 0) ? "" : ",", pklist[i], s, p_items->stripe[s].ost_idx, buff); first = false; } } /* only execute it if there was some stripe items */ if (total_si > 0) rc = db_exec_sql(&p_mgr->conn, req->str, NULL); out: g_string_free(req, TRUE); return rc; }