int ListMgr_Insert(lmgr_t *p_mgr, entry_id_t *p_id, attr_set_t *p_info, int update_if_exists) { int rc; char buff[4096]; /* retry the whole transaction when the error is retryable */ retry: rc = lmgr_begin(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return rc; rc = listmgr_batch_insert_no_tx(p_mgr, &p_id, &p_info, 1, update_if_exists); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) { lmgr_rollback(p_mgr); DisplayLog(LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg(&p_mgr->conn, buff, 4096)); return rc; } rc = lmgr_commit(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* success, count it */ if (!rc) p_mgr->nbop[OPIDX_INSERT]++; return rc; }
/** * Insert a batch of entries into the database. * All entries must have the same attr mask. */ int ListMgr_BatchInsert(lmgr_t * p_mgr, entry_id_t ** p_ids, attr_set_t ** p_attrs, unsigned int count, int update_if_exists) { int rc; char buff[4096]; if (count == 0) return DB_SUCCESS; else if (p_ids == NULL || p_attrs == NULL) RBH_BUG("NULL pointer argument"); /* read only fields in info mask? */ if (readonly_attr_set & p_attrs[0]->attr_mask) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Error: trying to insert read only values: attr_mask=%#x", readonly_attr_set & p_attrs[0]->attr_mask); return DB_INVALID_ARG; } /* retry the whole transaction when the error is retryable */ retry: /* We want insert operation set to be atomic */ rc = lmgr_begin(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return rc; rc = listmgr_batch_insert_no_tx(p_mgr, p_ids, p_attrs, count, update_if_exists); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) { lmgr_rollback(p_mgr); DisplayLog(LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg(&p_mgr->conn, buff, 4096)); return rc; } rc = lmgr_commit(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* success, count it */ if (!rc) { if (update_if_exists) p_mgr->nbop[OPIDX_UPDATE] += count; else p_mgr->nbop[OPIDX_INSERT] += count; } return rc; }
int ListMgr_Exists(lmgr_t *p_mgr, const entry_id_t *p_id) { GString *req; int rc; result_handle_t result; char *str_count = NULL; DEF_PK(pk); int retry_status; /* retrieve primary key */ entry_id2pk(p_id, PTR_PK(pk)); /* verify it exists in main table */ req = g_string_new("SELECT id FROM " MAIN_TABLE " WHERE id="); g_string_append_printf(req, DPK, pk); retry: /* execute the request (must return negative value on error) */ 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; rc = db_next_record(&p_mgr->conn, &result, &str_count, 1); if (rc == 0) rc = 1; /* return 1 if entry exists */ else if (rc != DB_END_OF_LIST) { 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_result; } } else rc = 0; free_result: db_result_free(&p_mgr->conn, &result); free_str: g_string_free(req, TRUE); return rc; }
/* Retrieve the FID from the database given the parent FID and the file name. */ int ListMgr_Get_FID_from_Path( lmgr_t * p_mgr, const entry_id_t * parent_fid, const char *name, entry_id_t * fid) { result_handle_t result; GString *req = NULL; char escaped[RBH_NAME_MAX*2+1]; DEF_PK(pk); int rc; char *str_info[1]; int retry_status; entry_id2pk(parent_fid, PTR_PK(pk)); db_escape_string(&p_mgr->conn, escaped, sizeof(escaped), name); req = g_string_new("SELECT id FROM "DNAMES_TABLE" WHERE pkn="); g_string_append_printf(req, HNAME_FMT, pk, escaped); 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; rc = db_next_record(&p_mgr->conn, &result, str_info, 1); 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_res; } else if (rc != DB_SUCCESS) goto free_res; rc = pk2entry_id(p_mgr, str_info[0], fid); free_res: db_result_free(&p_mgr->conn, &result); free_str: g_string_free(req, TRUE); return rc; }
/** * Set variable value. * @param value size must not exceed 1024. */ int ListMgr_SetVar(lmgr_t *p_mgr, const char *varname, const char *value) { int rc; retry: rc = lmgr_set_var(&p_mgr->conn, varname, value); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; return rc; }
int ListMgr_EntryCount(lmgr_t *p_mgr, uint64_t *count) { int rc; do { rc = lmgr_table_count(&p_mgr->conn, MAIN_TABLE, count); } while (rc != DB_SUCCESS && lmgr_delayed_retry(p_mgr, rc)); return rc; }
int ListMgr_Get( lmgr_t * p_mgr, const entry_id_t * p_id, attr_set_t * p_info ) { int rc; DEF_PK(pk); entry_id2pk(p_id, PTR_PK(pk)); retry: rc = listmgr_get_by_pk(p_mgr, pk, p_info); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; return rc; }
int ListMgr_Exists( lmgr_t * p_mgr, const entry_id_t * p_id ) { char request[4096]; int rc; result_handle_t result; char *str_count = NULL; DEF_PK( pk ); /* retrieve primary key */ entry_id2pk(p_id, PTR_PK(pk)); /* verify it exists in main table */ sprintf( request, "SELECT id FROM " MAIN_TABLE " WHERE id="DPK, pk ); retry: /* execute the request */ rc = db_exec_sql(&p_mgr->conn, request, &result); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return -rc; rc = db_next_record( &p_mgr->conn, &result, &str_count, 1 ); if (rc == 0) rc = 1; else if (rc != DB_END_OF_LIST) { if (lmgr_delayed_retry(p_mgr, rc)) goto retry; rc = -rc; } else rc = 0; db_result_free( &p_mgr->conn, &result ); return rc; }
/* Retrieve the FID from the database given the parent FID and the file name. */ int ListMgr_Get_FID_from_Path( lmgr_t * p_mgr, const entry_id_t * parent_fid, const char *name, entry_id_t * fid) { result_handle_t result; char query[4096]; char escaped[RBH_NAME_MAX*2]; DEF_PK(pk); int rc; char *str_info[1]; entry_id2pk(parent_fid, PTR_PK(pk)); db_escape_string(&p_mgr->conn, escaped, RBH_NAME_MAX*2, name); sprintf(query, "SELECT id FROM "DNAMES_TABLE" WHERE pkn="HNAME_FMT, pk, escaped); retry: rc = db_exec_sql(&p_mgr->conn, query, &result); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return rc; rc = db_next_record( &p_mgr->conn, &result, str_info, 1 ); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc != DB_SUCCESS) goto free_res; rc = pk2entry_id(p_mgr, str_info[0], fid); free_res: db_result_free( &p_mgr->conn, &result ); return rc; }
int ListMgr_Get( lmgr_t * p_mgr, const entry_id_t * p_id, attr_set_t * p_info ) { int rc; DEF_PK(pk); int retry_status; entry_id2pk(p_id, PTR_PK(pk)); retry: rc = listmgr_get_by_pk(p_mgr, pk, p_info); retry_status = lmgr_delayed_retry(p_mgr, rc); if (retry_status == 1) goto retry; else if (retry_status == 2) rc = DB_RBH_SIG_SHUTDOWN; return rc; }
int ListMgr_SetStripe(lmgr_t *p_mgr, const entry_id_t *p_id, stripe_info_t *p_stripe_info, stripe_items_t *p_stripe_items) { DEF_PK(pk); int rc; #ifdef HAVE_LLAPI_FSWAP_LAYOUTS int validator = (p_stripe_info ? p_stripe_info->validator : VALID_NOSTRIPE); #else int validator = VALID(p_id); #endif entry_id2pk(p_id, PTR_PK(pk)); retry: rc = insert_stripe_info(p_mgr, pk, validator, p_stripe_info, p_stripe_items, true); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; return rc; }
int ListMgr_EntryCount(lmgr_t * p_mgr, uint64_t *count) { int rc; result_handle_t result; char *str_count = NULL; /* execute the request */ retry: rc = db_exec_sql( &p_mgr->conn, "SELECT COUNT(*) FROM " MAIN_TABLE, &result ); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return rc; rc = db_next_record( &p_mgr->conn, &result, &str_count, 1 ); if (rc) return rc; if ( sscanf( str_count, "%"SCNu64, count ) != 1 ) rc = DB_REQUEST_FAILED; db_result_free( &p_mgr->conn, &result ); return rc; }
/** * 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, int attr_mask, wagon_t ** child_id_list, attr_set_t ** child_attr_list, unsigned int * child_count) { result_handle_t result; char *curr; int filter_main = 0; int filter_annex = 0; int main_attrs = 0; int dnames_attrs = 0; int annex_attrs = 0; char query[4096]; char fieldlist_main[1024] = ""; char fieldlist_dnames[1024] = ""; char fieldlist_annex[1024] = ""; char filter_str_main[1024] = ""; char filter_str_annex[1024] = ""; char tmp[2048]; char *path = NULL; int path_len; char * pc; int rc, i; /* TODO: 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 (parent_count != 1) RBH_BUG("cannot get children for several parent simultaneously"); /* always request for name to build fullpath in wagon */ attr_mask |= ATTR_MASK_name; /* request is always on the MAIN table (which contains [parent_id, id] relationship */ /* /!\ possible cases: * - simplest: the fields of the filter and the attributes to be retrieved are in the MAIN table * - harder: the fields of the filter and attributes are in a different table */ /* 1) location of filters */ if ( p_filter ) { char dummy_str[1024]; unsigned int dummy_uint; if (dir_filter(p_mgr, dummy_str, p_filter, &dummy_uint) != FILTERDIR_NONE) { DisplayLog( LVL_MAJOR, LISTMGR_TAG, "Directory filter not supported in %s()", __func__ ); return DB_NOT_SUPPORTED; } else if (func_filter(p_mgr, dummy_str, p_filter, T_MAIN, FALSE, FALSE)) { DisplayLog( LVL_MAJOR, LISTMGR_TAG, "Function filter not supported in %s()", __func__ ); return DB_NOT_SUPPORTED; } /* There is always a filter on T_DNAMES, which is the parent condition. * Look for optional filters: */ filter_main = filter2str( p_mgr, filter_str_main, p_filter, T_MAIN, FALSE, TRUE ); if ( annex_table ) filter_annex = filter2str( p_mgr, filter_str_annex, p_filter, T_ANNEX, FALSE, TRUE ); else filter_annex = 0; /* @TODO to be implemented */ #if 0 filter_stripe_info = filter2str( p_mgr, filter_str_stripe_info, p_filter, T_STRIPE_INFO, ( filter_main > 0 ) || ( filter_annex > 0 ), TRUE ); filter_stripe_items = filter2str( p_mgr, filter_str_stripe_items, p_filter, T_STRIPE_ITEMS, ( filter_main > 0 ) || ( filter_annex > 0 ) || ( filter_stripe_info > 0 ), TRUE ); #endif } /* 2) location of requested attributes */ if (attr_mask) { /* retrieve source info for generated fields */ add_source_fields_for_gen( &attr_mask ); main_attrs = attrmask2fieldlist( fieldlist_main, attr_mask, T_MAIN, /* leading comma */ TRUE, /* for update */ FALSE, /* prefix */ MAIN_TABLE".", /* postfix */ "" ); dnames_attrs += attrmask2fieldlist( fieldlist_dnames, attr_mask, T_DNAMES, /* leading comma */ TRUE, /* for update */ FALSE, /* prefix */ DNAMES_TABLE".", /* postfix */ "" ); if ( annex_table ) annex_attrs = attrmask2fieldlist( fieldlist_annex, attr_mask, T_ANNEX, /* leading comma */ TRUE, /* for update */ FALSE, /* prefix */ ANNEX_TABLE".", /* postfix */ "" ); else annex_attrs = 0; } else { /* no returned attrs */ if (child_attr_list) *child_attr_list = NULL; } pc = parent_cond(p_mgr, tmp, sizeof(tmp), parent_list, parent_count, DNAMES_TABLE"."); if (!pc) return DB_BUFFER_TOO_SMALL; curr = query; /* SELECT clause */ /* id + dname fields */ curr += sprintf(curr, "SELECT "DNAMES_TABLE".id%s", fieldlist_dnames); /* main attrs */ if (main_attrs) curr += sprintf(curr, "%s", fieldlist_main); /* annex attrs */ if (annex_attrs) curr += sprintf(curr, "%s", fieldlist_annex); /* FROM clause */ curr += sprintf(curr, " FROM "DNAMES_TABLE); if (main_attrs || filter_main) curr += sprintf(curr, " LEFT JOIN "MAIN_TABLE " ON "DNAMES_TABLE".id="MAIN_TABLE".id"); if (annex_attrs || filter_annex) curr += sprintf(curr, " LEFT JOIN "ANNEX_TABLE " ON "DNAMES_TABLE".id="ANNEX_TABLE".id"); /* WHERE clause */ curr += sprintf(curr, " WHERE %s", pc); if (filter_main) curr += sprintf(curr, " AND %s", filter_str_main); if (filter_annex) curr += sprintf(curr, " AND %s", filter_str_annex); retry: rc = db_exec_sql(&p_mgr->conn, query, &result); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return rc; /* 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) return DB_NO_MEMORY; 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 row is large enough */ rc = db_next_record(&p_mgr->conn, &result, res, 128); 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) { (*child_attr_list)[i].attr_mask = attr_mask; /* first id, then dnames attrs, then main attrs, then annex attrs */ if (dnames_attrs) { /* shift of 1 for id */ rc = result2attrset( T_DNAMES, res + 1, dnames_attrs, &((*child_attr_list)[i]) ); if ( rc ) goto array_free; } if (main_attrs) { /* first id, then main attrs, then annex attrs */ /* shift of 1 for id */ rc = result2attrset( T_MAIN, res + dnames_attrs + 1, main_attrs, &((*child_attr_list)[i]) ); if ( rc ) goto array_free; } if (annex_attrs) { /* shift of main_attrs count */ rc = result2attrset( T_ANNEX, res + dnames_attrs + main_attrs + 1, annex_attrs, &((*child_attr_list)[i]) ); if ( rc ) goto array_free; } #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. */ sprintf(path, "%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 ); 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; return rc; }
/** * 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; }
/** * Builds a report from database. */ struct lmgr_report_t *ListMgr_Report( lmgr_t * p_mgr, const report_field_descr_t * report_desc_array, unsigned int report_descr_count, const profile_field_descr_t * profile_descr, const lmgr_filter_t * p_filter, const lmgr_iter_opt_t * p_opt ) { unsigned int i; /* A query consists of 5 parts: * - List of fields to be selected * - FROM clause with joins * - WHERE clause (filters) * - GROUP BY clause * - ORBER BY clause */ char fields[1024] = ""; char from[512] = ""; char where[2048] = ""; char having[2048] = ""; char group_by[512] = ""; char order_by[512] = ""; char query[4096] = ""; /* filters on NAMES or STRIPE_ITEMS * must be managed differently, as they * can create duplicates (non uniq id) */ char name_filter_str[1024] = ""; char stripe_filter_str[1024] = ""; char *curr_field = fields; char *curr_group_by = group_by; char *curr_sort = order_by; char *curr_query = query; char *curr_where = where; char *curr_having = having; char attrname[128]; char attrstring[1024]; lmgr_report_t *p_report; int rc; table_enum query_tab; /* supported report fields: ENTRIES, ANNEX_INFO or ACCT */ int main_table_flag = FALSE; int annex_table_flag = FALSE; int acct_table_flag = FALSE; int filter_main = 0; int filter_annex = 0; int filter_stripe_info = 0; int filter_stripe_items = 0; int filter_names = 0; int filter_acct = 0; int full_acct = TRUE; lmgr_iter_opt_t opt = {0}; unsigned int profile_len = 0; unsigned int ratio = 0; /* check profile argument and increase output array if needed */ if (profile_descr != NULL) { if (profile_descr->attr_index != ATTR_INDEX_size) { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Profile on attribute #%u is not supported", profile_descr->attr_index); return NULL; } profile_len = SZ_PROFIL_COUNT; if (profile_descr->range_ratio_len > 0) ratio = 1; } /* allocate a new report structure */ p_report = ( lmgr_report_t * ) MemAlloc( sizeof( lmgr_report_t ) ); if ( !p_report ) return NULL; p_report->p_mgr = p_mgr; p_report->result_type_array = ( db_type_t * ) MemCalloc( report_descr_count + profile_len + ratio, sizeof( db_type_t ) ); if ( !p_report->result_type_array ) goto free_report; p_report->result_count = report_descr_count + profile_len + ratio; p_report->profile_count = profile_len; p_report->ratio_count = ratio; if (profile_descr != NULL) p_report->profile_attr = ATTR_INDEX_size; /* initialy, no char * tab allocated */ p_report->str_tab = NULL; if (p_opt) opt = *p_opt; for ( i = 0; i < report_descr_count; i++ ) { if ( ( report_desc_array[i].report_type != REPORT_COUNT ) && #ifdef ATTR_INDEX_dircount report_desc_array[i].attr_index != ATTR_INDEX_dircount && #endif !is_acct_field( report_desc_array[i].attr_index ) && !is_acct_pk( report_desc_array[i].attr_index ) ) full_acct = FALSE; } if ( p_filter ) { if ( p_filter->filter_type == FILTER_SIMPLE ) { for ( i = 0; i < p_filter->filter_simple.filter_count; i++ ) { if ( !is_acct_pk( p_filter->filter_simple.filter_index[i] ) && !is_acct_field( p_filter->filter_simple.filter_index[i] ) ) full_acct = FALSE; } } } if ( full_acct && !opt.force_no_acct ) { listmgr_optimizedstat( p_report, p_mgr, report_descr_count, report_desc_array, profile_descr, fields, &curr_field, group_by, &curr_group_by, order_by, &curr_sort, having, &curr_having, where, &curr_where); acct_table_flag = TRUE; } else /* not only ACCT table */ { /* sorting by ratio first */ if (profile_descr && profile_descr->range_ratio_len > 0) { if ( profile_descr->attr_index == ATTR_INDEX_size ) { if (profile_descr->range_ratio_sort == SORT_ASC) add_string( order_by, curr_sort, "sizeratio ASC"); else add_string( order_by, curr_sort, "sizeratio DESC"); } } for ( i = 0; i < report_descr_count; i++ ) { /* no field for count or distinct count */ if ( report_desc_array[i].report_type != REPORT_COUNT && report_desc_array[i].report_type != REPORT_COUNT_DISTINCT ) { /* in what table is this field ? */ if ( is_main_field( report_desc_array[i].attr_index ) ) main_table_flag = TRUE; else if ( is_annex_field( report_desc_array[i].attr_index ) ) annex_table_flag = TRUE; else { /* Not supported yet */ DisplayLog( LVL_CRIT, LISTMGR_TAG, "Error: report on attribute #%u is not supported (report item #%u).", report_desc_array[i].attr_index, i ); goto free_field_tab; } } sprintf( attrname, "attr%u", i ); /* what kind of stat on this field ? */ switch ( report_desc_array[i].report_type ) { case REPORT_MIN: sprintf( attrstring, "MIN( %s ) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_MAX: sprintf( attrstring, "MAX( %s ) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_AVG: sprintf( attrstring, "ROUND(AVG( %s )) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_SUM: sprintf( attrstring, "SUM( %s ) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_COUNT: sprintf( attrstring, "COUNT(*) as %s", attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = DB_BIGUINT; break; case REPORT_COUNT_DISTINCT: sprintf( attrstring, "COUNT(DISTINCT(%s)) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = DB_BIGUINT; break; case REPORT_GROUP_BY: sprintf( attrstring, "%s as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); add_string( group_by, curr_group_by, attrname ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; } /* is this field sorted ? */ if ( report_desc_array[i].sort_flag == SORT_ASC ) { sprintf( attrstring, "%s ASC", attrname ); add_string( order_by, curr_sort, attrstring ); } else if ( report_desc_array[i].sort_flag == SORT_DESC ) { sprintf( attrstring, "%s DESC", attrname ); add_string( order_by, curr_sort, attrstring ); } /* is this field filtered ? */ listmgr_fieldfilter( p_report, p_mgr, report_desc_array, attrstring, attrname, having, &curr_having, where, &curr_where, i ); } /* generate size profile */ if (profile_descr != NULL) { if (profile_descr->attr_index == ATTR_INDEX_size) { add_string( fields, curr_field, "SUM(size=0)" ); for (i=1; i < SZ_PROFIL_COUNT-1; i++) curr_field += sprintf(curr_field, ",SUM("ACCT_SZ_VAL("size")"=%u)", i-1); curr_field += sprintf(curr_field, ",SUM("ACCT_SZ_VAL("size")">=%u)", i-1); for (i=0; i<SZ_PROFIL_COUNT; i++) p_report->result_type_array[i+report_descr_count] = DB_BIGUINT; if (profile_descr->range_ratio_len > 0) { /* add ratio field and sort it */ attrstring[0] = '\0'; char *curr_attr = attrstring; curr_attr += sprintf(curr_attr, "SUM(size>=%Lu", SZ_MIN_BY_INDEX(profile_descr->range_ratio_start)); /* is the last range = 1T->inf ? */ if (profile_descr->range_ratio_start + profile_descr->range_ratio_len >= SZ_PROFIL_COUNT) curr_attr += sprintf(curr_attr, ")"); else curr_attr += sprintf(curr_attr, " and size<%Lu)", SZ_MIN_BY_INDEX(profile_descr->range_ratio_start+profile_descr->range_ratio_len)); curr_attr += sprintf(curr_attr, "/COUNT(*) as sizeratio"); add_string( fields, curr_field, attrstring ); } } } } /* filter */ if ( p_filter ) { if ( ( full_acct && !opt.force_no_acct ) ) { filter_acct = filter2str( p_mgr, curr_where, p_filter, T_ACCT, ( where != curr_where ), TRUE ); curr_where += strlen( curr_where ); if ( filter_acct ) acct_table_flag =TRUE; } else { /* filter on main table? */ filter_main = filter2str( p_mgr, curr_where, p_filter, T_MAIN, ( where != curr_where ), TRUE ); curr_where += strlen( curr_where ); if ( filter_main ) main_table_flag = TRUE; /* filter on annex table? */ if ( annex_table ) { filter_annex = filter2str( p_mgr, curr_where, p_filter, T_ANNEX, (where != curr_where), TRUE ); curr_where += strlen( curr_where ); if ( filter_annex ) annex_table_flag = TRUE; } filter_stripe_info = filter2str( p_mgr, curr_where, p_filter, T_STRIPE_INFO, (where != curr_where), TRUE ); curr_where += strlen( curr_where ); /* filter on names table is particular as this may duplicate * entries when computing the report (multiple hardlinks) */ filter_names = filter2str(p_mgr, name_filter_str, p_filter, T_DNAMES, FALSE, FALSE ); /* filter on stripe items table is particular as this may duplicate * entries when computing the report (multiple stripes) */ filter_stripe_items = filter2str(p_mgr, stripe_filter_str, p_filter, T_STRIPE_ITEMS, FALSE, FALSE); } } /* FROM clause */ if ( acct_table_flag ) { strcpy( from, ACCT_TABLE ); query_tab = T_ACCT; } else { const char * first_table = NULL; char * curr_from = from; if ( main_table_flag ) { strcpy(from, MAIN_TABLE); curr_from = from + strlen(from); first_table = MAIN_TABLE; query_tab = T_MAIN; } if ( annex_table_flag ) { if (first_table) curr_from += sprintf(curr_from, " LEFT JOIN "ANNEX_TABLE" ON %s.id="ANNEX_TABLE".id", first_table); else { strcpy(from, ANNEX_TABLE); curr_from = from + strlen(from); first_table = ANNEX_TABLE; query_tab = T_ANNEX; } } if ( filter_stripe_info ) { if (first_table) curr_from += sprintf(curr_from, " INNER JOIN "STRIPE_INFO_TABLE" ON %s.id="STRIPE_INFO_TABLE".id", first_table); else { strcpy(from, STRIPE_INFO_TABLE); curr_from = from + strlen(from); first_table = STRIPE_INFO_TABLE; query_tab = T_STRIPE_INFO; } } if (filter_names) { if (first_table) curr_from += sprintf(curr_from," INNER JOIN (SELECT DISTINCT(id)" " FROM "DNAMES_TABLE" WHERE %s) N" " ON %s.id=N.id", name_filter_str, first_table); else { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Unexpected case: "DNAMES_TABLE " table can't be the query table in %s()", __func__); goto free_field_tab; } } if (filter_stripe_items) { if (first_table) curr_from += sprintf(curr_from, " INNER JOIN (SELECT DISTINCT(id)" " FROM "STRIPE_ITEMS_TABLE" WHERE %s) SI" " ON %s.id=SI.id", stripe_filter_str, first_table); else { strcpy(from, STRIPE_ITEMS_TABLE); curr_from = from + strlen(from); strcpy(curr_where, stripe_filter_str); curr_where += strlen(curr_where); first_table = STRIPE_ITEMS_TABLE; query_tab = T_STRIPE_ITEMS; /* XXX the caller is supposed to select DISTINCT(id) in this case */ } } } /* Build the request */ curr_query += sprintf( query, "SELECT %s FROM %s", fields, from ); if ( where[0] ) { curr_query += sprintf( curr_query, " WHERE %s", where ); } if ( group_by[0] ) { curr_query += sprintf( curr_query, " GROUP BY %s", group_by ); } if ( having[0] ) { curr_query += sprintf( curr_query, " HAVING %s", having ); } if ( order_by[0] ) { curr_query += sprintf( curr_query, " ORDER BY %s", order_by ); } /* iterator opt */ if ( opt.list_count_max > 0 ) { curr_query += sprintf( curr_query, " LIMIT %u", opt.list_count_max ); } #ifdef _DEBUG_DB printf( "Report is specified by: %s\n", query ); #endif retry: /* execute request (expect that ACCT table does not exists) */ if (acct_table_flag) rc = db_exec_sql_quiet( &p_mgr->conn, query, &p_report->select_result ); else rc = db_exec_sql( &p_mgr->conn, query, &p_report->select_result ); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* if the ACCT table does exist, switch to standard mode */ if ( acct_table_flag && (rc == DB_NOT_EXISTS)) { lmgr_iter_opt_t new_opt; if (p_opt != NULL) new_opt = *p_opt; else new_opt.list_count_max = 0; new_opt.force_no_acct = TRUE; DisplayLog( LVL_EVENT, LISTMGR_TAG, "No accounting info: switching to standard query mode" ); return ListMgr_Report( p_mgr, report_desc_array, report_descr_count, profile_descr, p_filter, &new_opt ); } if ( rc ) goto free_field_tab; else return p_report; /* error handlers */ free_field_tab: MemFree( p_report->result_type_array ); free_report: MemFree( p_report ); return NULL; } /* ListMgr_Report */
/** * Builds a report from database. */ struct lmgr_report_t *ListMgr_Report(lmgr_t *p_mgr, const report_field_descr_t * report_desc_array, unsigned int report_descr_count, const profile_field_descr_t * profile_descr, const lmgr_filter_t *p_filter, const lmgr_iter_opt_t *p_opt) { unsigned int i; char attrname[128]; lmgr_report_t *p_report; int rc; table_enum query_tab; /* supported report fields: ENTRIES, ANNEX_INFO or ACCT */ bool use_acct_table = false; lmgr_iter_opt_t opt = { 0 }; unsigned int profile_len = 0; unsigned int ratio = 0; struct field_count fcnt = { 0 }; GString *req = NULL; GString *fields = NULL; GString *where = NULL; GString *having = NULL; GString *group_by = NULL; GString *order_by = NULL; GString *filter_name = NULL; /* check profile argument and increase output array if needed */ if (profile_descr != NULL) { if (profile_descr->attr_index != ATTR_INDEX_size) { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Profile on attribute '%s' (index=%u) is not supported", field_name(profile_descr->attr_index), profile_descr->attr_index); return NULL; } profile_len = SZ_PROFIL_COUNT; if (profile_descr->range_ratio_len > 0) ratio = 1; } /* allocate a new report structure */ p_report = (lmgr_report_t *) MemAlloc(sizeof(lmgr_report_t)); if (!p_report) return NULL; p_report->p_mgr = p_mgr; p_report->result = (struct result *)MemCalloc(report_descr_count + profile_len + ratio, sizeof(struct result)); if (!p_report->result) goto free_report; p_report->result_count = report_descr_count + profile_len + ratio; p_report->profile_count = profile_len; p_report->ratio_count = ratio; if (profile_descr != NULL) p_report->profile_attr = ATTR_INDEX_size; /* initially, no char * tab allocated */ p_report->str_tab = NULL; if (p_opt) opt = *p_opt; fields = g_string_new(NULL); group_by = g_string_new(NULL); order_by = g_string_new(NULL); having = g_string_new(NULL); where = g_string_new(NULL); if (full_acct(report_desc_array, report_descr_count, p_filter) && !opt.force_no_acct) { listmgr_optimizedstat(p_report, p_mgr, report_descr_count, report_desc_array, profile_descr, fields, group_by, order_by, having, where); use_acct_table = true; } else { /* not only ACCT table */ /* sorting by ratio first */ if (profile_descr && profile_descr->range_ratio_len > 0) { if (profile_descr->attr_index == ATTR_INDEX_size) { coma_if_needed(order_by); if (profile_descr->range_ratio_sort == SORT_ASC) g_string_append(order_by, "sizeratio ASC"); else g_string_append(order_by, "sizeratio DESC"); } } for (i = 0; i < report_descr_count; i++) { /* no field for count or distinct count */ if (report_desc_array[i].report_type != REPORT_COUNT && report_desc_array[i].report_type != REPORT_COUNT_DISTINCT) { /* in what table is this field ? */ if (is_main_field(report_desc_array[i].attr_index)) fcnt.nb_main++; else if (is_annex_field(report_desc_array[i].attr_index)) fcnt.nb_annex++; else { /* Not supported yet */ DisplayLog(LVL_CRIT, LISTMGR_TAG, "Error: report on attribute '%s' (index=%u) is not supported (report item #%u).", field_name(report_desc_array[i].attr_index), report_desc_array[i].attr_index, i); rc = DB_NOT_SUPPORTED; goto free_str; } } sprintf(attrname, "attr%u", i); /* what kind of stat on this field ? */ switch (report_desc_array[i].report_type) { case REPORT_MIN: coma_if_needed(fields); g_string_append_printf(fields, "MIN(%s) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_MAX: coma_if_needed(fields); g_string_append_printf(fields, "MAX(%s) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_AVG: coma_if_needed(fields); g_string_append_printf(fields, "ROUND(AVG(%s)) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_SUM: coma_if_needed(fields); g_string_append_printf(fields, "SUM(%s) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_COUNT: coma_if_needed(fields); g_string_append_printf(fields, "COUNT(*) as %s", attrname); p_report->result[i].type = DB_BIGUINT; break; case REPORT_COUNT_DISTINCT: coma_if_needed(fields); g_string_append_printf(fields, "COUNT(DISTINCT(%s)) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = DB_BIGUINT; break; case REPORT_GROUP_BY: coma_if_needed(fields); g_string_append_printf(fields, "%s as %s", field_str(report_desc_array[i]. attr_index), attrname); coma_if_needed(group_by); g_string_append(group_by, attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; } /* is this field sorted ? */ append_sort_order(order_by, attrname, report_desc_array[i].sort_flag); /* is this field filtered ? */ listmgr_fieldfilter(p_report, p_mgr, report_desc_array, attrname, having, where, i); p_report->result[i].flags = field_flag(report_desc_array[i].attr_index); } /* generate size profile */ if (profile_descr != NULL) { if (profile_descr->attr_index == ATTR_INDEX_size) { coma_if_needed(fields); g_string_append(fields, "SUM(size=0)"); for (i = 1; i < SZ_PROFIL_COUNT - 1; i++) g_string_append_printf(fields, ",SUM(" SZRANGE_FUNC "(size)=%u)", i - 1); g_string_append_printf(fields, ",SUM(" SZRANGE_FUNC "(size)>=%u)", SZ_PROFIL_COUNT - 1); for (i = 0; i < SZ_PROFIL_COUNT; i++) p_report->result[i + report_descr_count].type = DB_BIGUINT; if (profile_descr->range_ratio_len > 0) { /* add ratio field and sort it */ coma_if_needed(fields); g_string_append_printf(fields, "SUM(size>=%llu", SZ_MIN_BY_INDEX(profile_descr-> range_ratio_start)); /* is the last range = 1T->inf ? */ if (profile_descr->range_ratio_start + profile_descr->range_ratio_len >= SZ_PROFIL_COUNT) g_string_append(fields, ")"); else g_string_append_printf(fields, " and size<%llu)", SZ_MIN_BY_INDEX(profile_descr->range_ratio_start + profile_descr->range_ratio_len)); g_string_append(fields, "/COUNT(*) as sizeratio"); } } } } /* process filter */ if (!(no_filter(p_filter))) { if (full_acct(report_desc_array, report_descr_count, p_filter) && !opt.force_no_acct) { int filter_acct; /* filter on acct fields only */ filter_acct = filter2str(p_mgr, where, p_filter, T_ACCT, (!GSTRING_EMPTY(where) ? AOF_LEADING_SEP : 0) | AOF_PREFIX); if (filter_acct > 0) use_acct_table = true; } else { /* process NAMES filters apart, as with must then join with * DISTINCT(id) */ filter_where(p_mgr, p_filter, &fcnt, where, (!GSTRING_EMPTY(where) ? AOF_LEADING_SEP : 0) | AOF_SKIP_NAME); filter_name = g_string_new(NULL); fcnt.nb_names = filter2str(p_mgr, filter_name, p_filter, T_DNAMES, 0); } } /* start building the whole request */ req = g_string_new("SELECT "); g_string_append_printf(req, "%s FROM ", fields->str); /* FROM clause */ if (use_acct_table) { g_string_append(req, ACCT_TABLE); query_tab = T_ACCT; } else { bool distinct; filter_from(p_mgr, &fcnt, req, &query_tab, &distinct, AOF_SKIP_NAME); if (filter_name != NULL && !GSTRING_EMPTY(filter_name)) { g_string_append_printf(req, " INNER JOIN (SELECT DISTINCT(id)" " FROM " DNAMES_TABLE " WHERE %s) N" " ON %s.id=N.id", filter_name->str, table2name(query_tab)); /* FIXME: what if NAMES is the query tab? */ } /* FIXME: do the same for stripe items */ } /* Build the request */ if (!GSTRING_EMPTY(where)) g_string_append_printf(req, " WHERE %s", where->str); if (!GSTRING_EMPTY(group_by)) g_string_append_printf(req, " GROUP BY %s", group_by->str); if (!GSTRING_EMPTY(having)) g_string_append_printf(req, " HAVING %s", having->str); if (!GSTRING_EMPTY(order_by)) g_string_append_printf(req, " ORDER BY %s", order_by->str); /* iterator opt */ if (opt.list_count_max > 0) g_string_append_printf(req, " LIMIT %u", opt.list_count_max); retry: /* execute request (expect that ACCT table does not exists) */ if (use_acct_table) rc = db_exec_sql_quiet(&p_mgr->conn, req->str, &p_report->select_result); else rc = db_exec_sql(&p_mgr->conn, req->str, &p_report->select_result); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* if the ACCT table does exist, switch to standard mode */ if (use_acct_table && (rc == DB_NOT_EXISTS)) { lmgr_iter_opt_t new_opt; if (p_opt != NULL) new_opt = *p_opt; else new_opt.list_count_max = 0; new_opt.force_no_acct = true; DisplayLog(LVL_EVENT, LISTMGR_TAG, "No accounting info: switching to standard query mode"); g_string_free(req, TRUE); g_string_free(fields, TRUE); g_string_free(group_by, TRUE); g_string_free(order_by, TRUE); g_string_free(having, TRUE); g_string_free(where, TRUE); if (filter_name != NULL) g_string_free(filter_name, TRUE); return ListMgr_Report(p_mgr, report_desc_array, report_descr_count, profile_descr, p_filter, &new_opt); } free_str: /* these are always allocated */ g_string_free(fields, TRUE); g_string_free(group_by, TRUE); g_string_free(order_by, TRUE); g_string_free(having, TRUE); g_string_free(where, TRUE); /* these may not be allocated */ if (req != NULL) g_string_free(req, TRUE); if (filter_name != NULL) g_string_free(filter_name, TRUE); if (rc == DB_SUCCESS) return p_report; /* error */ MemFree(p_report->result); free_report: MemFree(p_report); return NULL; } /* ListMgr_Report */
/** * Initialize a recovery process. * \param p_filter[in] (optional) filter partial filesystem recovery * \retval DB_SUCCESS the recovery process successfully started; * the stats indicate the recovery states we can expect. * \retval DB_ALREADY_EXISTS a recovery process already started * and was not properly completed. stats indicate the current status. * \retval error another error occurred. */ int ListMgr_RecovInit( lmgr_t * p_mgr, const lmgr_filter_t * p_filter, lmgr_recov_stat_t * p_stats ) { int rc; db_value_t report_val; unsigned int nb; struct lmgr_report_t * report; report_field_descr_t report_count = {-1, REPORT_COUNT, SORT_NONE, false, 0, FV_NULL}; /** @TODO use glib strings */ char query[4096]; char filter_str[4096] = ""; char *filter_curr = filter_str; #define has_filters (filter_curr != filter_str) int distinct = 0; rc = ListMgr_RecovStatus( p_mgr, p_stats ); if (rc == 0) { if (p_stats->total != 0) /* RECOVERY table exists and is not empty */ return DB_ALREADY_EXISTS; } else if ( rc != DB_NOT_EXISTS ) /* other error */ return rc; if ( rc == 0 ) { DisplayLog( LVL_EVENT, LISTMGR_TAG, "Dropping any previous "RECOV_TABLE" table" ); /* start from clean state (no table, no indexes, no addl field) */ rc = db_drop_component(&p_mgr->conn, DBOBJ_TABLE, RECOV_TABLE); if ( rc ) return rc; } if ( p_filter ) { /* dummy vars */ char filter_dir_str[512] = ""; unsigned int filter_dir_index = 0; if (dir_filter(p_mgr, filter_dir_str, p_filter, &filter_dir_index, NULL) != FILTERDIR_NONE) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "Directory filter not supported for recovery"); return DB_NOT_SUPPORTED; } if (filter2str(p_mgr, filter_curr, p_filter, T_MAIN, AOF_PREFIX) > 0) filter_curr += strlen(filter_curr); if (filter2str(p_mgr, filter_curr, p_filter, T_ANNEX, (has_filters ? AOF_LEADING_SEP : 0) | AOF_PREFIX) > 0) filter_curr += strlen(filter_curr); if (filter2str(p_mgr, filter_curr, p_filter, T_DNAMES, (has_filters ? AOF_LEADING_SEP : 0) | AOF_PREFIX) > 0) { filter_curr += strlen(filter_curr); distinct = 1; } if (filter2str(p_mgr, filter_curr, p_filter, T_STRIPE_INFO, (has_filters ? AOF_LEADING_SEP : 0) | AOF_PREFIX) > 0) filter_curr += strlen(filter_curr); if (filter2str(p_mgr, filter_curr, p_filter, T_STRIPE_ITEMS, (has_filters ? AOF_LEADING_SEP : 0) | AOF_PREFIX) > 0) { filter_curr += strlen(filter_curr); distinct = 1; } } DisplayLog( LVL_EVENT, LISTMGR_TAG, "Populating "RECOV_TABLE" table (this can take a few minutes)..." ); /* create the recovery table */ if (distinct) { /* need to select only 1 instance of each object when joining with STRIPE_ITEMS or NAMES */ strcpy(query, "CREATE TABLE "RECOV_TABLE " SELECT DISTINCT("MAIN_TABLE".id)," BUILD_RECOV_LIST_FIELDS_NAMES " FROM "MAIN_TABLE" LEFT JOIN "ANNEX_TABLE" ON " "("MAIN_TABLE".id = "ANNEX_TABLE".id)" " LEFT JOIN "DNAMES_TABLE" ON " "("MAIN_TABLE".id = "DNAMES_TABLE".id)" " LEFT JOIN "STRIPE_INFO_TABLE" ON " "("MAIN_TABLE".id = "STRIPE_INFO_TABLE".id)" " LEFT JOIN "STRIPE_ITEMS_TABLE" ON " "("MAIN_TABLE".id = "STRIPE_ITEMS_TABLE".id)"); } else { strcpy(query, "CREATE TABLE "RECOV_TABLE " SELECT "MAIN_TABLE".id," BUILD_RECOV_LIST_FIELDS " FROM "MAIN_TABLE" LEFT JOIN "ANNEX_TABLE" ON " "("MAIN_TABLE".id = "ANNEX_TABLE".id)" " LEFT JOIN "STRIPE_INFO_TABLE" ON " "("MAIN_TABLE".id = "STRIPE_INFO_TABLE".id)"); } if (has_filters) { strcat(query, " WHERE "); strcat(query, filter_str); } /* the whole function is not atomic as we try to preserve the progress * in case of DB engine failure. So we retry each step independently. */ retry1: rc = db_exec_sql(&p_mgr->conn, query, NULL); if (lmgr_delayed_retry(p_mgr, rc)) goto retry1; else if (rc) return rc; DisplayLog( LVL_EVENT, LISTMGR_TAG, "Building indexes on "RECOV_TABLE" table..." ); /* create pk */ retry2: rc = db_exec_sql( &p_mgr->conn, "ALTER TABLE "RECOV_TABLE" ADD PRIMARY KEY (id)", NULL ); if (lmgr_delayed_retry(p_mgr, rc)) goto retry2; else if (rc) return rc; /* add recov_status column */ retry3: rc = db_exec_sql( &p_mgr->conn, "ALTER TABLE "RECOV_TABLE" ADD COLUMN recov_status INTEGER", NULL ); if (lmgr_delayed_retry(p_mgr, rc)) goto retry3; else if (rc) return rc; /* add index on status */ retry4: rc = db_exec_sql( &p_mgr->conn, "CREATE INDEX recov_st_index ON "RECOV_TABLE"(recov_status)", NULL ); if (lmgr_delayed_retry(p_mgr, rc)) goto retry4; else if (rc) return rc; /* count entries of each status */ expected_recov_status( p_mgr, p_stats ); /* if there is a filter on OSTs, report distinct ids */ if (distinct) report_count.report_type = REPORT_COUNT_DISTINCT; /* double check entry count before deleting entries */ report = ListMgr_Report(p_mgr, &report_count, 1, NULL, p_filter, NULL); if (report == NULL) return DB_REQUEST_FAILED; nb = 1; rc = ListMgr_GetNextReportItem(report, &report_val, &nb, NULL); ListMgr_CloseReport(report); if (rc) return rc; if ( nb == 0 ) return DB_REQUEST_FAILED; if ( report_val.value_u.val_biguint != p_stats->total ) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "ERROR: recovery count (%llu) is different from entry count in main table (%lld): preserving entries", p_stats->total, report_val.value_u.val_biguint ); return DB_REQUEST_FAILED; } /* clean previous DB content */ return ListMgr_MassRemove( p_mgr, p_filter, NULL ); }
/** check that validator is matching for a given entry */ int ListMgr_CheckStripe(lmgr_t *p_mgr, const entry_id_t *p_id, int validator) { char *res; result_handle_t result; int rc = DB_SUCCESS; GString *req = NULL; DEF_PK(pk); #ifndef HAVE_LLAPI_FSWAP_LAYOUTS if (validator != VALID_EXISTS) validator = VALID(p_id); #endif entry_id2pk(p_id, PTR_PK(pk)); req = g_string_new("SELECT validator FROM " STRIPE_INFO_TABLE " WHERE id="); g_string_append_printf(req, DPK, pk); retry: rc = db_exec_sql(&p_mgr->conn, req->str, &result); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) goto out; rc = db_next_record(&p_mgr->conn, &result, &res, 1); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; if (rc == DB_END_OF_LIST) rc = DB_NOT_EXISTS; if (rc) goto res_free; if (res == NULL) { rc = DB_ATTR_MISSING; goto res_free; } if (validator == VALID_EXISTS) { DisplayLog(LVL_FULL, LISTMGR_TAG, DFID ": validator exists (%s): OK", PFID(p_id), res); /* just check it exists */ rc = DB_SUCCESS; } else if (atoi(res) != validator) { DisplayLog(LVL_FULL, LISTMGR_TAG, DFID ": stripe change detected: gen %s->%d", PFID(p_id), res, validator); rc = DB_OUT_OF_DATE; } else { /* validator matches */ DisplayLog(LVL_FULL, LISTMGR_TAG, DFID ": stripe gen is unchanged (%d)", PFID(p_id), validator); rc = DB_SUCCESS; } res_free: db_result_free(&p_mgr->conn, &result); out: g_string_free(req, TRUE); DisplayLog(LVL_FULL, LISTMGR_TAG, DFID ": %s returns with status=%d", PFID(p_id), __func__, rc); return rc; }