static void no_name_warning(PK_PARG_T pk, attr_set_t *p_attrs, unsigned int count) { DEF_PK(ppk); char msg[256]; entry_id2pk(&ATTR(p_attrs, parent_id), PTR_PK(ppk)); if (count > 1) snprintf(msg, sizeof(msg), "%u entries", count); else rh_strncpy(msg, "entry", sizeof(msg)); DisplayLog(LVL_MAJOR, LISTMGR_TAG, "WARNING: %s created without" " name or parent information: pk="DPK", name='%s', parent='%s'", msg, pk, ATTR_MASK_TEST(p_attrs, name) ? ATTR(p_attrs, name) : "", ATTR_MASK_TEST(p_attrs, parent_id) ? ppk : ""); }
/* directory callback */ static int dircb(wagon_t * id_list, attr_set_t * attr_list, unsigned int entry_count, void * dummy ) { /* retrieve child entries for all directories */ int i, rc; for (i = 0; i < entry_count; i++) { wagon_t * chids = NULL; attr_set_t * chattrs = NULL; unsigned int chcount = 0; int j; /* match condition on dirs parent */ if (!is_expr || (EntryMatches(&id_list[i].id, &attr_list[i], &match_expr, NULL) == POLICY_MATCH)) { /* don't display dirs if no_dir is specified */ if (! (prog_options.no_dir && ATTR_MASK_TEST(&attr_list[i], type) && !strcasecmp(ATTR(&attr_list[i], type), STR_TYPE_DIR)) ) print_entry(&id_list[i], &attr_list[i]); } if (!prog_options.dir_only) { rc = ListMgr_GetChild( &lmgr, &entry_filter, id_list+i, 1, disp_mask | query_mask, &chids, &chattrs, &chcount); if (rc) { DisplayLog(LVL_MAJOR, FIND_TAG, "ListMgr_GetChild() failed with error %d", rc); return rc; } for (j = 0; j < chcount; j++) { if (!is_expr || (EntryMatches(&chids[j].id, &chattrs[j], &match_expr, NULL) == POLICY_MATCH)) print_entry(&chids[j], &chattrs[j]); ListMgr_FreeAttrs(&chattrs[j]); } free_wagon(chids, 0, chcount); MemFree(chids); MemFree(chattrs); } } return 0; }
static int alerter_alert(const entry_id_t *p_entry_id, attr_set_t *p_attrs, const action_params_t *params, post_action_e *after, db_cb_func_t db_cb_fn, void *db_cb_arg) { char *str_id = NULL; bool str_is_alloc = false; GString *gs = g_string_new(NULL); /* build alert string */ if (ATTR_MASK_TEST(p_attrs, fullpath)) { str_id = ATTR(p_attrs, fullpath); } else { asprintf(&str_id, DFID, PFID(p_entry_id)); str_is_alloc = true; } /** TODO build specific parameter that represents the alert rule */ #if 0 rc = BoolExpr2str(&entry_proc_conf.alert_list[i].boolexpr, stralert, 2*RBH_PATH_MAX); if ( rc < 0 ) strcpy( stralert, "Error building alert string" ); #endif /** TODO build specific parameter that represents attr mask for the rule (alert mask) */ print_attrs(gs, p_attrs, null_mask, 0); /* title: alert rule name */ RaiseEntryAlert(rbh_param_get(params, "title"), "entry matches alert rule", str_id, gs->str); g_string_free(gs, TRUE); if (str_is_alloc) free(str_id); return 0; }
/** * Bulk filtering in the DB. */ static int list_bulk(void) { attr_set_t root_attrs, attrs; entry_id_t root_id, id; int rc; struct stat st; struct lmgr_iterator_t *it; /* no tranvsersal => no wagon * so we need the path from the DB. */ query_mask |= ATTR_MASK_fullpath; ATTR_MASK_INIT(&root_attrs); rc = retrieve_root_id(&root_id); if (rc) return rc; /* root is not a part of the DB: print it now */ ATTR_MASK_SET(&root_attrs, fullpath); strcpy(ATTR(&root_attrs, fullpath), config.global_config.fs_path); if (lstat(ATTR(&root_attrs, fullpath), &st) == 0) { PosixStat2EntryAttr(&st, &root_attrs, TRUE); ListMgr_GenerateFields(&root_attrs, disp_mask | query_mask); } /* root has no name... */ ATTR_MASK_SET(&root_attrs, name); ATTR(&root_attrs, name)[0] = '\0'; /* match condition on dirs parent */ if (!is_expr || (EntryMatches(&root_id, &root_attrs, &match_expr, NULL) == POLICY_MATCH)) { /* don't display dirs if no_dir is specified */ if (! (prog_options.no_dir && ATTR_MASK_TEST(&root_attrs, type) && !strcasecmp(ATTR(&root_attrs, type), STR_TYPE_DIR))) { wagon_t w; w.id = root_id; w.fullname = ATTR(&root_attrs, fullpath); print_entry(&w, &root_attrs); } } /* list all, including dirs */ it = ListMgr_Iterator(&lmgr, &entry_filter, NULL, NULL); if (!it) { DisplayLog(LVL_MAJOR, FIND_TAG, "ERROR: cannot retrieve entry list from database"); return -1; } attrs.attr_mask = disp_mask | query_mask; while ((rc = ListMgr_GetNext(it, &id, &attrs)) == DB_SUCCESS) { if (!is_expr || (EntryMatches(&id, &attrs, &match_expr, NULL) == POLICY_MATCH)) { /* don't display dirs if no_dir is specified */ if (! (prog_options.no_dir && ATTR_MASK_TEST(&attrs, type) && !strcasecmp(ATTR(&attrs, type), STR_TYPE_DIR))) { wagon_t w; w.id = id; w.fullname = ATTR(&attrs, fullpath); print_entry(&w, &attrs); } /* don't display non dirs is dir_only is specified */ else if (! (prog_options.dir_only && ATTR_MASK_TEST(&attrs, type) && strcasecmp(ATTR(&attrs, type), STR_TYPE_DIR))) { wagon_t w; w.id = id; w.fullname = ATTR(&attrs, fullpath); print_entry(&w, &attrs); } else /* return entry don't match? */ DisplayLog(LVL_DEBUG, FIND_TAG, "Warning: returned DB entry doesn't match filter: %s", ATTR(&attrs, fullpath)); } ListMgr_FreeAttrs(&attrs); /* prepare next call */ attrs.attr_mask = disp_mask | query_mask; } ListMgr_CloseIterator(it); return 0; }
static inline void print_entry(const wagon_t *id, const attr_set_t * attrs) { char ostbuf[24576] = ""; #ifdef ATTR_INDEX_status if (prog_options.match_status) { if (ATTR_MASK_TEST(attrs, status) && (ATTR(attrs, status) != prog_options.status)) { /* no match -> no display */ return; } } #endif #ifdef _LUSTRE /* prepare OST display buffer */ if (prog_options.lsost && ATTR_MASK_TEST(attrs, stripe_items) && (ATTR(attrs, stripe_items).count > 0)) { /* leave a space as first char */ ostbuf[0] = ' '; FormatStripeList(ostbuf+1, sizeof(ostbuf)-2, &ATTR(attrs, stripe_items), TRUE); } #endif if (prog_options.ls) { const char * type; char date_str[128]; char mode_str[128]; #ifdef ATTR_INDEX_status const char * status_str = ""; /* add status after type */ if (ATTR_MASK_TEST(attrs, status) && (ATTR(attrs, status) != STATUS_UNKNOWN)) status_str = db_status2str(ATTR(attrs, status), 1); /* 1 for brief */ #define STATUS_FORMAT "%-10s" #define STATUS_VAL ,status_str #else #define STATUS_FORMAT "" #define STATUS_VAL #endif /* type2char */ if (!ATTR_MASK_TEST(attrs, type)) type = "?"; else type = type2char(ATTR(attrs, type)); memset(mode_str, 0, sizeof(mode_str)); mode_string(ATTR(attrs, mode), mode_str); if (!ATTR_MASK_TEST(attrs, last_mod)) strcpy(date_str, ""); else { time_t tt; struct tm stm; tt = ATTR(attrs, last_mod); strftime(date_str, 128, "%Y/%m/%d %T", localtime_r(&tt, &stm)); } if (ATTR_MASK_TEST(attrs, type) && !strcmp(ATTR(attrs, type), STR_TYPE_LINK) && ATTR_MASK_TEST(attrs, link)) /* display: id, type, mode, nlink, (status,) owner, group, size, mtime, path -> link */ printf(DFID" %-4s %s %3u "STATUS_FORMAT"%-10s %-10s %15"PRIu64" %20s %s -> %s\n", PFID(&id->id), type, mode_str, ATTR(attrs, nlink) STATUS_VAL, ATTR(attrs, owner), ATTR(attrs, gr_name), ATTR(attrs, size), date_str, id->fullname, ATTR(attrs,link)); else /* display all: id, type, mode, nlink, (status,) owner, group, size, mtime, path */ printf(DFID" %-4s %s %3u "STATUS_FORMAT"%-10s %-10s %15"PRIu64" %20s %s%s\n", PFID(&id->id), type, mode_str, ATTR(attrs, nlink) STATUS_VAL, ATTR(attrs, owner), ATTR(attrs, gr_name), ATTR(attrs, size), date_str, id->fullname, ostbuf); } else if (prog_options.lsost) /* lsost without -ls */ { const char * type; /* type2char */ if (!ATTR_MASK_TEST(attrs, type)) type = "?"; else type = type2char(ATTR(attrs, type)); /* display: id, type, size, path */ printf(DFID" %-4s %15"PRIu64" %s%s\n", PFID(&id->id), type, ATTR(attrs, size), id->fullname, ostbuf); } else if (prog_options.print) { /* just display name */ if (id->fullname) printf("%s%s\n", id->fullname, ostbuf); else printf(DFID"%s\n", PFID(&id->id), ostbuf); } if (prog_options.exec) { const char *vars[] = { "", id->fullname, NULL, NULL }; char * cmd = replace_cmd_parameters(prog_options.exec_cmd, vars); if (cmd) { execute_shell_command(FALSE, cmd, 0); free(cmd); } } }
static int recov_resume(int retry_errors) { struct lmgr_iterator_t *it; int rc, st; entry_id_t id, new_id; attr_set_t attrs, new_attrs; char buff[128]; /* TODO iter opt */ it = ListMgr_RecovResume(&lmgr, path_filter, retry_errors, NULL); if (it == NULL) { fprintf(stderr, "ERROR: cannot get the list of entries to be recovered\n"); return -1; } attrs.attr_mask = RECOV_ATTR_MASK; while (!terminate && ((rc = ListMgr_RecovGetNext(it, &id, &attrs, NULL)) != DB_END_OF_LIST)) { if (rc) { fprintf(stderr, "ERROR %d getting entry from recovery table\n", rc); ListMgr_CloseIterator(it); return rc; } FormatFileSize(buff, 128, ATTR(&attrs, size)); if (ATTR_MASK_TEST(&attrs, fullpath)) printf("Restoring %s (%s)...", ATTR(&attrs, fullpath), buff); else printf("Restoring " DFID " (%s)...", PFID(&id), buff); /* TODO process entries asynchronously, in parallel, in separate * threads */ st = rbhext_recover(&id, &attrs, &new_id, &new_attrs, NULL); if ((st == RS_FILE_OK) || (st == RS_FILE_EMPTY) || (st == RS_NON_FILE) || (st == RS_FILE_DELTA)) { /* don't insert readonly attrs */ new_attrs.attr_mask &= ~readonly_attr_set; /* insert the entry in the database, and update recovery status */ rc = ListMgr_Insert(&lmgr, &new_id, &new_attrs, true); if (rc) { fprintf(stderr, "DB insert failure for '%s'\n", ATTR(&new_attrs, fullpath)); st = RS_ERROR; } } /* old id must be used for impacting recovery table */ if (ListMgr_RecovSetState(&lmgr, &id, st)) st = RS_ERROR; switch (st) { case RS_FILE_OK: printf(" OK\n"); break; case RS_FILE_DELTA: printf(" OK (old version)\n"); break; case RS_NON_FILE: printf(" OK (non-file)\n"); break; case RS_FILE_EMPTY: printf(" OK (empty file)\n"); break; case RS_NOBACKUP: printf(" No backup available\n"); break; case RS_ERROR: printf(" FAILED\n"); break; default: printf(" ERROR st=%d, rc=%d\n", st, rc); break; } /* reset mask */ attrs.attr_mask = RECOV_ATTR_MASK; } return 0; }
/** * 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 */
static inline void print_entry(const wagon_t *id, const attr_set_t * attrs) { #ifdef ATTR_INDEX_status if (prog_options.match_status) { if (ATTR_MASK_TEST(attrs, status) && (ATTR(attrs, status) != prog_options.status)) { /* no match -> no display */ return; } } #endif if (prog_options.ls) { const char * type; char date_str[128]; char mode_str[128]; char uname[LOGIN_NAME_MAX]; char gname[LOGIN_NAME_MAX]; struct passwd *passwd; struct group *group; #ifdef ATTR_INDEX_status const char * status_str = ""; /* add status after type */ if (ATTR_MASK_TEST(attrs, status) && (ATTR(attrs, status) != STATUS_UNKNOWN)) status_str = db_status2str(ATTR(attrs, status), 1); /* 1 for brief */ #define STATUS_FORMAT "%-10s" #define STATUS_VAL ,status_str #else #define STATUS_FORMAT "" #define STATUS_VAL #endif /* type2char */ if (!ATTR_MASK_TEST(attrs, type)) type = "?"; else type = type2char(ATTR(attrs, type)); memset(mode_str, 0, sizeof(mode_str)); mode_string(ATTR(attrs, mode), mode_str); if (!ATTR_MASK_TEST(attrs, last_mod)) strcpy(date_str, ""); else { time_t tt; struct tm stm; tt = ATTR(attrs, last_mod); strftime(date_str, 128, "%Y/%m/%d %T", localtime_r(&tt, &stm)); } /* UID/GID to username/group. */ passwd = GetPwUid(ATTR(attrs, uid)); if (passwd) sprintf(uname, "%-10s", passwd->pw_name); else sprintf(uname, "%10u", ATTR(attrs, uid)); group = GetGrGid(ATTR(attrs, gid)); if (group) sprintf(gname, "%-10s", group->gr_name); else sprintf(gname, "%10u", ATTR(attrs, gid)); if (ATTR_MASK_TEST(attrs, type) && !strcmp(ATTR(attrs, type), STR_TYPE_LINK) && ATTR_MASK_TEST(attrs, link)) /* display: id, type, mode, nlink, (status,) owner, group, size, mtime, path -> link */ printf(DFID" %-4s %s %3u "STATUS_FORMAT"%-10s %-10s %15"PRIu64" %20s %s -> %s\n", PFID(&id->id), type, mode_str, ATTR(attrs, nlink) STATUS_VAL, uname, gname, ATTR(attrs, size), date_str, id->fullname, ATTR(attrs,link)); else /* display all: id, type, mode, nlink, (status,) owner, group, size, mtime, path */ printf(DFID" %-4s %s %3u "STATUS_FORMAT"%-10s %-10s %15"PRIu64" %20s %s\n", PFID(&id->id), type, mode_str, ATTR(attrs, nlink) STATUS_VAL, uname, gname, ATTR(attrs, size), date_str, id->fullname); } else if (prog_options.lsstat) { /* In the worst case scenario, each character will be escaped * to '\xXX'; so the string can be up to 4 time the name * length. */ char escaped_name[4*RBH_NAME_MAX+1]; /* Exclude any file with an uncomplete attributes. */ if ((attrs->attr_mask & LSSTAT_MASK) == LSSTAT_MASK) { printf("[%s,%u,%u,%zu,%lu,%lu,%lu]=%s\n", ATTR(attrs, type), ATTR(attrs, uid), ATTR(attrs, gid), ATTR(attrs, size), ATTR(attrs, ctime), ATTR(attrs, mtime), ATTR(attrs, atime), escape_name(id->fullname, escaped_name)); } else { printf("SKIPPED(%x,%x)=%s\n", attrs->attr_mask, LSSTAT_MASK, id->fullname); } } #ifdef _LUSTRE else if (prog_options.lsost) { char tmpbuf[24576]; FormatStripeList( tmpbuf, sizeof(tmpbuf)-1, &ATTR( attrs, stripe_items), FALSE); printf("%s\t%s\n", id->fullname, tmpbuf); } #endif else { /* just display name */ if (id->fullname) printf("%s\n", id->fullname); else printf(DFID"\n", PFID(&id->id)); } }
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; }
/** * For entries from FS scan, we must get the associated entry ID. */ int EntryProc_get_fid( struct entry_proc_op_t *p_op, lmgr_t * lmgr ) { #ifdef _HAVE_FID int rc; entry_id_t tmp_id; char buff[RBH_PATH_MAX]; char * path; /* 2 possible options: get fid using parent_fid/name or from fullpath */ if (ATTR_MASK_TEST(&p_op->fs_attrs, parent_id) && ATTR_MASK_TEST(&p_op->fs_attrs, name)) { BuildFidPath( &ATTR(&p_op->fs_attrs, parent_id), buff ); long len = strlen(buff); sprintf(buff+len, "/%s", ATTR(&p_op->fs_attrs, name)); path = buff; } else if (ATTR_MASK_TEST( &p_op->fs_attrs, fullpath)) { path = ATTR(&p_op->fs_attrs, fullpath); } else { DisplayLog( LVL_CRIT, ENTRYPROC_TAG, "Error: not enough information to get fid: parent_id/name or fullpath needed"); EntryProcessor_Acknowledge(p_op, -1, true); return EINVAL; } /* perform path2fid */ rc = Lustre_GetFidFromPath( path, &tmp_id ); /* Workaround for Lustre 2.3: if parent is root, llapi_path2fid returns EINVAL (see LU-3245). * In this case, get fid from full path. */ if ((rc == -EINVAL) && ATTR_MASK_TEST( &p_op->fs_attrs, fullpath)) { path = ATTR(&p_op->fs_attrs, fullpath); rc = Lustre_GetFidFromPath( path, &tmp_id ); } if ( rc ) { /* remove the operation from pipeline */ rc = EntryProcessor_Acknowledge(p_op, -1, true); if ( rc ) DisplayLog( LVL_CRIT, ENTRYPROC_TAG, "Error %d acknowledging stage STAGE_GET_FID.", rc ); } else { EntryProcessor_SetEntryId( p_op, &tmp_id ); /* go to GET_INFO_DB stage */ rc = EntryProcessor_Acknowledge(p_op, STAGE_GET_INFO_DB, false); if ( rc ) DisplayLog( LVL_CRIT, ENTRYPROC_TAG, "Error %d acknowledging stage STAGE_GET_FID.", rc ); } return rc; #else DisplayLog( LVL_CRIT, ENTRYPROC_TAG, "Error: unexpected stage in a filesystem with no fid: STAGE_GET_FID."); EntryProcessor_Acknowledge(p_op, -1, true); return EINVAL; #endif }
/** * check if the entry exists in the database and what info * must be retrieved. */ int EntryProc_get_info_db( struct entry_proc_op_t *p_op, lmgr_t * lmgr ) { int rc = 0; int next_stage = -1; /* -1 = skip */ attr_mask_t attr_allow_cached = null_mask; attr_mask_t attr_need_fresh = null_mask; uint32_t status_scope = 0; /* status mask only */ attr_mask_t tmp; const pipeline_stage_t *stage_info = &entry_proc_pipeline[p_op->pipeline_stage]; /* check if entry is in policies scope */ add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true, &status_scope); /* XXX also retrieve needed attributes to check the scope? */ /* get diff attributes from DB and FS (to allow comparison) */ p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &diff_mask); tmp = attr_mask_and_not(&diff_mask, &p_op->fs_attrs.attr_mask); p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp); if (entry_proc_conf.detect_fake_mtime) attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_creation_time); attr_allow_cached = attrs_for_status_mask(status_scope, false); attr_need_fresh = attrs_for_status_mask(status_scope, true); /* XXX check if entry is in policy scope? */ /* what must be retrieved from DB: */ tmp = attr_mask_and_not(&attr_allow_cached, &p_op->fs_attrs.attr_mask); p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &tmp); /* no dircount for non-dirs */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type) && !strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR)) { attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_dircount); } /* no readlink for non symlinks */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type)) /* likely */ { if (!strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_LINK)) { attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_link); /* check if it is known */ /* no stripe for symlinks */ attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_info); attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_items); } else attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_link); } if (!attr_mask_is_null(p_op->db_attr_need)) { p_op->db_attrs.attr_mask = p_op->db_attr_need; rc = ListMgr_Get(lmgr, &p_op->entry_id, &p_op->db_attrs); if (rc == DB_SUCCESS) { p_op->db_exists = 1; } else if (rc == DB_NOT_EXISTS ) { p_op->db_exists = 0; ATTR_MASK_INIT( &p_op->db_attrs ); } else { /* ERROR */ DisplayLog(LVL_CRIT, ENTRYPROC_TAG, "Error %d retrieving entry "DFID" from DB: %s.", rc, PFID(&p_op->entry_id), lmgr_err2str(rc)); p_op->db_exists = 0; ATTR_MASK_INIT( &p_op->db_attrs ); } } else { p_op->db_exists = ListMgr_Exists( lmgr, &p_op->entry_id ); } /* get status for all policies with a matching scope */ add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true, &p_op->fs_attr_need.status); tmp = attr_mask_and_not(&attr_need_fresh, &p_op->fs_attrs.attr_mask); p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp); if ( !p_op->db_exists ) { /* new entry */ p_op->db_op_type = OP_TYPE_INSERT; /* set creation time if it was not set by scan module */ if (!ATTR_MASK_TEST(&p_op->fs_attrs, creation_time)) { ATTR_MASK_SET( &p_op->fs_attrs, creation_time ); ATTR( &p_op->fs_attrs, creation_time ) = time(NULL); /* XXX min(atime,mtime,ctime)? */ } #ifdef _LUSTRE if (ATTR_MASK_TEST(&p_op->fs_attrs, type) && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_FILE ) /* only if it was not retrieved during the scan */ && !(ATTR_MASK_TEST(&p_op->fs_attrs, stripe_info) && ATTR_MASK_TEST(&p_op->fs_attrs, stripe_items))) { attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_info); attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_items); } #endif /* readlink for symlinks (if not already known) */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type) && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_LINK) && !ATTR_MASK_TEST(&p_op->fs_attrs, link)) { attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_link); } else { attr_mask_unset_index(&p_op->fs_attr_need, ATTR_INDEX_link); } #ifdef ATTR_INDEX_status /** @FIXME RBHv3 drop old-style status reference */ if (ATTR_MASK_TEST(&p_op->fs_attrs, type) #ifdef _LUSTRE_HSM && !strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_FILE )) #elif defined (_HSM_LITE) && (strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR ) != 0) && !p_op->extra_info.not_supp) #endif { p_op->fs_attr_need |= ATTR_MASK_status; #ifdef _HSM_LITE p_op->fs_attr_need |= (attr_need_fresh & ~p_op->fs_attrs.attr_mask); #endif } else {
/** * build LOVEA buffer from stripe information * @return size of significant information in buffer. */ ssize_t BuildLovEA(const entry_id_t * p_id, const attr_set_t * p_attrs, void * buff, size_t buf_sz) { int i; size_t len = 0; if (!ATTR_MASK_TEST(p_attrs, stripe_info)) /* no stripe info */ return 0; /* check inconsistent values */ if (!ATTR_MASK_TEST(p_attrs, stripe_items) || (ATTR(p_attrs, stripe_items).count != ATTR(p_attrs, stripe_info).stripe_count)) { DisplayLog(LVL_MAJOR, "BuildLovEA", "ERROR: inconsistent stripe info for "DFID, PFID(p_id)); return -1; } /* is there a pool? */ if (EMPTY_STRING(ATTR(p_attrs, stripe_info).pool_name)) { /* no => build lov_user_md_v1 */ struct lov_user_md_v1 * p_lum = (struct lov_user_md_v1 *) buff; len = sizeof(struct lov_user_md_v1) + ATTR(p_attrs, stripe_info).stripe_count * sizeof(struct lov_user_ost_data_v1); /* check buffer size */ if (buf_sz < len) return -1; p_lum->lmm_magic = LOV_USER_MAGIC_V1; p_lum->lmm_pattern = LOV_PATTERN_RAID0; /* the only supported for now */ #ifdef _HAVE_FID p_lum->lmm_object_id = p_id->f_oid; p_lum->lmm_object_seq = p_id->f_seq; #else /* lmm_object_gr for Lustre 1.x */ p_lum->lmm_object_id = p_id->inode; p_lum->lmm_object_gr = 0; #endif p_lum->lmm_stripe_size = ATTR(p_attrs, stripe_info).stripe_size; p_lum->lmm_stripe_count = ATTR(p_attrs, stripe_info).stripe_count; p_lum->lmm_stripe_offset = 0; /* set stripe items */ for ( i = 0; i < ATTR(p_attrs, stripe_items).count; i++ ) { p_lum->lmm_objects[i].l_ost_idx = ATTR(p_attrs, stripe_items).stripe[i].ost_idx; p_lum->lmm_objects[i].l_ost_gen = ATTR(p_attrs, stripe_items).stripe[i].ost_gen; #ifdef HAVE_OBJ_ID p_lum->lmm_objects[i].l_object_id = ATTR(p_attrs, stripe_items).stripe[i].obj_id; #ifdef HAVE_OBJ_SEQ p_lum->lmm_objects[i].l_object_seq = ATTR(p_attrs, stripe_items).stripe[i].obj_seq; #else p_lum->lmm_objects[i].l_object_gr = ATTR(p_attrs, stripe_items).stripe[i].obj_seq; #endif #else /* new structure (union of fid and id/seq) */ p_lum->lmm_objects[i].l_ost_oi.oi.oi_id = ATTR(p_attrs, stripe_items).obj_id; p_lum->lmm_objects[i].l_ost_oi.oi.oi_seq = ATTR(p_attrs, stripe_items).stripe[i].obj_seq; #endif } return len; } else { /* yes => build lov_user_md_v3 */ struct lov_user_md_v3 * p_lum = (struct lov_user_md_v3 *) buff; len = sizeof(struct lov_user_md_v3) + ATTR(p_attrs, stripe_info).stripe_count * sizeof(struct lov_user_ost_data_v1); /* check buffer size */ if (buf_sz < len) return (size_t)-1; p_lum->lmm_magic = LOV_USER_MAGIC_V3; p_lum->lmm_pattern = LOV_PATTERN_RAID0; /* the only supported for now */ #ifdef _HAVE_FID p_lum->lmm_object_id = p_id->f_oid; p_lum->lmm_object_seq = p_id->f_seq; #else /* lmm_object_gr for Lustre 1.x */ p_lum->lmm_object_id = p_id->inode; p_lum->lmm_object_gr = 0; #endif p_lum->lmm_stripe_size = ATTR(p_attrs, stripe_info).stripe_size; p_lum->lmm_stripe_count = ATTR(p_attrs, stripe_info).stripe_count; p_lum->lmm_stripe_offset = 0; /* pool name */ rh_strncpy(p_lum->lmm_pool_name, ATTR(p_attrs, stripe_info).pool_name, LOV_MAXPOOLNAME); /* set stripe items */ for ( i = 0; i < ATTR(p_attrs, stripe_items).count; i++ ) { p_lum->lmm_objects[i].l_ost_idx = ATTR(p_attrs, stripe_items).stripe[i].ost_idx; p_lum->lmm_objects[i].l_ost_gen = ATTR(p_attrs, stripe_items).stripe[i].ost_gen; #ifdef HAVE_OBJ_ID p_lum->lmm_objects[i].l_object_id = ATTR(p_attrs, stripe_items).stripe[i].obj_id; #ifdef HAVE_OBJ_SEQ p_lum->lmm_objects[i].l_object_seq = ATTR(p_attrs, stripe_items).stripe[i].obj_seq; #else p_lum->lmm_objects[i].l_object_gr = ATTR(p_attrs, stripe_items).stripe[i].obj_seq; #endif #else /* new structure (union of fid and id/seq) */ p_lum->lmm_objects[i].l_ost_oi.oi.oi_id = ATTR(p_attrs, stripe_items).obj_id; p_lum->lmm_objects[i].l_ost_oi.oi.oi_seq = ATTR(p_attrs, stripe_items).stripe[i].obj_seq; #endif } return len; } }
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; }
/** * Output the desired information for one file. */ void printf_entry(GArray *chunks, const wagon_t *id, const attr_set_t *attrs) { int i; for (i = 0; i < chunks->len; i++) { struct fchunk *chunk = &g_array_index(chunks, struct fchunk, i); const char *format = chunk->format->str; switch (chunk->directive) { case 0: #if __GNUC__ >= 7 /* * "format" below is constructed safely, ignore the warning. * Old GCC versions do not like these statements */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-security" #endif printf(format); #if __GNUC__ >= 7 #pragma GCC diagnostic pop #endif break; case 'A': printf_date(chunk, ATTR(attrs, last_access)); break; case 'b': printf(format, ATTR(attrs, blocks)); break; case 'C': printf_date(chunk, ATTR(attrs, last_mdchange)); break; case 'd': printf(format, ATTR(attrs, depth)); break; case 'f': printf(format, ATTR(attrs, name)); break; case 'g': if (global_config.uid_gid_as_numbers) printf(format, ATTR(attrs, gid).num); else printf(format, ATTR(attrs, gid).txt); break; case 'm': printf(format, ATTR(attrs, mode)); break; case 'M': { char mode_str[10]; /* mask + final '\0' */ mode_str[9] = 0; mode_string(ATTR(attrs, mode), mode_str); printf(format, mode_str); } break; case 'n': printf(format, ATTR(attrs, nlink)); break; case 'p': if (prog_options.escaped) printf(format, escape_name(id->fullname)); else printf(format, id->fullname); break; case 's': printf(format, ATTR(attrs, size)); break; case 'T': printf_date(chunk, ATTR(attrs, last_mod)); break; case 'u': if (global_config.uid_gid_as_numbers) printf(format, ATTR(attrs, uid).num); else printf(format, ATTR(attrs, uid).txt); break; case 'Y': { const char *type; if (!ATTR_MASK_TEST(attrs, type)) type = "?"; else type = type2char(ATTR(attrs, type)); printf(format, type); } break; case 'y': { char type; if (!ATTR_MASK_TEST(attrs, type)) type = '?'; else type = type2onechar(ATTR(attrs, type)); printf(format, type); } break; case 'z': printf(format, 0); break; case 'R': /* Robinhood specifiers */ switch (chunk->sub_directive) { case 'C': printf_date(chunk, ATTR(attrs, creation_time)); break; case 'c': printf(format, class_format(ATTR_MASK_TEST(attrs, fileclass) ? ATTR(attrs, fileclass) : NULL)); break; case 'f': { char fid_str[RBH_FID_LEN]; sprintf(fid_str, DFID_NOBRACE, PFID(&id->id)); printf(format, fid_str); } break; case 'm': if (ATTR_MASK_INFO_TEST(attrs, chunk->smi, chunk->rel_sm_info_index)) { switch (chunk->def->db_type) { case DB_UINT: printf(format, *(unsigned int *)SMI_INFO(attrs, chunk->smi, chunk-> rel_sm_info_index)); break; case DB_INT: printf(format, *(int *)SMI_INFO(attrs, chunk->smi, chunk->rel_sm_info_index)); break; case DB_BOOL: printf(format, *(bool *)SMI_INFO(attrs, chunk->smi, chunk->rel_sm_info_index)); break; case DB_TEXT: printf(format, SMI_INFO(attrs, chunk->smi, chunk->rel_sm_info_index)); break; default: break; } } else { switch (chunk->def->db_type) { case DB_UINT: case DB_INT: printf(format, 0); break; case DB_TEXT: printf(format, "[n/a]"); break; default: break; } } break; #ifdef _LUSTRE case 'o': if (ATTR_MASK_TEST(attrs, stripe_items) && (ATTR(attrs, stripe_items).count > 0)) { GString *osts = g_string_new(""); append_stripe_list(osts, &ATTR(attrs, stripe_items), true); printf(format, osts->str); g_string_free(osts, TRUE); } break; case 'p': { char fid_str[RBH_FID_LEN]; sprintf(fid_str, DFID_NOBRACE, PFID(&ATTR(attrs, parent_id))); printf(format, fid_str); break; } #endif case SUB_DIRECTIVE_STATUS: { unsigned int smi_index = chunk->smi->smi_index; if (ATTR_MASK_STATUS_TEST(attrs, smi_index)) printf(format, STATUS_ATTR(attrs, smi_index)); else printf(format, "[n/a]"); break; } } break; } } }
/** * 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 */
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; }
/** 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; }
int batch_insert_stripe_info(lmgr_t *p_mgr, pktype *pklist, int *validators, attr_set_t **p_attrs, unsigned int count, bool update_if_exists) { bool first; int i, rc = 0; int total_si; GString *req = g_string_new(""); attr_mask_t tmp_mask = { ATTR_MASK_stripe_info, 0, 0LL }; if (!attr_mask_is_null(sum_masks(p_attrs, count, tmp_mask))) { /* build batch request for STRIPE_INFO table */ g_string_assign(req, "INSERT INTO " STRIPE_INFO_TABLE " (" STRIPE_INFO_FIELDS ") VALUES "); first = true; for (i = 0; i < count; i++) { /* no request if the entry has no stripe info */ if (!ATTR_MASK_TEST(p_attrs[i], stripe_info)) continue; g_string_append_printf(req, "%s(" DPK ",%d,%u,%u,'%s')", first ? "" : ",", pklist[i], validators[i], ATTR(p_attrs[i], stripe_info).stripe_count, (unsigned int)ATTR(p_attrs[i], stripe_info).stripe_size, ATTR(p_attrs[i], stripe_info).pool_name); first = false; } if (update_if_exists) /* append "on duplicate key ..." */ g_string_append(req, " ON DUPLICATE KEY UPDATE " STRIPE_INFO_SET_VALUES); if (!first) { /* do nothing if no entry had stripe info */ rc = db_exec_sql(&p_mgr->conn, req->str, NULL); if (rc) goto out; } /* reset the string */ g_string_assign(req, ""); } /* Stripe items more tricky because we want to delete previous items * on update. */ /* If update_if_exists is false, insert them all as a batch. * For the update case, remove previous items before bluk insert. */ if (update_if_exists) { for (i = 0; i < count; i++) { /* no request if the entry has no stripe items */ if (!ATTR_MASK_TEST(p_attrs[i], stripe_items)) continue; g_string_printf(req, "DELETE FROM " STRIPE_ITEMS_TABLE " WHERE id=" DPK, pklist[i]); rc = db_exec_sql(&p_mgr->conn, req->str, NULL); if (rc) goto out; } } /* bulk insert stripe items (if any is set) */ tmp_mask.std = ATTR_MASK_stripe_items; if (attr_mask_is_null(sum_masks(p_attrs, count, tmp_mask))) goto out; total_si = 0; first = true; g_string_assign(req, "INSERT INTO " STRIPE_ITEMS_TABLE " (" STRIPE_ITEMS_FIELDS ") VALUES "); /* loop on all entries and all stripe items */ for (i = 0; i < count; i++) { int s; const stripe_items_t *p_items; /* skip the entry if it has no stripe items */ if (!ATTR_MASK_TEST(p_attrs[i], stripe_items)) continue; p_items = &ATTR(p_attrs[i], stripe_items); for (s = 0; s < p_items->count; s++) { char buff[2 * STRIPE_DETAIL_SZ + 1]; total_si++; if (buf2hex (buff, sizeof(buff), (unsigned char *)(&p_items->stripe[s].ost_gen), STRIPE_DETAIL_SZ) < 0) { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Buffer too small to store details stripe info"); memset(buff, 0, sizeof(buff)); } g_string_append_printf(req, "%s(" DPK ",%u,%u,x'%s')", first && (s == 0) ? "" : ",", pklist[i], s, p_items->stripe[s].ost_idx, buff); first = false; } } /* only execute it if there was some stripe items */ if (total_si > 0) rc = db_exec_sql(&p_mgr->conn, req->str, NULL); out: g_string_free(req, TRUE); return rc; }