int lmgr_commit( lmgr_t * p_mgr ) { if ( lmgr_config.commit_behavior == 0 ) return DB_SUCCESS; else if ( lmgr_config.commit_behavior == 1 ) return db_exec_sql( &p_mgr->conn, "COMMIT", NULL ); else { /* if the transaction count is reached: * commit operations and result transction count */ if ( ( p_mgr->last_commit % lmgr_config.commit_behavior == 0 ) || p_mgr->force_commit ) { int rc; rc = db_exec_sql( &p_mgr->conn, "COMMIT", NULL ); if ( rc ) return rc; p_mgr->last_commit = 0; } } return DB_SUCCESS; }
int lmgr_get_var(db_conn_t *pconn, const char *varname, char *value, int bufsize) { int rc; result_handle_t result; char *str_val = NULL; GString *req = NULL; if (!varname || !value) return DB_INVALID_ARG; req = g_string_new("SELECT value FROM "VAR_TABLE" WHERE varname="); g_string_append_printf(req, "'%s'", varname); /* execute the request */ rc = db_exec_sql(pconn, req->str, &result); if (rc) goto free_str; rc = db_next_record(pconn, &result, &str_val, 1); if (rc == DB_END_OF_LIST) rc = DB_NOT_EXISTS; if (rc) goto free_res; if (str_val == NULL) { rc = DB_REQUEST_FAILED; goto free_res; } /* copy the result */ if (strlen(str_val) >= bufsize) { rc = DB_BUFFER_TOO_SMALL; } else { strcpy(value, str_val); rc = DB_SUCCESS; } free_res: db_result_free(pconn, &result); free_str: g_string_free(req, TRUE); return rc; }
/** * Continue a recovery process (returns an iterator on entry list), * possibly using the specified filter. * \retval iterator must be release using ListMgr_CloseIterator() */ struct lmgr_iterator_t * ListMgr_RecovResume( lmgr_t * p_mgr, const char * dir_path, int retry, /* also retry previously erroneous entries */ const lmgr_iter_opt_t * p_opt ) { char query[4096]; char * curr; lmgr_iterator_t * it; int rc; strcpy( query, "SELECT id,recov_status,"GET_RECOV_LIST_FIELDS" FROM "RECOV_TABLE" WHERE " ); curr = query + strlen(query); if ( retry ) curr += sprintf( curr, "(recov_status IS NULL OR recov_status=%u)", RS_ERROR ); else curr += sprintf( curr, "recov_status IS NULL" ); if ( dir_path ) { char rel[RBH_PATH_MAX] = ""; /* Recovery table contains path from DB (<root_id>/<rel_path>), * and dirpath is absolute. So convert it. */ if (fullpath_attr2db(dir_path, rel)) return NULL; #ifdef _MYSQL /* MySQL is case insensitive. * To force case-sensitivity, use BINARY keyword. */ curr += sprintf( curr, " AND relpath LIKE BINARY '%s/%%'", rel ); #else curr += sprintf( curr, " AND relpath LIKE '%s/%%'", rel ); #endif } /* allocate a new iterator */ it = ( lmgr_iterator_t * ) MemAlloc( sizeof( lmgr_iterator_t ) ); it->p_mgr = p_mgr; /* execute request */ rc = db_exec_sql( &p_mgr->conn, query, &it->select_result ); if ( rc ) { MemFree( it ); return NULL; } else return it; }
int lmgr_flush_commit( lmgr_t * p_mgr ) { int rc; if ( ( lmgr_config.commit_behavior > 1 ) && ( p_mgr->last_commit != 0 ) ) { rc = db_exec_sql( &p_mgr->conn, "COMMIT", NULL ); if ( rc ) return rc; p_mgr->last_commit = 0; return DB_SUCCESS; } else return DB_SUCCESS; }
/* 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; }
/* check that validator is matching for a given entry */ int ListMgr_CheckStripe( lmgr_t * p_mgr, const entry_id_t * p_id ) { char query[1024]; char *res; result_handle_t result; int rc = DB_SUCCESS; DEF_PK(pk); rc = entry_id2pk( p_mgr, p_id, FALSE, PTR_PK(pk) ); if (rc) return rc; sprintf( query, "SELECT validator FROM " STRIPE_INFO_TABLE " WHERE id="DPK, pk ); rc = db_exec_sql( &p_mgr->conn, query, &result ); if ( rc ) goto out; rc = db_next_record( &p_mgr->conn, &result, &res, 1 ); 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 ( atoi( res ) != VALID(p_id) ) { delete_stipe_info( p_mgr, pk ); rc = DB_OUT_OF_DATE; } else rc = DB_SUCCESS; res_free: db_result_free( &p_mgr->conn, &result ); out: return rc; }
fsal_posixdb_status_t fsal_posixdb_deleteHandle(fsal_posixdb_conn * p_conn, /* IN */ posixfsal_handle_t * p_parent_directory_handle /* IN */ ) { /* char handleid_str[MAX_HANDLEIDSTR_SIZE]; char handlets_str[MAX_HANDLETSSTR_SIZE]; const char *paramValues[2]; */ int found; result_handle_t res; fsal_posixdb_status_t st; char query[2048]; BeginTransaction(p_conn); LogFullDebug(COMPONENT_FSAL, "Deleting %llu.%u\n", p_parent_directory_handle->data.id, p_parent_directory_handle->data.ts); snprintf(query, 2048, "SELECT Handle.deviceid, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype " "FROM Handle WHERE handleid=%llu AND handlets=%u FOR UPDATE", p_parent_directory_handle->data.id, p_parent_directory_handle->data.ts); st = db_exec_sql(p_conn, query, &res); if(FSAL_POSIXDB_IS_ERROR(st)) goto rollback; found = mysql_num_rows(res); mysql_free_result(res); if(found) { /* entry found */ st = fsal_posixdb_recursiveDelete(p_conn, p_parent_directory_handle->data.id, p_parent_directory_handle->data.ts, FSAL_TYPE_DIR); if(FSAL_POSIXDB_IS_ERROR(st)) goto rollback; } return EndTransaction(p_conn); rollback: RollbackTransaction(p_conn); return st; }
/** * List entries by recovery status. * \param st type of entries to be listed * (done, failed, to be done, all) */ struct lmgr_iterator_t * ListMgr_RecovList( lmgr_t * p_mgr,recov_type_e st ) { char query[4096]; char * curr; lmgr_iterator_t * it; int rc; strcpy( query, "SELECT id,recov_status,"GET_RECOV_LIST_FIELDS" FROM "RECOV_TABLE ); curr = query + strlen(query); switch(st) { case RT_ALL: /* add no filter */ break; case RT_TODO: strcpy(curr, " WHERE recov_status is NULL"); break; case RT_DONE: sprintf(curr, " WHERE recov_status in (%u, %u, %u, %u, %u)", RS_FILE_OK, RS_FILE_DELTA, RS_FILE_EMPTY, RS_NON_FILE, RS_NOBACKUP ); break; case RT_FAILED: sprintf(curr, " WHERE recov_status=%u", RS_ERROR); break; } /* allocate a new iterator */ it = ( lmgr_iterator_t * ) MemAlloc( sizeof( lmgr_iterator_t ) ); it->p_mgr = p_mgr; /* execute request */ rc = db_exec_sql( &p_mgr->conn, query, &it->select_result ); if ( rc ) { MemFree( it ); return NULL; } else return it; }
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); /* 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); if (lmgr_delayed_retry(p_mgr, -rc)) goto retry; 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) { if (lmgr_delayed_retry(p_mgr, -rc)) goto retry; } else rc = 0; db_result_free(&p_mgr->conn, &result); free_str: g_string_free(req, TRUE); 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_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; }
int insert_stripe_info( lmgr_t * p_mgr, PK_ARG_T pk, int validator, const stripe_info_t * p_stripe, const stripe_items_t * p_items, int update_if_exists ) { int i, rc; int created = FALSE; if ( p_stripe == NULL ) return DB_INVALID_ARG; do { char short_query[4096]; /* First insert info into STRIPE_INFO_TABLE, * so if a file is already present with the same id, * we will remove its previous stripe info */ sprintf( short_query, "INSERT INTO " STRIPE_INFO_TABLE "(id,validator, stripe_count,stripe_size,pool_name) " "VALUES ("DPK",%u,%u,%u,'%s')", pk, validator, p_stripe->stripe_count, ( unsigned int ) p_stripe->stripe_size, p_stripe->pool_name ); if ( update_if_exists ) rc = db_exec_sql_quiet( &p_mgr->conn, short_query, NULL ); else rc = db_exec_sql( &p_mgr->conn, short_query, NULL ); if ( rc == 0 ) { created = TRUE; } else if ( (rc == DB_ALREADY_EXISTS) && update_if_exists ) { /* remove previous stripe info */ DisplayLog( LVL_EVENT, LISTMGR_TAG, "A stripe info already exists with this identifier, removing it" ); rc = delete_stipe_info( p_mgr, pk ); } if ( rc != 0 ) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg( &p_mgr->conn, short_query, 4096 ) ); return rc; } } while ( !created ); /* retry loop in case a similar entry already exists */ /* then insert stripe items */ if ( (p_items != NULL) && (p_items->count > 0) ) { ssize_t len; unsigned int est_len; char *query = NULL; /* estimate query size = fix part + stripe_count * ( 4 + pklen + ost_idx_len ) * = ~64(oversize to 128) + stripe_count * 4 + 128 */ est_len = 128 + p_items->count * 128; DisplayLog( LVL_FULL, LISTMGR_TAG, "Estimated query size for %u stripe = %u", p_items->count, est_len ); query = MemAlloc(est_len); if (query == NULL) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "Not enough memory to build SQL query (length = %u)", est_len ); return DB_NO_MEMORY; } strcpy( query, "INSERT INTO " STRIPE_ITEMS_TABLE "(id, storage_item) VALUES " ); len = strlen( query ); /* first stripe item */ len += snprintf( query + len, est_len - len, "("DPK",%u)", pk, p_items->stripe_units[0] ); /* next items */ for ( i = 1; i < p_items->count; i++ ) { len += snprintf( query + len, est_len - len, ",("DPK",%u)", pk, p_items->stripe_units[i] ); if ( len >= est_len ) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "Error in %s(): query too long (>%u bytes long), stripe_count=%d", __FUNCTION__, est_len, p_items->count ); MemFree( query ); return DB_BUFFER_TOO_SMALL; } } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg( &p_mgr->conn, query, 4096 ) ); MemFree( query ); return rc; } MemFree( query ); } return 0; }
int listmgr_batch_insert_no_tx(lmgr_t * p_mgr, entry_id_t **p_ids, attr_set_t **p_attrs, unsigned int count, int update_if_exists) { int rc = 0; int i, full_mask; char fields[1024]; /* field list */ pktype *pklist = NULL; var_str query = VAR_STR_NULL; char values[4096] = ""; char *values_curr = NULL; bool first; /* fake attribute struct, to write generic name fields */ attr_set_t fake_attrs = *(p_attrs[0]); full_mask = sum_masks(p_attrs, count, ~0); fake_attrs.attr_mask = full_mask; pklist = (pktype *)MemCalloc(count, sizeof(pktype)); if (pklist == NULL) return DB_NO_MEMORY; for (i = 0; i < count; i++) { /* check attr mask */ if (!lmgr_batch_compat(full_mask, p_attrs[i]->attr_mask)) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Incompatible attr mask in batched operation: %#x vs. %#x", p_attrs[i]->attr_mask, full_mask); rc = DB_INVALID_ARG; goto out_free; } /* fill pk array */ entry_id2pk(p_ids[i], PTR_PK(pklist[i])); /* The same for all tables? */ } /* build batch request for main table */ attrmask2fieldlist(fields, full_mask, T_MAIN, TRUE, FALSE, "", ""); var_str_append(&query, "INSERT INTO " MAIN_TABLE "(id"); var_str_append(&query, fields); var_str_append(&query, ") VALUES "); first = true; for (i = 0; i < count; i++) { /* don't set this entry if no attribute is in main table */ if ((p_attrs[i]->attr_mask & main_attr_set) == 0) continue; values_curr = values + sprintf(values, DPK, pklist[i]); attrset2valuelist(p_mgr, values_curr, p_attrs[i], T_MAIN, TRUE); /* add "[,](values)" to query */ var_str_append(&query, first ? "(" : ",("); var_str_append(&query, values); var_str_append(&query, ")"); first = false; } if (update_if_exists) { /* append "on duplicate key ..." */ attrset2updatelist(p_mgr, values, &fake_attrs, T_MAIN, FALSE, TRUE); var_str_append(&query, " ON DUPLICATE KEY UPDATE "); var_str_append(&query, values); } rc = db_exec_sql(&p_mgr->conn, VAR_STR_START(query), NULL); if (rc) goto out_free; var_str_reset(&query); /* allow inserting entries in MAIN_TABLE, without name information */ /* both parent and name are defined */ if ((full_mask & ATTR_MASK_name) && (full_mask & ATTR_MASK_parent_id)) { /* build batch request for names table */ attrmask2fieldlist(fields, full_mask, T_DNAMES, TRUE, FALSE, "", ""); var_str_append(&query, "INSERT INTO " DNAMES_TABLE "(id"); var_str_append(&query, fields); var_str_append(&query, ",pkn) VALUES "); first = true; for (i = 0; i < count; i++) { /* don't set this entry if parent or name is missing */ if (!ATTR_MASK_TEST(p_attrs[i], name) || !ATTR_MASK_TEST(p_attrs[i], parent_id)) { /* warn for create operations without name information */ if (!update_if_exists) no_name_warning(pklist[i], p_attrs[i], 1); continue; } values_curr = values + sprintf(values, DPK, pklist[i]); attrset2valuelist(p_mgr, values_curr, p_attrs[i], T_DNAMES, TRUE); /* add "[,](values,<pk>)" to query */ var_str_append(&query, first ? "(" : ",("); var_str_append(&query, values); var_str_append(&query, ","HNAME_DEF")"); first = false; } values_curr = values + sprintf(values, "id=VALUES(id)"); /* not part of the PK */ attrset2updatelist(p_mgr, values_curr, &fake_attrs, T_DNAMES, TRUE, TRUE); var_str_append(&query, " ON DUPLICATE KEY UPDATE "); var_str_append(&query, values); rc = db_exec_sql(&p_mgr->conn, VAR_STR_START(query), NULL); if (rc) goto out_free; } else if (!update_if_exists) { /* only warn for create operations */ /* if we get here, the name information is missing in all fields. * use entry[0] as example for the warning message. */ no_name_warning(pklist[0], p_attrs[0], count); } var_str_reset(&query); /* insert all info in annex table, if any */ if (annex_table && (full_mask & annex_attr_set)) { /* Create field and values lists. * Do nothing if no fields are to be set. */ if (attrmask2fieldlist(fields, full_mask, T_ANNEX, TRUE, FALSE, "", "") > 0) { var_str_append(&query, "INSERT INTO "ANNEX_TABLE "(id"); var_str_append(&query, fields); var_str_append(&query, ") VALUES "); first = true; for (i = 0; i < count; i++) { char values[4096] = ""; char *values_curr = NULL; /* don't set this entry if no attribute is in annex table */ if ((p_attrs[i]->attr_mask & annex_attr_set) == 0) continue; sprintf(values, DPK, pklist[i]); values_curr = values + strlen(values); attrset2valuelist(p_mgr, values_curr, p_attrs[i], T_ANNEX, TRUE); /* add "[,](values)" to query */ var_str_append(&query, first ? "(" : ",("); var_str_append(&query, values); var_str_append(&query, ")"); first = false; } /* always update as having the entry in the main table * is the reference to know if we knew the entry */ /* append "on duplicate key ..." */ attrset2updatelist(p_mgr, values, &fake_attrs, T_ANNEX, FALSE, TRUE); var_str_append(&query, " ON DUPLICATE KEY UPDATE "); var_str_append(&query, values); rc = db_exec_sql(&p_mgr->conn, VAR_STR_START(query), NULL); if (rc) goto out_free; } } #ifdef _LUSTRE /* batch insert of striping info */ if (ATTR_MASK_TEST(&fake_attrs, stripe_info) || ATTR_MASK_TEST(&fake_attrs, stripe_items)) { /* create validator list */ int *validators = (int*)MemCalloc(count, sizeof(int)); if (!validators) { rc = DB_NO_MEMORY; goto out_free; } for (i = 0; i < count; i++) #ifdef HAVE_LLAPI_FSWAP_LAYOUTS validators[i] = ATTR_MASK_TEST(p_attrs[i], stripe_info)? ATTR(p_attrs[i],stripe_info).validator:VALID_NOSTRIPE; #else validators[i] = VALID(p_ids[i]); #endif rc = batch_insert_stripe_info(p_mgr, pklist, validators, p_attrs, count, TRUE); MemFree(validators); if (rc) goto out_free; } #endif out_free: var_str_free(&query); MemFree(pklist); return rc; }
int get_stripe_info( lmgr_t * p_mgr, PK_ARG_T pk, stripe_info_t * p_stripe_info, stripe_items_t * p_items ) { char query[1024]; char *res[3]; result_handle_t result; int i; int rc = DB_SUCCESS; /* retrieve basic stripe info */ sprintf( query, "SELECT stripe_count, stripe_size, pool_name FROM " STRIPE_INFO_TABLE " WHERE id="DPK, pk ); rc = db_exec_sql( &p_mgr->conn, query, &result ); if ( rc ) goto out; rc = db_next_record( &p_mgr->conn, &result, res, 3 ); if ( rc == DB_END_OF_LIST ) rc = DB_NOT_EXISTS; if ( rc ) goto res_free; if ( res[0] == NULL || res[1] == NULL || res[2] == NULL ) { rc = DB_ATTR_MISSING; goto res_free; } p_stripe_info->stripe_count = atoi( res[0] ); p_stripe_info->stripe_size = atoi( res[1] ); strncpy( p_stripe_info->pool_name, res[2], MAX_POOL_LEN ); db_result_free( &p_mgr->conn, &result ); if ( p_items ) { /* retrieve stripe list */ sprintf( query, "SELECT storage_item FROM " STRIPE_ITEMS_TABLE " WHERE id="DPK, pk ); rc = db_exec_sql( &p_mgr->conn, query, &result ); if ( rc ) goto out; if ( p_stripe_info->stripe_count != db_result_nb_records( &p_mgr->conn, &result ) ) { DisplayLog( LVL_MAJOR, LISTMGR_TAG, "Warning: the number of stripe items (%d) doesn't match stripe count (%u)! (Pk="DPK")", db_result_nb_records( &p_mgr->conn, &result ), p_stripe_info->stripe_count, pk ); } p_items->count = db_result_nb_records( &p_mgr->conn, &result ); if ( p_items->count > 0 ) { /* allocate stripe array */ p_items->stripe_units = MemCalloc( p_items->count, sizeof( storage_unit_id_t ) ); if ( !p_items->stripe_units ) { rc = DB_NO_MEMORY; goto res_free; } /* fill stripe units */ for ( i = 0; i < p_items->count; i++ ) { rc = db_next_record( &p_mgr->conn, &result, res, 1 ); if ( rc ) goto stripe_free; if ( res[0] == NULL ) { rc = DB_ATTR_MISSING; goto stripe_free; } p_items->stripe_units[i] = atoi( res[0] ); } } else p_items->stripe_units = NULL; /* last query result must be freed */ rc = DB_SUCCESS; goto res_free; } /* nothing to free */ return DB_SUCCESS; stripe_free: MemFree( p_items->stripe_units ); p_items->stripe_units = NULL; p_items->count = 0; p_stripe_info->stripe_count = 0; res_free: db_result_free( &p_mgr->conn, &result ); out: return rc; }
int db_exec_sql_quiet( db_conn_t * conn, const char *query, result_handle_t * p_result ) { return db_exec_sql( conn, query, p_result); }
fsal_posixdb_status_t fsal_posixdb_getInfoFromHandle(fsal_posixdb_conn * p_conn, /* IN */ posixfsal_handle_t * p_object_handle, /* IN/OUT */ fsal_path_t * p_paths, /* OUT */ int paths_size, /* IN */ int *p_count /* OUT */ ) { fsal_posixdb_status_t st; result_handle_t res; MYSQL_ROW row; posixfsal_handle_t parent_directory_handle; int i_path; int toomanypaths = 0; char query[2048]; /* sanity check */ if(!p_conn || !p_object_handle || ((!p_paths || !p_count) && paths_size > 0)) { ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); } LogFullDebug(COMPONENT_FSAL, "OBJECT_ID=%lli\n", p_object_handle->data.id); BeginTransaction(p_conn); /* lookup for the handle of the file */ if(!fsal_posixdb_GetInodeCache(p_object_handle)) { snprintf(query, 2048, "SELECT Handle.deviceid, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype " "FROM Handle WHERE handleid=%llu AND handlets=%u", p_object_handle->data.id, p_object_handle->data.ts); st = db_exec_sql(p_conn, query, &res); if(FSAL_POSIXDB_IS_ERROR(st)) goto rollback; /* p_res contains : Handle.deviceId, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype */ LogDebug(COMPONENT_FSAL, "lookupHandle(%llu,%u)", p_object_handle->data.id, (unsigned int)p_object_handle->data.ts); if((mysql_num_rows(res) != 1) || ((row = mysql_fetch_row(res)) == NULL)) { LogDebug(COMPONENT_FSAL, "lookupHandle=%d entries", mysql_num_rows(res)); mysql_free_result(res); RollbackTransaction(p_conn); ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0); } posixdb_internal_fillFileinfoFromStrValues(&(p_object_handle->data.info), row[0], row[1], row[2], row[3], row[4]); mysql_free_result(res); /* update the inode */ fsal_posixdb_UpdateInodeCache(p_object_handle); } /* Build the paths of the object */ if(p_paths) { /* find all the paths to the object */ snprintf(query, 2048, "SELECT name, handleidparent, handletsparent " "FROM Parent WHERE handleid=%llu AND handlets=%u", p_object_handle->data.id, p_object_handle->data.ts); st = db_exec_sql(p_conn, query, &res); if(FSAL_POSIXDB_IS_ERROR(st)) goto rollback; /* res contains name, handleidparent, handletsparent */ *p_count = mysql_num_rows(res); if(*p_count == 0) { mysql_free_result(res); RollbackTransaction(p_conn); ReturnCodeDB(ERR_FSAL_POSIXDB_NOPATH, 0); } else if(*p_count > paths_size) { toomanypaths = 1; LogCrit(COMPONENT_FSAL, "Too many paths found for object %llu.%u: found=%u, max=%d", p_object_handle->data.id, p_object_handle->data.ts, *p_count, paths_size); *p_count = paths_size; } for(i_path = 0; i_path < *p_count; i_path++) { unsigned int tmp_len; row = mysql_fetch_row(res); if(row == NULL) { mysql_free_result(res); RollbackTransaction(p_conn); ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); } /* build the path of the parent directory */ parent_directory_handle.data.id = atoll(row[1]); parent_directory_handle.data.ts = atoi(row[2]); st = fsal_posixdb_buildOnePath(p_conn, &parent_directory_handle, &p_paths[i_path]); if(FSAL_POSIXDB_IS_ERROR(st)) goto free_res; tmp_len = p_paths[i_path].len; if((tmp_len > 0) && (p_paths[i_path].path[tmp_len - 1] == '/')) { /* then concatenate the name of the file */ /* but not concatenate '/' */ if((tmp_len + strlen(row[0]) >= FSAL_MAX_PATH_LEN)) { mysql_free_result(res); RollbackTransaction(p_conn); ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0); } strcpy(&p_paths[i_path].path[tmp_len], row[0]); p_paths[i_path].len += strlen(row[0]); } else { /* then concatenate the name of the file */ if((tmp_len + 1 + strlen(row[0]) >= FSAL_MAX_PATH_LEN)) { mysql_free_result(res); RollbackTransaction(p_conn); ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0); } p_paths[i_path].path[tmp_len] = '/'; strcpy(&p_paths[i_path].path[tmp_len + 1], row[0]); p_paths[i_path].len += 1 + strlen(row[0]); } /* insert the object into cache */ fsal_posixdb_CachePath(p_object_handle, &p_paths[i_path]); } mysql_free_result(res); } st = EndTransaction(p_conn); if(toomanypaths) ReturnCodeDB(ERR_FSAL_POSIXDB_TOOMANYPATHS, 0); else return st; free_res: mysql_free_result(res); rollback: RollbackTransaction(p_conn); return st; }
fsal_posixdb_status_t fsal_posixdb_getInfoFromName(fsal_posixdb_conn * p_conn, /* IN */ posixfsal_handle_t * p_parent_directory_handle, /* IN/OUT */ fsal_name_t * p_objectname, /* IN */ fsal_path_t * p_path, /* OUT */ posixfsal_handle_t * p_handle /* OUT */ ) { fsal_posixdb_status_t st; char query[2048]; result_handle_t res; MYSQL_ROW row; /* sanity check */ if(!p_conn || !p_handle) { ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); } LogFullDebug(COMPONENT_FSAL, "object_name='%s'\n", p_objectname->name ? p_objectname->name : "/"); BeginTransaction(p_conn); /* lookup for the handle of the file */ if(p_parent_directory_handle && p_parent_directory_handle->data.id) { snprintf(query, 2048, "SELECT Parent.handleid, Parent.handlets, Handle.deviceid, " "Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype " "FROM Parent INNER JOIN Handle ON Parent.handleid = Handle.handleid AND Parent.handlets=Handle.handlets " "WHERE handleidparent=%llu AND handletsparent=%u AND name='%s'", p_parent_directory_handle->data.id, p_parent_directory_handle->data.ts, p_objectname->name); st = db_exec_sql(p_conn, query, &res); if(FSAL_POSIXDB_IS_ERROR(st)) goto rollback; } else { /* get root handle: */ st = db_exec_sql(p_conn, "SELECT Parent.handleid, Parent.handlets, Handle.deviceid, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype " "FROM Parent INNER JOIN Handle ON Parent.handleid = Handle.handleid AND Parent.handlets=Handle.handlets " "WHERE Parent.handleidparent=Parent.handleid AND Parent.handletsparent=Parent.handlets", &res); if(FSAL_POSIXDB_IS_ERROR(st)) goto rollback; } /* res contains : Parent.handleid, Parent.handlets, Handle.deviceid, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype */ /* entry not found */ if((mysql_num_rows(res) != 1) || ((row = mysql_fetch_row(res)) == NULL)) { mysql_free_result(res); RollbackTransaction(p_conn); ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0); } p_handle->data.id = atoll(row[0]); p_handle->data.ts = atoi(row[1]); posixdb_internal_fillFileinfoFromStrValues(&(p_handle->data.info), row[2], row[3], /* devid, inode */ row[4], /* nlink */ row[5], /* ctime */ row[6]); /* ftype */ mysql_free_result(res); /* Build the path of the object */ if(p_path && p_objectname) { /* build the path of the Parent */ st = fsal_posixdb_buildOnePath(p_conn, p_parent_directory_handle, p_path); if(FSAL_POSIXDB_IS_ERROR(st)) goto rollback; /* then concatenate the filename */ if(!(p_path->len + 1 + p_objectname->len < FSAL_MAX_PATH_LEN)) { RollbackTransaction(p_conn); ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0); } p_path->path[p_path->len] = '/'; strcpy(&p_path->path[p_path->len + 1], p_objectname->name); p_path->len += 1 + p_objectname->len; /* add the the path to cache */ fsal_posixdb_CachePath(p_handle, p_path); } else { /* update handle if it was in cache */ fsal_posixdb_UpdateInodeCache(p_handle); } return EndTransaction(p_conn); rollback: RollbackTransaction(p_conn); return st; }
int ListMgr_Update( lmgr_t * p_mgr, const entry_id_t * p_id, const attr_set_t * p_update_set ) { int rc, main_count, annex_count; char query[4096]; char fields[4096]; char annex_fields[4096]; DEF_PK(pk); int nb_tables = 0; /* read only fields in info mask? */ if ( readonly_attr_set & p_update_set->attr_mask ) { DisplayLog( LVL_MAJOR, LISTMGR_TAG, "Error: trying to update read only values: attr_mask=%#x", readonly_attr_set & p_update_set->attr_mask ); return DB_INVALID_ARG; } rc = entry_id2pk( p_mgr, p_id, FALSE, PTR_PK(pk) ); if (rc) return rc; /* check how many tables are to be updated */ if ( main_fields( p_update_set->attr_mask ) ) { main_count = attrset2updatelist( p_mgr, fields, p_update_set, T_MAIN, FALSE ); if ( main_count < 0 ) return -main_count; if ( main_count > 0 ) nb_tables++; } else main_count = 0; if ( annex_table && annex_fields( p_update_set->attr_mask ) ) { annex_count = attrset2updatelist( p_mgr, annex_fields, p_update_set, T_ANNEX, FALSE ); if ( annex_count < 0 ) return -annex_count; if ( annex_count > 0 ) nb_tables++; } else annex_count = 0; if ( stripe_fields( p_update_set->attr_mask ) ) nb_tables += 2; /* if only 1 table is impacted, switch to autocommit mode */ if ( nb_tables > 1 ) { /* @todo in the case of sqlite, we may want to do periodic commit * instead of systematic one. */ rc = lmgr_begin( p_mgr ); if ( rc ) return rc; } /* update main table */ if ( main_count > 0 ) { sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id="DPK, fields, pk ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* update annex table (if any) */ if ( annex_count > 0 ) { sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id="DPK, annex_fields, pk ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* insert new stripe info if provided (and eventually remove previous values) */ if ( ATTR_MASK_TEST( p_update_set, stripe_info ) ) { rc = insert_stripe_info( p_mgr, pk, VALID(p_id), &ATTR( p_update_set, stripe_info ), ATTR_MASK_TEST( p_update_set, stripe_items ) ? &ATTR( p_update_set, stripe_items ) : NULL, TRUE ); if ( rc ) goto rollback; } if ( nb_tables > 1 ) return lmgr_commit( p_mgr ); else return DB_SUCCESS; rollback: lmgr_rollback( p_mgr ); 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; }
/** * Retrieve entry attributes from its primary key */ int listmgr_get_by_pk( lmgr_t * p_mgr, PK_ARG_T pk, attr_set_t * p_info ) { int rc; char *first_table = NULL; GString *req, *from; /* attribute count is up to 1 per bit (8 per byte). * x2 for bullet proofing */ char *result_tab[2*8*sizeof(p_info->attr_mask)]; result_handle_t result; bool checkmain = true; int main_count = 0, annex_count = 0, name_count = 0; attr_mask_t gen = gen_fields(p_info->attr_mask); if (p_info == NULL) return 0; /* init entry info */ memset(&p_info->attr_values, 0, sizeof(entry_info_t)); req = g_string_new("SELECT "); from = g_string_new(" FROM "); /* retrieve source info for generated fields (only about std fields)*/ add_source_fields_for_gen(&p_info->attr_mask.std); /* don't get fields that are not in main, names, annex, stripe... * This allows the caller to set all bits 'on' to get everything. * Note: this also clear generated fields. They will be restored after. */ supported_bits_only(&p_info->attr_mask); /* get info from main table (if asked) */ main_count = attrmask2fieldlist(req, p_info->attr_mask, T_MAIN, "", "", 0); if (main_count < 0) { rc = -main_count; goto free_str; } else if (main_count > 0) { checkmain = false; first_table = MAIN_TABLE; g_string_append(from, MAIN_TABLE); } annex_count = attrmask2fieldlist(req, p_info->attr_mask, T_ANNEX, "", "", first_table != NULL ? AOF_LEADING_SEP : 0); if (annex_count < 0) { rc = -annex_count; goto free_str; } else if (annex_count > 0) { if (first_table != NULL) g_string_append_printf(from, " LEFT JOIN "ANNEX_TABLE" ON %s.id=" ANNEX_TABLE".id", first_table); else { first_table = ANNEX_TABLE; g_string_append(from, ANNEX_TABLE); } } name_count = attrmask2fieldlist(req, p_info->attr_mask, T_DNAMES, "", "", first_table != NULL ? AOF_LEADING_SEP : 0); if (name_count < 0) { rc = -name_count; goto free_str; } else if (name_count > 0) { if (first_table) /* it's OK to JOIN with NAMES table here even if there are multiple paths, * as we only take one result record. The important thing is to return * consistent values for parent_id, name and fullpath. */ g_string_append_printf(from, " LEFT JOIN "DNAMES_TABLE" ON %s.id=" DNAMES_TABLE".id", first_table); else { first_table = DNAMES_TABLE; g_string_append(from, DNAMES_TABLE); } } if (first_table != NULL) { int shift = 0; g_string_append_printf(req, "%s WHERE %s.id="DPK, from->str, first_table, pk); rc = db_exec_sql(&p_mgr->conn, req->str, &result); if (rc) goto free_str; rc = db_next_record(&p_mgr->conn, &result, result_tab, main_count + annex_count + name_count); /* END_OF_LIST means it does not exist */ if (rc == DB_END_OF_LIST) { clean_std_table_bits(&p_info->attr_mask); /* not found, but did not check MAIN yet */ if (checkmain) goto next_table; rc = DB_NOT_EXISTS; } if (rc) goto free_res; /* set info from result */ if (main_count) { rc = result2attrset(T_MAIN, result_tab + shift, main_count, p_info); shift += main_count; if (rc) goto free_res; } if (annex_count) { rc = result2attrset(T_ANNEX, result_tab + shift, annex_count, p_info); shift += annex_count; if (rc) goto free_res; } if (name_count) { rc = result2attrset(T_DNAMES, result_tab + shift, name_count, p_info); shift += name_count; if (rc) goto free_res; } next_table: db_result_free(&p_mgr->conn, &result); } /* remove stripe info if it is not a file */ if (stripe_fields(p_info->attr_mask) && ATTR_MASK_TEST(p_info, type) && strcmp(ATTR(p_info, type), STR_TYPE_FILE) != 0) { p_info->attr_mask = attr_mask_and_not(&p_info->attr_mask, &stripe_attr_set); } /* get stripe info if asked */ #ifdef _LUSTRE if (stripe_fields(p_info->attr_mask)) { rc = get_stripe_info(p_mgr, pk, &ATTR(p_info, stripe_info), ATTR_MASK_TEST(p_info, stripe_items)? &ATTR(p_info, stripe_items) : NULL); if (rc == DB_ATTR_MISSING || rc == DB_NOT_EXISTS) { /* stripe info is in std mask */ p_info->attr_mask.std &= ~ATTR_MASK_stripe_info; if (ATTR_MASK_TEST(p_info, stripe_items)) p_info->attr_mask.std &= ~ATTR_MASK_stripe_items; } else if (rc) goto free_str; else checkmain = false; /* entry exists */ } #else /* POSIX: always clean stripe bits */ p_info->attr_mask = attr_mask_and_not(&p_info->attr_mask, &stripe_attr_set); #endif /* special field dircount */ if (dirattr_fields(p_info->attr_mask)) { if (listmgr_get_dirattrs(p_mgr, pk, p_info)) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "listmgr_get_dirattrs failed for "DPK, pk); p_info->attr_mask = attr_mask_and_not(&p_info->attr_mask, &dir_attr_set); } } if (checkmain) { /* verify it exists in main table */ g_string_printf(req, "SELECT id FROM " MAIN_TABLE " WHERE id="DPK, pk); /* execute the request */ rc = db_exec_sql(&p_mgr->conn, req->str, &result); if (rc) goto free_str; rc = db_next_record(&p_mgr->conn, &result, result_tab, 1); db_result_free(&p_mgr->conn, &result); if (rc) { rc = DB_NOT_EXISTS; goto free_str; } } /* restore generated fields in attr mask */ p_info->attr_mask = attr_mask_or(&p_info->attr_mask, &gen); /* generate them */ generate_fields(p_info); /* update operation stats */ p_mgr->nbop[OPIDX_GET]++; rc = DB_SUCCESS; goto free_str; free_res: db_result_free(&p_mgr->conn, &result); free_str: g_string_free(req, TRUE); g_string_free(from, TRUE); return rc; } /* listmgr_get_by_pk */
/** * 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; }
struct lmgr_iterator_t *ListMgr_Iterator( lmgr_t * p_mgr, const lmgr_filter_t * p_filter, const lmgr_sort_type_t * p_sort_type, const lmgr_iter_opt_t * p_opt ) { char query[4096]; char filter_str_main[2048]; char filter_str_annex[2048]; char filter_str_stripe_info[2048]; char filter_str_stripe_items[2048]; int filter_main = 0; int filter_annex = 0; int filter_stripe_info = 0; int filter_stripe_items = 0; int rc; char fields[2048]; char tables[2048]; lmgr_iterator_t *it; table_enum sort_table = T_NONE; int do_sort = 0; filter_str_main[0] = '\0'; filter_str_annex[0] = '\0'; filter_str_stripe_info[0] = '\0'; filter_str_stripe_items[0] = '\0'; char *query_end; /* Iterator only select a sorted list of ids. * Entry attributes are retrieved afterward in ListMgr_GetNext() call. */ /* is there a sort order ? */ do_sort = ( p_sort_type && ( p_sort_type->order != SORT_NONE ) ); /* check sort order */ if ( do_sort ) { if ( is_main_field( p_sort_type->attr_index ) ) sort_table = T_MAIN; else if ( is_annex_field( p_sort_type->attr_index ) ) sort_table = T_ANNEX; else if ( field_infos[p_sort_type->attr_index].db_type == DB_STRIPE_INFO ) sort_table = T_STRIPE_INFO; else if ( field_infos[p_sort_type->attr_index].db_type == DB_STRIPE_ITEMS ) sort_table = T_STRIPE_ITEMS; else { DisplayLog( LVL_CRIT, LISTMGR_TAG, "Invalid field for sort order (index=%d)", p_sort_type->attr_index ); return NULL; } } /* check filter location */ /* /!\ possible cases: * - simplest: the fields of the filter and the attributes to be changed are in the same table * - harder: the fields of the filter are in the same table and attributes are in another different table */ /* 1) check the location of filters */ if ( p_filter ) { 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, ( filter_main > 0 ), TRUE ); else filter_annex = 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 ); if ( ( filter_main == 0 ) && ( filter_annex == 0 ) && ( filter_stripe_items == 0 ) && ( filter_stripe_info == 0 ) ) { /* all records */ DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be affected" ); if ( do_sort ) { /* entries must be selected depending on sort order */ if ( sort_table == T_MAIN ) strcpy( query, "SELECT id FROM " MAIN_TABLE ); else if ( sort_table == T_ANNEX ) strcpy( query, "SELECT id FROM " ANNEX_TABLE ); else if ( sort_table == T_STRIPE_INFO ) strcpy( query, "SELECT id FROM " STRIPE_INFO_TABLE ); else if ( sort_table == T_STRIPE_ITEMS ) strcpy( query, "SELECT DISTINCT(id) FROM " STRIPE_ITEMS_TABLE ); } else { strcpy( query, "SELECT id FROM " MAIN_TABLE ); } } else if ( filter_main && !( filter_annex || filter_stripe_items || filter_stripe_info ) && ( !do_sort || ( sort_table == T_MAIN ) ) ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " MAIN_TABLE " table" ); sprintf( query, "SELECT id FROM " MAIN_TABLE " WHERE %s", filter_str_main ); } else if ( filter_annex && !( filter_main || filter_stripe_items || filter_stripe_info ) && ( !do_sort || ( sort_table == T_ANNEX ) ) ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " ANNEX_TABLE " table" ); sprintf( query, "SELECT id FROM " ANNEX_TABLE " WHERE %s", filter_str_annex ); } else if ( filter_stripe_info && !( filter_main || filter_annex || filter_stripe_items ) && ( !do_sort || ( sort_table == T_STRIPE_INFO ) ) ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_INFO_TABLE " table" ); sprintf( query, "SELECT id FROM " STRIPE_INFO_TABLE " WHERE %s", filter_str_stripe_info ); } else if ( filter_stripe_items && !( filter_main || filter_annex || filter_stripe_info ) && ( !do_sort || ( sort_table == T_STRIPE_ITEMS ) ) ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_ITEMS_TABLE " table" ); sprintf( query, "SELECT DISTINCT(id) FROM " STRIPE_ITEMS_TABLE " WHERE %s", filter_str_stripe_items ); } else { char *curr_fields = fields; char *curr_tables = tables; char *first_table = NULL; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter or sort order on several tables: " MAIN_TABLE ":%d, " ANNEX_TABLE ":%d, " STRIPE_INFO_TABLE ":%d, " STRIPE_ITEMS_TABLE ":%d", filter_main, filter_annex, filter_stripe_info, filter_stripe_items ); if ( ( filter_main > 0 ) || ( do_sort && ( sort_table == T_MAIN ) ) ) { first_table = MAIN_TABLE; if ( filter_main > 0 ) curr_fields += sprintf( curr_fields, "%s", filter_str_main ); curr_tables += sprintf( curr_tables, "%s", MAIN_TABLE ); } if ( ( filter_annex > 0 ) || ( do_sort && ( sort_table == T_ANNEX ) ) ) { if ( filter_annex > 0 ) curr_fields += sprintf( curr_fields, "%s", filter_str_annex ); if ( ( filter_main > 0 ) || ( do_sort && ( sort_table == T_MAIN ) ) ) { *curr_tables = ','; curr_tables++; /* also add junction condition */ curr_fields += sprintf( curr_fields, " AND %s.id=%s.id", MAIN_TABLE, ANNEX_TABLE ); } else first_table = ANNEX_TABLE; curr_tables += sprintf( curr_tables, "%s", ANNEX_TABLE ); } if ( ( filter_stripe_items > 0 ) || ( do_sort && ( sort_table == T_STRIPE_ITEMS ) ) ) { if ( filter_stripe_items > 0 ) curr_fields += sprintf( curr_fields, "%s", filter_str_stripe_items ); if ( ( filter_main > 0 ) || ( do_sort && ( sort_table == T_MAIN ) ) || ( filter_annex > 0 ) || ( do_sort && ( sort_table == T_ANNEX ) ) ) { *curr_tables = ','; curr_tables++; /* add junction condition */ if ( ( filter_main > 0 ) || ( do_sort && ( sort_table == T_MAIN ) ) ) curr_fields += sprintf( curr_fields, " AND %s.id=%s.id", MAIN_TABLE, STRIPE_ITEMS_TABLE ); if ( ( filter_annex > 0 ) || ( do_sort && ( sort_table == T_ANNEX ) ) ) curr_fields += sprintf( curr_fields, " AND %s.id=%s.id", ANNEX_TABLE, STRIPE_ITEMS_TABLE ); } else first_table = STRIPE_ITEMS_TABLE; curr_tables += sprintf( curr_tables, "%s", STRIPE_ITEMS_TABLE ); } if ( ( filter_stripe_info > 0 ) || ( do_sort && ( sort_table == T_STRIPE_INFO ) ) ) { if ( filter_stripe_info > 0 ) curr_fields += sprintf( curr_fields, "%s", filter_str_stripe_info ); if ( ( filter_main > 0 ) || ( do_sort && ( sort_table == T_MAIN ) ) || ( filter_annex > 0 ) || ( do_sort && ( sort_table == T_ANNEX ) ) || ( filter_stripe_items > 0 ) || ( do_sort && ( sort_table == T_STRIPE_ITEMS ) ) ) { *curr_tables = ','; curr_tables++; /* add junction condition */ if ( ( filter_main > 0 ) || ( do_sort && ( sort_table == T_MAIN ) ) ) curr_fields += sprintf( curr_fields, " AND %s.id=%s.id", MAIN_TABLE, STRIPE_INFO_TABLE ); if ( ( filter_annex > 0 ) || ( do_sort && ( sort_table == T_ANNEX ) ) ) curr_fields += sprintf( curr_fields, " AND %s.id=%s.id", ANNEX_TABLE, STRIPE_INFO_TABLE ); if ( ( filter_stripe_items > 0 ) || ( do_sort && ( sort_table == T_STRIPE_ITEMS ) ) ) curr_fields += sprintf( curr_fields, " AND %s.id=%s.id", STRIPE_ITEMS_TABLE, STRIPE_INFO_TABLE ); } else first_table = STRIPE_INFO_TABLE; curr_tables += sprintf( curr_tables, "%s", STRIPE_INFO_TABLE ); } sprintf( query, "SELECT %s.id AS id FROM %s WHERE %s", first_table, tables, fields ); } } else if ( do_sort ) { /* entries must be selected depending on sort order */ if ( sort_table == T_MAIN ) strcpy( query, "SELECT id FROM " MAIN_TABLE ); else if ( sort_table == T_ANNEX ) strcpy( query, "SELECT id FROM " ANNEX_TABLE ); else if ( sort_table == T_STRIPE_ITEMS ) strcpy( query, "SELECT DISTINCT(id) FROM " STRIPE_ITEMS_TABLE ); else if ( sort_table == T_STRIPE_INFO ) strcpy( query, "SELECT id FROM " STRIPE_INFO_TABLE ); } else { DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be selected" ); strcpy( query, "SELECT id FROM " MAIN_TABLE ); } query_end = query + strlen( query ); /* sort order */ if ( do_sort ) { if ( sort_table == T_MAIN ) { query_end += sprintf( query_end, " ORDER BY " MAIN_TABLE ".%s ", field_infos[p_sort_type->attr_index].field_name ); } else if ( sort_table == T_ANNEX ) { query_end += sprintf( query_end, " ORDER BY " ANNEX_TABLE ".%s ", field_infos[p_sort_type->attr_index].field_name ); } else if ( sort_table == T_STRIPE_ITEMS ) { query_end += sprintf( query_end, " ORDER BY " STRIPE_ITEMS_TABLE ".storage_unit " ); } else if ( sort_table == T_STRIPE_INFO ) { query_end += sprintf( query_end, " ORDER BY " STRIPE_INFO_TABLE ".pool_name " ); } if ( p_sort_type->order == SORT_ASC ) query_end += sprintf( query_end, "ASC" ); else query_end += sprintf( query_end, "DESC" ); } /* iterator opt */ if ( p_opt && ( p_opt->list_count_max > 0 ) ) { query_end += sprintf( query_end, " LIMIT %u", p_opt->list_count_max ); } /* allocate a new iterator */ it = ( lmgr_iterator_t * ) MemAlloc( sizeof( lmgr_iterator_t ) ); it->p_mgr = p_mgr; #ifdef _DEBUG_DB printf( "Iterator is specified by: %s\n", query ); #endif /* execute request */ rc = db_exec_sql( &p_mgr->conn, query, &it->select_result ); if ( rc ) { MemFree( it ); return NULL; } else return it; }
int ListMgr_MassUpdate( lmgr_t * p_mgr, const lmgr_filter_t * p_filter, const attr_set_t * p_attr_set ) { char query[4096]; char filter_str_main[2048]; char filter_str_annex[2048]; char filter_str_stripe_info[2048]; char filter_str_stripe_units[2048]; int filter_main = 0; int filter_annex = 0; int filter_stripe_info = 0; int filter_stripe_units = 0; int rc, count; int impact_all = FALSE; int filter_unic = FALSE; char fields[2048]; char tmp_table_name[256]; int tmp_table_created = FALSE; filter_str_main[0] = '\0'; filter_str_annex[0] = '\0'; filter_str_stripe_info[0] = '\0'; filter_str_stripe_units[0] = '\0'; /* /!\ possible cases: * - simplest: the fields of the filter and the attributes to be changed are in the same table * - harder: the fields of the filter are in the same table and attributes are in another different table */ /* 1) check the location of filters */ if ( p_filter ) { filter_main = filter2str( p_mgr, filter_str_main, p_filter, T_MAIN, FALSE, FALSE ); if ( annex_table ) filter_annex = filter2str( p_mgr, filter_str_annex, p_filter, T_ANNEX, FALSE, FALSE ); else filter_annex = 0; filter_stripe_info = filter2str( p_mgr, filter_str_stripe_info, p_filter, T_STRIPE_INFO, FALSE, FALSE ); filter_stripe_units = filter2str( p_mgr, filter_str_stripe_units, p_filter, T_STRIPE_ITEMS,FALSE, FALSE ); if ( filter_main + filter_annex + filter_stripe_info + filter_stripe_units == 0 ) { /* all records */ impact_all = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be affected" ); } else if ( filter_main && !( filter_annex || filter_stripe_info || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " MAIN_TABLE " table" ); } else if ( filter_annex && !( filter_main || filter_stripe_info || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " ANNEX_TABLE " table" ); } else if ( filter_stripe_info && !( filter_main || filter_annex || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_INFO_TABLE " table" ); } else if ( filter_stripe_units && !( filter_main || filter_annex || filter_stripe_info ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_ITEMS_TABLE " table" ); } else DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter on several tables: " MAIN_TABLE ":%d, " ANNEX_TABLE ":%d, " STRIPE_INFO_TABLE ":%d, " STRIPE_ITEMS_TABLE ":%d", filter_main, filter_annex, filter_stripe_info, filter_stripe_units ); } else { impact_all = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be affected" ); } /* 2) check if attributes to be changed are in MAIN table */ /* 3) if filters are in MAIN table too, make a simple update statement */ /* 4) if not, make a compound request: update xxx set xxx WHERE pk in ( select pk from ... where ... ) */ rc = lmgr_begin( p_mgr ); if ( rc ) return rc; /* perform updates on MAIN TABLE */ count = attrset2updatelist( p_mgr, fields, p_attr_set, T_MAIN, FALSE ); if ( count < 0 ) return -count; if ( count > 0 ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Update on " MAIN_TABLE " table" ); if ( impact_all ) { /* all records are impacted */ sprintf( query, "UPDATE " MAIN_TABLE " SET %s", fields ); } else if ( filter_unic && filter_main ) { /* update on the same table as filter */ sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE %s", fields, filter_str_main ); } else if ( filter_unic ) { /* update is on a different table than filter */ if ( filter_annex ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " ANNEX_TABLE " WHERE %s", tmp_table_name, filter_str_annex ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_units ) { if ( !tmp_table_created ) { sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); /* create temp table */ sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_ITEMS_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_units ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_info ) { if ( !tmp_table_created ) { sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); /* create temp table */ sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_INFO_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_info ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } } else { /* @todo mixed filter :-s */ rc = DB_NOT_SUPPORTED; goto rollback; } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* update on annex table ? */ if ( annex_table ) { count = attrset2updatelist( p_mgr, fields, p_attr_set, T_ANNEX, FALSE ); if ( count < 0 ) return -count; if ( count > 0 ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Update on " ANNEX_TABLE " table" ); if ( impact_all ) { /* all records are impacted */ sprintf( query, "UPDATE " ANNEX_TABLE " SET %s", fields ); } else if ( filter_unic && filter_annex ) { /* update on the same table as filter */ sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE %s", fields, filter_str_annex ); } else if ( filter_unic ) { /* update is on a different table than filter */ if ( filter_main ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " MAIN_TABLE " WHERE %s", tmp_table_name, filter_str_main ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_units ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_ITEMS_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_units ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_info ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_INFO_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_info ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } } else { /* @todo mixed filter :-s */ rc = DB_NOT_SUPPORTED; goto rollback; } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } } if ( ATTR_MASK_TEST( p_attr_set, stripe_info ) || ATTR_MASK_TEST( p_attr_set, stripe_items ) ) { /* XXX is there a case where stripe info is to be updated massively ? */ rc = DB_NOT_SUPPORTED; goto rollback; } if ( tmp_table_created ) { sprintf( query, "DROP TABLE %s", tmp_table_name ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } return lmgr_commit( p_mgr ); rollback: lmgr_rollback( p_mgr ); return rc; }
/** * 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 ); }
/** retrieve directory attributes (nbr of entries, avg size of entries)*/ int listmgr_get_dirattrs( lmgr_t * p_mgr, PK_ARG_T dir_pk, attr_set_t * p_attrs ) { GString *req; result_handle_t result; char *str_info[1]; int rc = 0; int tmp_val; long long tmp_long; if (ATTR_MASK_TEST(p_attrs, type) && (strcmp(ATTR(p_attrs, type), STR_TYPE_DIR) != 0)) { DisplayLog(LVL_FULL, LISTMGR_TAG, "Type='%s' != 'dir' => unsetting dirattrs in attr mask", ATTR(p_attrs, type)); p_attrs->attr_mask = attr_mask_and_not(&p_attrs->attr_mask, &dir_attr_set); return 0; } req = g_string_new(NULL); /* get child entry count from DNAMES_TABLE */ if (ATTR_MASK_TEST(p_attrs, dircount)) { g_string_printf(req, "SELECT %s FROM "DNAMES_TABLE" WHERE parent_id="DPK, dirattr2str(ATTR_INDEX_dircount), dir_pk); rc = db_exec_sql(&p_mgr->conn, req->str, &result); if (rc) goto free_str; rc = db_next_record(&p_mgr->conn, &result, str_info, 1); if (rc == DB_END_OF_LIST) { ATTR_MASK_UNSET(p_attrs, dircount); rc = DB_SUCCESS; } else if (rc == DB_SUCCESS) { if (str_info[0] == NULL) /* count(*) should at least return 0 */ rc = DB_REQUEST_FAILED; else { tmp_val = str2int(str_info[0]); if (tmp_val != -1) { ATTR_MASK_SET(p_attrs, dircount); ATTR(p_attrs, dircount) = tmp_val; rc = DB_SUCCESS; } else /* invalid output format */ rc = DB_REQUEST_FAILED; } } db_result_free(&p_mgr->conn, &result); if (rc) goto free_str; } /* get avgsize of child entries from MAIN_TABLE */ if (ATTR_MASK_TEST(p_attrs, avgsize)) { g_string_printf(req, "SELECT %s FROM "MAIN_TABLE" m, "DNAMES_TABLE" d" " WHERE m.id = d.id and type='file' and d.parent_id="DPK, dirattr2str(ATTR_INDEX_avgsize), dir_pk); rc = db_exec_sql(&p_mgr->conn, req->str, &result); if (rc) goto free_str; rc = db_next_record(&p_mgr->conn, &result, str_info, 1); if (rc == DB_END_OF_LIST) ATTR_MASK_UNSET(p_attrs, avgsize); else if (rc == DB_SUCCESS) { if (str_info[0] == NULL) { /* NULL if no entry matches the criteria */ ATTR_MASK_UNSET(p_attrs, avgsize); rc = DB_SUCCESS; } else { tmp_long = str2bigint(str_info[0]); if (tmp_long != -1LL) { ATTR_MASK_SET(p_attrs, avgsize); ATTR(p_attrs, avgsize) = tmp_long; rc = DB_SUCCESS; } else /* invalid output format */ rc = DB_REQUEST_FAILED; } } db_result_free(&p_mgr->conn, &result); } free_str: g_string_free(req, TRUE); return rc; }
/** * Retrieve entry attributes from its primary key */ int listmgr_get_by_pk( lmgr_t * p_mgr, PK_ARG_T pk, attr_set_t * p_info ) { int rc; char fieldlist[4096] = ""; char *first_table = NULL; char from[1024] = ""; char query[4096] = ""; /* we assume there is not more than 128 fields */ char *result_tab[128]; result_handle_t result; int checkmain = 1; int main_count = 0, annex_count = 0, name_count = 0; if (p_info == NULL) return 0; /* init entry info */ memset( &p_info->attr_values, 0, sizeof( entry_info_t ) ); fieldlist[0] = '\0'; /* retrieve source info for generated fields */ add_source_fields_for_gen( &p_info->attr_mask ); /* get info from main table (if asked) */ main_count = attrmask2fieldlist(fieldlist, p_info->attr_mask, T_MAIN, FALSE, FALSE, "", ""); if (main_count < 0) return -main_count; else if (main_count > 0) { checkmain = 0; first_table = MAIN_TABLE; sprintf(from, MAIN_TABLE); } annex_count = attrmask2fieldlist(fieldlist + strlen(fieldlist), p_info->attr_mask, T_ANNEX, first_table != NULL, FALSE, "", ""); if (annex_count < 0) return -annex_count; else if (annex_count > 0) { if (first_table) sprintf(from + strlen(from), " LEFT JOIN "ANNEX_TABLE" ON %s.id=" ANNEX_TABLE".id", first_table); else { first_table = ANNEX_TABLE; sprintf(from, ANNEX_TABLE); } } name_count = attrmask2fieldlist(fieldlist + strlen(fieldlist), p_info->attr_mask, T_DNAMES, first_table != NULL, FALSE, "", ""); if (name_count < 0) return -name_count; else if (name_count > 0) { if (first_table) /* it's OK to JOIN with NAMES table here even if there are multiple paths, * as we only take one result record. The important thing is to return * consistent values for parent_id, name and fullpath. */ sprintf(from + strlen(from), " LEFT JOIN "DNAMES_TABLE" ON %s.id=" DNAMES_TABLE".id", first_table); else { first_table = DNAMES_TABLE; sprintf(from, DNAMES_TABLE); } } if (first_table != NULL) { int shift = 0; sprintf(query, "SELECT %s FROM %s WHERE %s.id="DPK, fieldlist, from, first_table, pk); rc = db_exec_sql(&p_mgr->conn, query, &result); if (rc) return rc; rc = db_next_record(&p_mgr->conn, &result, result_tab, main_count + annex_count + name_count); /* END_OF_LIST means it does not exist */ if (rc == DB_END_OF_LIST) rc = DB_NOT_EXISTS; if (rc) goto free_res; /* set info from result */ if (main_count) { rc = result2attrset(T_MAIN, result_tab + shift, main_count, p_info); shift += main_count; if (rc) goto free_res; } if (annex_count) { rc = result2attrset(T_ANNEX, result_tab + shift, annex_count, p_info); shift += annex_count; if (rc) goto free_res; } if (name_count) { rc = result2attrset(T_DNAMES, result_tab + shift, name_count, p_info); shift += name_count; if (rc) goto free_res; } db_result_free(&p_mgr->conn, &result); } /* remove stripe info if it is not a file */ if (stripe_fields(p_info->attr_mask) && ATTR_MASK_TEST(p_info, type) && strcmp(ATTR(p_info, type), STR_TYPE_FILE) != 0) { p_info->attr_mask &= ~stripe_attr_set; } /* get stripe info if asked */ #ifdef _LUSTRE if (stripe_fields( p_info->attr_mask )) { rc = get_stripe_info( p_mgr, pk, &ATTR( p_info, stripe_info ), ATTR_MASK_TEST( p_info, stripe_items ) ? &ATTR( p_info, stripe_items ) : NULL ); if ( rc == DB_ATTR_MISSING || rc == DB_NOT_EXISTS ) { p_info->attr_mask &= ~ATTR_MASK_stripe_info; if ( ATTR_MASK_TEST( p_info, stripe_items ) ) p_info->attr_mask &= ~ATTR_MASK_stripe_items; } else if ( rc ) return rc; else checkmain = 0; /* entry exists */ } #else /* always clean them */ p_info->attr_mask &= ~(ATTR_MASK_stripe_info | ATTR_MASK_stripe_items); #endif /* special field dircount */ if (dirattr_fields( p_info->attr_mask )) { if (listmgr_get_dirattrs(p_mgr, pk, p_info)) { DisplayLog( LVL_MAJOR, LISTMGR_TAG, "listmgr_get_dirattrs failed for "DPK, pk ); p_info->attr_mask &= ~dir_attr_set; } } if (checkmain) { /* verify it exists in main table */ sprintf( query, "SELECT id FROM " MAIN_TABLE " WHERE id="DPK, pk ); /* execute the request */ rc = db_exec_sql( &p_mgr->conn, query, &result ); if ( rc ) return rc; rc = db_next_record( &p_mgr->conn, &result, result_tab, 1 ); db_result_free( &p_mgr->conn, &result ); if (rc) return DB_NOT_EXISTS; } /* compute generated fields if asked */ generate_fields( p_info ); p_mgr->nbop[OPIDX_GET]++; return DB_SUCCESS; free_res: db_result_free( &p_mgr->conn, &result ); return rc; } /* listmgr_get_by_pk */
/** * 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 */
/** * Main daemon routine */ int main( int argc, char **argv ) { int c = 0; char *bin = basename( argv[0] ); int rc; char err_msg[4096]; robinhood_config_t config; int chgd = 0; /* options */ char config_file[MAX_OPT_LEN] = ""; char badcfg[RBH_PATH_MAX]; int force_log_level = FALSE; int log_level = 0; int margin = 0; char output_file[MAX_OPT_LEN] = "/tmp/lov_objid"; lmgr_t lmgr; FILE * out; /* parse command line options */ while ((c = getopt(argc, argv, OPT_STRING)) != -1) { switch (c) { case 'l': force_log_level = TRUE; 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); } break; case 'f': rh_strncpy(config_file, optarg, MAX_OPT_LEN); break; case 'o': rh_strncpy(output_file, optarg, MAX_OPT_LEN); break; case 'm': margin = str2int(optarg); if (margin < 0) { fprintf( stderr, "Invalid parameter '%s' for '-m' option: positive integer expected\n", optarg ); exit(1); } break; case ':': case '?': default: display_help(bin); exit( 1 ); break; } } /* get default config file, if not specified */ if (SearchConfig(config_file, 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", config_file ); } /* only read ListMgr config */ if ( ReadRobinhoodConfig( 0, config_file, err_msg, &config, FALSE ) ) { fprintf( stderr, "Error reading configuration file '%s': %s\n", config_file, err_msg ); exit( 1 ); } process_config_file = config_file; /* set global configuration */ global_config = config.global_config; if ( force_log_level ) config.log_config.debug_level = log_level; else config.log_config.debug_level = LVL_MAJOR; /* no event message */ /* set logging to stderr for this tool */ strcpy( config.log_config.log_file, "stderr" ); strcpy( config.log_config.report_file, "stderr" ); strcpy( config.log_config.alert_file, "stderr" ); /* Initialize logging */ rc = InitializeLogs( bin, &config.log_config ); if ( rc ) { fprintf( stderr, "Error opening log files: rc=%d, errno=%d: %s\n", rc, errno, strerror( errno ) ); exit( rc ); } /* Initialize list manager */ rc = ListMgr_Init( &config.lmgr_config, TRUE ); if ( rc ) { DisplayLog( LVL_CRIT, TAG, "Error %d initializing list manager", rc ); exit( rc ); } else DisplayLog( LVL_DEBUG, TAG, "ListManager successfully initialized" ); if ( CheckLastFS( ) != 0 ) exit( 1 ); /* Create database access */ rc = ListMgr_InitAccess( &lmgr ); if ( rc ) { DisplayLog( LVL_CRIT, TAG, "Error %d: cannot connect to database", rc ); exit( rc ); } out = fopen(output_file, "w"); if (!out) { DisplayLog(LVL_CRIT, TAG, "Failed to open '%s' for writting: %s", output_file, strerror(errno)); return errno; } /* direct SQL request to retrieve the max object index from DB */ result_handle_t res; /* FIXME max on the low weight 32bits of the 'objid' 64bits value */ rc = db_exec_sql(&lmgr.conn, "SELECT ostidx, max(hex(cast(reverse(cast(details as binary(8))) as binary(4)))) " "FROM "STRIPE_ITEMS_TABLE" GROUP BY ostidx ORDER BY ostidx", &res); if (rc) goto db_error; int index = -1; do { char *resstr[2]; unsigned int ostidx; unsigned int objid; unsigned long long objid_long; resstr[0] = resstr[1] = NULL; rc = db_next_record( &lmgr.conn, &res, resstr, 2 ); if (rc == DB_END_OF_LIST) break; else if (rc != DB_SUCCESS) goto db_error; index ++; if (resstr[0] == NULL || resstr[1] == NULL) { DisplayLog(LVL_MAJOR, TAG, "ERROR: got NULL record from DB at index %u", index); rc = EINVAL; goto out; } /* resstr[0] is ost_idx */ if (sscanf(resstr[0], "%u", &ostidx) != 1) { DisplayLog(LVL_MAJOR, TAG, "ERROR: cannot parse OST index '%s' at index %u", resstr[0], index); rc = EINVAL; goto out; } else if (ostidx != index) { DisplayLog(LVL_MAJOR, TAG, "Warning: OST index %u not found in database, assuming current objid=1", index); objid_long = 1 + margin; printf("ostidx=%u, max objid=%016LX\n", ostidx, objid_long); fwrite(&objid_long, sizeof(objid_long), 1, out); continue; } /* resstr[1] is objid (hexa) */ if (sscanf(resstr[1], "%X", &objid) != 1) { DisplayLog(LVL_MAJOR, TAG, "ERROR: cannot parse objid '%s' at index %u", resstr[1], index); rc = EINVAL; goto out; } objid_long = objid + margin; printf("ostidx=%u, objid=%016LX\n", ostidx, objid_long); fwrite(&objid_long, sizeof(objid_long), 1, out); } while(rc == 0); fclose(out); ListMgr_CloseAccess( &lmgr ); return 0; db_error: DisplayLog( LVL_CRIT, TAG, "Database error %d\n", rc); out: ListMgr_CloseAccess( &lmgr ); 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 */