static void test_atomic_flag(void) { pg_atomic_flag flag; pg_atomic_init_flag(&flag); if (!pg_atomic_unlocked_test_flag(&flag)) elog(ERROR, "flag: unexpectedly set"); if (!pg_atomic_test_set_flag(&flag)) elog(ERROR, "flag: couldn't set"); if (pg_atomic_unlocked_test_flag(&flag)) elog(ERROR, "flag: unexpectedly unset"); if (pg_atomic_test_set_flag(&flag)) elog(ERROR, "flag: set spuriously #2"); pg_atomic_clear_flag(&flag); if (!pg_atomic_unlocked_test_flag(&flag)) elog(ERROR, "flag: unexpectedly set #2"); if (!pg_atomic_test_set_flag(&flag)) elog(ERROR, "flag: couldn't set"); pg_atomic_clear_flag(&flag); }
void cfs_lock_file(FileMap* map, char const* file_path) { long delay = CFS_LOCK_MIN_TIMEOUT; while (true) { uint64 count = pg_atomic_fetch_add_u32(&map->lock, 1); if (count < CFS_GC_LOCK) { break; } if (InRecovery) { /* Uhhh... looks like last GC was interrupted. * Try to recover file */ char* map_bck_path = psprintf("%s.map.bck", file_path); char* file_bck_path = psprintf("%s.bck", file_path); if (access(file_bck_path, R_OK) != 0) { /* There is no backup file: new map should be constructed */ int md2 = open(map_bck_path, O_RDWR|PG_BINARY, 0); if (md2 >= 0) { /* Recover map */ if (!cfs_read_file(md2, map, sizeof(FileMap))) { elog(LOG, "Failed to read file %s: %m", map_bck_path); } close(md2); } } else { /* Presence of backup file means that we still have unchanged data and map files. * Just remove backup files, grab lock and continue processing */ unlink(file_bck_path); unlink(map_bck_path); } pfree(file_bck_path); pfree(map_bck_path); break; } pg_atomic_fetch_sub_u32(&map->lock, 1); pg_usleep(delay); if (delay < CFS_LOCK_MAX_TIMEOUT) { delay *= 2; } } if (IsUnderPostmaster && cfs_gc_workers != 0 && pg_atomic_test_set_flag(&cfs_state->gc_started)) { cfs_start_background_gc(); } }
Datum cfs_start_gc(PG_FUNCTION_ARGS) { int i = 0; if (cfs_gc_workers == 0 && pg_atomic_test_set_flag(&cfs_state->gc_started)) { int j; BackgroundWorkerHandle** handles; cfs_stop = true; /* do just one iteration */ cfs_state->max_iterations = 1; cfs_state->n_workers = PG_GETARG_INT32(0); handles = (BackgroundWorkerHandle**)palloc(cfs_state->n_workers*sizeof(BackgroundWorkerHandle*)); for (i = 0; i < cfs_state->n_workers; i++) { BackgroundWorker worker; MemSet(&worker, 0, sizeof(worker)); sprintf(worker.bgw_name, "cfs-worker-%d", i); worker.bgw_flags = BGWORKER_SHMEM_ACCESS; worker.bgw_start_time = BgWorkerStart_ConsistentState; worker.bgw_restart_time = 1; worker.bgw_main = cfs_bgworker_main; worker.bgw_main_arg = Int32GetDatum(i); if (!RegisterDynamicBackgroundWorker(&worker, &handles[i])) { break; } } for (j = 0; j < i; j++) { WaitForBackgroundWorkerShutdown(handles[j]); } pfree(handles); pg_atomic_clear_flag(&cfs_state->gc_started); } PG_RETURN_INT32(i); }