/* * Closes a given workfile and updates the diskspace accordingly * * work_set can be NULL for workfile that were created outside of the workfile manager, * e.g. for ShareInputScan workfiles or window functions * * Returns the actual size of the file on disk in bytes upon closing */ int64 workfile_mgr_close_file(workfile_set *work_set, ExecWorkFile *file, bool canReportError) { Assert(NULL != file); bool delOnClose = file->flags & EXEC_WORKFILE_DEL_ON_CLOSE; bool created = file->flags & EXEC_WORKFILE_CREATED; elog(gp_workfile_caching_loglevel, "closing file %s, delOnClose=%d", ExecWorkFile_GetFileName(file), delOnClose); int64 size = 0; PG_TRY(); { size = ExecWorkFile_Close(file, canReportError); } PG_CATCH(); { elog(gp_workfile_caching_loglevel, "Caught exception, file=%s, returned size=" INT64_FORMAT " actual size before adjustment=" INT64_FORMAT, file->fileName, size, ExecWorkFile_GetSize(file)); update_workset_size(work_set, delOnClose, created, ExecWorkFile_GetSize(file)); PG_RE_THROW(); } PG_END_TRY(); update_workset_size(work_set, delOnClose, created, size); return size; }
/* * Do a byte-by-byte comparison between a given plan and a saved one. * * Returns true if identical, false otherwise * */ static bool workfile_mgr_compare_plan(workfile_set *work_set, workfile_set_plan *sf_plan) { Assert(NULL != work_set); Assert(NULL != sf_plan); ExecWorkFile *plan_file = workfile_mgr_open_fileno(work_set, WORKFILE_NUM_ALL_PLAN); elog(gp_workfile_caching_loglevel, "Loading and comparing query plan from file %s", ExecWorkFile_GetFileName(plan_file)); if (plan_file == NULL) { elog(gp_workfile_caching_loglevel, "could not open plan file for matching for set %s", work_set->path); return false; } char buffer[BLCKSZ]; uint64 plan_offset = 0; bool match = false; while (true) { uint64 size_read = ExecWorkFile_Read(plan_file, buffer, sizeof(buffer)); if (plan_offset + size_read > sf_plan->serialized_plan_len) { /* Disk plan is larger than new plan. No match */ break; } if (size_read < sizeof(buffer) && plan_offset + size_read < sf_plan->serialized_plan_len) { /* Disk plan is smaller than new plan. No match */ break; } /* We have enough data in memory to compare */ char *plan_pointer = ((char *) sf_plan->serialized_plan ) + plan_offset; if ( memcmp(buffer, plan_pointer, size_read) != 0) { break; } /* Reached the end of both streams, with no miss-match */ if (size_read < sizeof(buffer)) { match = true; break; } plan_offset += size_read; } workfile_mgr_close_file(work_set, plan_file); return match; }
/* * For a new workfile, sets the capabilities flags according to * the known underlying file type capabilities and the method the file was created */ static void ExecWorkFile_SetFlags(ExecWorkFile *workfile, bool delOnClose, bool created) { Assert(workfile != NULL); /* Assert that only the creator of a file can delete it on close */ AssertImply(delOnClose, created); switch(workfile->fileType) { case BUFFILE: workfile->flags |= EXEC_WORKFILE_RANDOM_ACCESS; break; case BFZ: workfile->flags |= EXEC_WORKFILE_SUSPENDABLE; break; default: insist_log(false, "invalid work file type: %d", workfile->fileType); } if (delOnClose) { workfile->flags |= EXEC_WORKFILE_DEL_ON_CLOSE; } if (created) { workfile->flags |= EXEC_WORKFILE_CREATED; elog(gp_workfile_caching_loglevel, "Created workfile %s, delOnClose = %d", ExecWorkFile_GetFileName(workfile), delOnClose); } else { elog(gp_workfile_caching_loglevel, "Opened existing workfile %s, delOnClose = %d", ExecWorkFile_GetFileName(workfile), delOnClose); } if ((gp_workfile_limit_per_query > 0) || (gp_workfile_limit_per_segment > 0)) { workfile->flags |= EXEC_WORKFILE_LIMIT_SIZE; } }
/* * Save the serialized plan to a file in the workfile set. * It will be used to do full plan matching before reusing. */ static void workfile_mgr_save_plan(workfile_set *work_set, workfile_set_plan *sf_plan) { Assert(work_set); Assert(sf_plan); ExecWorkFile *plan_file = workfile_mgr_create_fileno(work_set, WORKFILE_NUM_ALL_PLAN); insist_log(plan_file != NULL, "Could not create temporary work file: %m"); elog(gp_workfile_caching_loglevel, "Saving query plan to file %s", ExecWorkFile_GetFileName(plan_file)); bool res = ExecWorkFile_Write(plan_file, sf_plan->serialized_plan, sf_plan->serialized_plan_len); if(!res) { workfile_mgr_report_error(); } workfile_mgr_close_file(work_set, plan_file); }