static int recov_status(void) { int rc; lmgr_recov_stat_t stats; rc = ListMgr_RecovStatus(&lmgr, &stats); if (rc) { if (rc == DB_NOT_EXISTS) fprintf(stderr, "ERROR: There is no pending recovery\n"); return rc; } printf("Current recovery status:\n"); print_recov_stats(false, &stats); printf("\n"); return 0; }
static int recov_reset(int force) { int rc; /* ask confirmation */ if ( !force ) { lmgr_recov_stat_t stats; char * buff = malloc(1024); size_t sz = 1024; rc = ListMgr_RecovStatus( &lmgr, &stats ); if (rc) { if ( rc == DB_NOT_EXISTS ) fprintf( stderr, "ERROR: There is no pending recovery\n" ); return rc; } printf( "\nWARNING: you are about to abort the current recovery.\n" ); printf( "All entries not yet recovered will be definitely lost!\n\n"); printf( "Current recovery status:\n"); print_recov_stats( FALSE, &stats ); printf("\n"); do { printf( "Do you really want to proceed [y/n]: " ); if ( getline( &buff, &sz, stdin ) > 0 ) { if ( !strcasecmp(buff, "y\n") || !strcasecmp(buff, "yes\n") ) break; else { printf("Aborted\n"); free(buff); return -ECANCELED; } } } while(1); free(buff); } return ListMgr_RecovReset( &lmgr ); }
int ListMgr_RecovComplete( lmgr_t * p_mgr, lmgr_recov_stat_t * p_stats ) { long long int diff; int rc; /* Check there is no more unprocessed entries */ rc = ListMgr_RecovStatus( p_mgr, p_stats ); if (rc) return rc; diff = p_stats->total - p_stats->status_count[RS_FILE_OK] - p_stats->status_count[RS_FILE_DELTA] - p_stats->status_count[RS_FILE_EMPTY] - p_stats->status_count[RS_NON_FILE] - p_stats->status_count[RS_NOBACKUP] - p_stats->status_count[RS_ERROR]; if (diff > 0) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "Cannot complete recovery: there are still %lld unprocessed files", diff ); return DB_NOT_ALLOWED; } /* clear all */ return ListMgr_RecovReset( p_mgr ); }
/** * 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 ); }