/* * Updating accounting of size when closing a persistent file we created */ static void adjust_size_persistent_file_new(workfile_set *work_set, int64 size) { #if USE_ASSERT_CHECKING bool isCached = (NULL != work_set) && Cache_IsCached(CACHE_ENTRY_HEADER(work_set)); #endif Assert(NULL != work_set && !isCached); work_set->size += size; elog(gp_workfile_caching_loglevel, "closed new persistent file, added size " INT64_FORMAT " to set space", size); }
/* * Close a spill file set. If we're planning to re-use it, insert it in the * cache. If not, let the cleanup routine delete the files and free up memory. */ void workfile_mgr_close_set(workfile_set *work_set) { Assert(work_set!=NULL); elog(gp_workfile_caching_loglevel, "closing workfile set: location: %s, size=" INT64_FORMAT " in_progress_size=" INT64_FORMAT, work_set->path, work_set->size, work_set->in_progress_size); CacheEntry *cache_entry = CACHE_ENTRY_HEADER(work_set); Cache_Release(workfile_mgr_cache, cache_entry); }
/* * Updating accounting of size when closing an existing persistent file * we opened for reading */ static void adjust_size_persistent_file_existing(workfile_set *work_set, int64 size) { #if USE_ASSERT_CHECKING bool isCached = (NULL != work_set) && Cache_IsCached(CACHE_ENTRY_HEADER(work_set)); #endif AssertEquivalent((NULL != work_set), isCached); elog(gp_workfile_caching_loglevel, "closing existing persistent file, nothing to do"); return; }
/* * Updating accounting of size when closing a temporary file we created */ static void adjust_size_temp_file_new(workfile_set *work_set, int64 size) { #if USE_ASSERT_CHECKING bool isCached = (NULL != work_set) && Cache_IsCached(CACHE_ENTRY_HEADER(work_set)); #endif Assert(!isCached); AssertImply((NULL != work_set), work_set->size == 0); AssertImply((NULL != work_set), work_set->in_progress_size >= size); if (NULL != work_set) { work_set->in_progress_size -= size; } WorkfileDiskspace_Commit(0, size, true /* update_query_size */); elog(gp_workfile_caching_loglevel, "closed and deleted temp file, subtracted size " INT64_FORMAT " from disk space", size); }
/* * Close a spill file set. If we're planning to re-use it, insert it in the * cache. If not, let the cleanup routine delete the files and free up memory. */ void workfile_mgr_close_set(workfile_set *work_set) { Assert(work_set!=NULL); /* Although work_set is in shared memory only this process has access to it */ if (work_set->prev) work_set->prev->next = work_set->next; else open_workfile_sets = work_set->next; if (work_set->next) work_set->next->prev = work_set->prev; elog(gp_workfile_caching_loglevel, "closing workfile set: location: %s, size=" INT64_FORMAT " in_progress_size=" INT64_FORMAT, work_set->path, work_set->size, work_set->in_progress_size); CacheEntry *cache_entry = CACHE_ENTRY_HEADER(work_set); Cache_Release(workfile_mgr_cache, cache_entry); }
/* * Updating accounting of size when closing a temporary file we created */ static void adjust_size_temp_file_new(workfile_set *work_set, int64 size) { #if USE_ASSERT_CHECKING bool isCached = (NULL != work_set) && Cache_IsCached(CACHE_ENTRY_HEADER(work_set)); #endif Assert(!isCached); AssertImply((NULL != work_set), work_set->size == 0); AssertImply((NULL != work_set), work_set->in_progress_size >= size); if (NULL != work_set) { work_set->in_progress_size -= size; } WorkfileDiskspace_Commit(0 /* commit_bytes */, size, true /* update_query_size */); elog(gp_workfile_caching_loglevel, "closed and deleted temp file, subtracted size " INT64_FORMAT " from disk space", size); /* About to physically delete a file we created. Update the per-query file count as well */ WorkfileQueryspace_SubtractWorkfile(1 /* nFiles */); }
/* * Workfile-manager specific function to clean up before releasing a * workfile set from the cache. * */ static void workfile_mgr_cleanup_set(const void *resource) { workfile_set *work_set = (workfile_set *) resource; ereport(gp_workfile_caching_loglevel, (errmsg("workfile mgr cleanup deleting set: key=0x%0xd, size=" INT64_FORMAT " in_progress_size=" INT64_FORMAT " path=%s", work_set->key, work_set->size, work_set->in_progress_size, work_set->path), errprintstack(true))); workfile_mgr_delete_set_directory(work_set->path); /* * The most accurate size of a workset is recorded in work_set->in_progress_size. * work_set->size is only updated when we close a file, so it lags behind */ Assert(work_set->in_progress_size >= work_set->size); int64 size_to_delete = work_set->in_progress_size; elog(gp_workfile_caching_loglevel, "Subtracting " INT64_FORMAT " from workfile diskspace", size_to_delete); /* * When subtracting the size of this workset from our accounting, * only update the per-query counter if we created the workset. * In that case, the state is ACQUIRED, otherwise is CACHED or DELETED */ CacheEntry *cacheEntry = CACHE_ENTRY_HEADER(resource); bool update_query_space = (cacheEntry->state == CACHE_ENTRY_ACQUIRED); WorkfileDiskspace_Commit(0, size_to_delete, update_query_space); }
/* * Close a spill file set. If we're planning to re-use it, insert it in the * cache. If not, let the cleanup routine delete the files and free up memory. */ void workfile_mgr_close_set(workfile_set *work_set) { Assert(work_set!=NULL); elog(gp_workfile_caching_loglevel, "closing workfile set: can_be_reused=%d complete=%d location: %s, size=" INT64_FORMAT " in_progress_size=" INT64_FORMAT, work_set->can_be_reused, work_set->complete, work_set->path, work_set->size, work_set->in_progress_size); CacheEntry *cache_entry = CACHE_ENTRY_HEADER(work_set); if (Cache_IsCached(cache_entry)) { /* Workset came from cache. Just release it, nothing to do */ Cache_Release(workfile_mgr_cache, cache_entry); return; } if (work_set->complete && work_set->can_be_reused) { cache_entry->size = work_set->size; /* We want to keep this one around. Insert into cache */ Cache_Insert(workfile_mgr_cache, cache_entry); Cache_Release(workfile_mgr_cache, cache_entry); return; } /* * Fall-through case: We need to delete this work_set, as it's not reusable. */ Assert(!work_set->complete || !work_set->can_be_reused); Cache_Release(workfile_mgr_cache, cache_entry); }
/* * Workfile-manager specific function to clean up before releasing a * workfile set from the cache. * */ static void workfile_mgr_cleanup_set(const void *resource) { workfile_set *work_set = (workfile_set *) resource; /* * We have to make this callback function return cleanly ALL the * time. It shouldn't throw an exception. * We must try to clean up as much as we can in the callback, and * then never be called again. * This means holding interrupts, catching and handling all exceptions. */ if (work_set->on_disk) { ereport(gp_workfile_caching_loglevel, (errmsg("workfile mgr cleanup deleting set: key=0x%0xd, size=" INT64_FORMAT " in_progress_size=" INT64_FORMAT " path=%s", work_set->key, work_set->size, work_set->in_progress_size, work_set->path), errprintstack(true))); Assert(NULL == work_set->set_plan); PG_TRY(); { #ifdef FAULT_INJECTOR FaultInjector_InjectFaultIfSet( WorkfileCleanupSet, DDLNotSpecified, "", /* databaseName */ "" /* tableName */ ); #endif /* Prevent interrupts while cleaning up */ HOLD_INTERRUPTS(); workfile_mgr_delete_set_directory(work_set->path); /* Now we can allow interrupts again */ RESUME_INTERRUPTS(); } PG_CATCH(); { elog(LOG, "Cleaning up workfile set directory path=%s failed. Proceeding", work_set->path); /* We're not re-throwing the error. Otherwise we'll end up having * to clean up again, probably failing again. */ } PG_END_TRY(); /* * The most accurate size of a workset is recorded in work_set->in_progress_size. * work_set->size is only updated when we close a file, so it lags behind */ Assert(work_set->in_progress_size >= work_set->size); int64 size_to_delete = work_set->in_progress_size; elog(gp_workfile_caching_loglevel, "Subtracting " INT64_FORMAT " from workfile diskspace", size_to_delete); /* * When subtracting the size of this workset from our accounting, * only update the per-query counter if we created the workset. * In that case, the state is ACQUIRED, otherwise is CACHED or DELETED */ CacheEntry *cacheEntry = CACHE_ENTRY_HEADER(resource); bool update_query_space = (cacheEntry->state == CACHE_ENTRY_ACQUIRED); WorkfileDiskspace_Commit(0, size_to_delete, update_query_space); } else { /* Non-physical workfile set, we need to free up the plan memory */ if (NULL != work_set->set_plan->serialized_plan) { pfree(work_set->set_plan->serialized_plan); } if (NULL != work_set->set_plan) { pfree(work_set->set_plan); } } }