/* * Main worker routine. Accepts dsm_handle as an argument */ static void bg_worker_main(Datum main_arg) { PartitionArgs *args; dsm_handle handle = DatumGetInt32(main_arg); /* Create resource owner */ CurrentResourceOwner = ResourceOwnerCreate(NULL, "CreatePartitionsWorker"); /* Attach to dynamic shared memory */ if (!handle) { ereport(WARNING, (errmsg("pg_pathman worker: invalid dsm_handle"))); } segment = dsm_attach(handle); args = dsm_segment_address(segment); /* Establish connection and start transaction */ BackgroundWorkerInitializeConnectionByOid(args->dbid, InvalidOid); StartTransactionCommand(); SPI_connect(); PushActiveSnapshot(GetTransactionSnapshot()); /* Create partitions */ args->result = create_partitions(args->relid, PATHMAN_GET_DATUM(args->value, args->by_val), args->value_type, &args->crashed); /* Cleanup */ SPI_finish(); PopActiveSnapshot(); CommitTransactionCommand(); dsm_detach(segment); }
/* attach worker to the shared memory segment, read the job structure */ static void initialize_worker(uint32 segment) { dsm_segment *seg; ResourceOwner old, tmp; /* Connect to dynamic shared memory segment. * * In order to attach a dynamic shared memory segment, we need a * resource owner. We cannot to StartTransactionCommand here, since * we haven't yet attached to the database: to do this, we need to * fetch information about connection properties from the shared * memory segment. */ old = CurrentResourceOwner; CurrentResourceOwner = ResourceOwnerCreate(NULL, "Background Worker"); seg = dsm_attach(segment); if (seg == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("unable to map dynamic shared memory segment"))); dsm_pin_mapping(seg); tmp = CurrentResourceOwner; CurrentResourceOwner = old; ResourceOwnerDelete(tmp); job = palloc(sizeof(JobDesc)); /* copy the arguments from shared memory segment */ memcpy(job, dsm_segment_address(seg), sizeof(JobDesc)); /* and detach it right away */ dsm_detach(seg); Assert(job->magic == JOB_MAGIC); job_run_function.schema = quote_identifier(job->schemaname); job_run_function.name = quote_identifier("run_job"); }
/* * Initialize dsm segment. Returns true if new segment was created and * false if attached to existing segment */ bool init_dsm_segment(size_t blocks_count, size_t block_size) { bool ret; /* if there is already an existing segment then attach to it */ if (dsm_cfg->segment_handle != 0) { ret = false; segment = dsm_attach(dsm_cfg->segment_handle); } /* * If segment hasn't been created yet or has already been destroyed * (it happens when last session detaches segment) then create new one */ if (dsm_cfg->segment_handle == 0 || segment == NULL) { /* create segment */ segment = dsm_create(block_size * blocks_count, 0); dsm_cfg->segment_handle = dsm_segment_handle(segment); dsm_cfg->first_free = 0; dsm_cfg->block_size = block_size; dsm_cfg->blocks_count = blocks_count; init_dsm_table(block_size, 0, dsm_cfg->blocks_count); ret = true; } /* * Keep mapping till the end of the session. Otherwise it would be * destroyed by the end of transaction */ dsm_pin_mapping(segment); return ret; }
/* * Attach process to dsm_array segment. This function is used for * background workers only. Use init_dsm_segment() in backend processes. */ void attach_dsm_array_segment() { segment = dsm_attach(dsm_cfg->segment_handle); }
/* * Background worker entrypoint. * * This is intended to demonstrate how a background worker can be used to * facilitate a parallel computation. Most of the logic here is fairly * boilerplate stuff, designed to attach to the shared memory segment, * notify the user backend that we're alive, and so on. The * application-specific bits of logic that you'd replace for your own worker * are attach_to_queues() and copy_messages(). */ void test_shm_mq_main(Datum main_arg) { dsm_segment *seg; shm_toc *toc; shm_mq_handle *inqh; shm_mq_handle *outqh; volatile test_shm_mq_header *hdr; int myworkernumber; PGPROC *registrant; /* * Establish signal handlers. * * We want CHECK_FOR_INTERRUPTS() to kill off this worker process just as * it would a normal user backend. To make that happen, we establish a * signal handler that is a stripped-down version of die(). We don't have * any equivalent of the backend's command-read loop, where interrupts can * be processed immediately, so make sure ImmediateInterruptOK is turned * off. */ pqsignal(SIGTERM, handle_sigterm); ImmediateInterruptOK = false; BackgroundWorkerUnblockSignals(); /* * Connect to the dynamic shared memory segment. * * The backend that registered this worker passed us the ID of a shared * memory segment to which we must attach for further instructions. In * order to attach to dynamic shared memory, we need a resource owner. * Once we've mapped the segment in our address space, attach to the table * of contents so we can locate the various data structures we'll need to * find within the segment. */ CurrentResourceOwner = ResourceOwnerCreate(NULL, "test_shm_mq worker"); seg = dsm_attach(DatumGetInt32(main_arg)); if (seg == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("unable to map dynamic shared memory segment"))); toc = shm_toc_attach(PG_TEST_SHM_MQ_MAGIC, dsm_segment_address(seg)); if (toc == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("bad magic number in dynamic shared memory segment"))); /* * Acquire a worker number. * * By convention, the process registering this background worker should * have stored the control structure at key 0. We look up that key to * find it. Our worker number gives our identity: there may be just one * worker involved in this parallel operation, or there may be many. */ hdr = shm_toc_lookup(toc, 0); SpinLockAcquire(&hdr->mutex); myworkernumber = ++hdr->workers_attached; SpinLockRelease(&hdr->mutex); if (myworkernumber > hdr->workers_total) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("too many message queue testing workers already"))); /* * Attach to the appropriate message queues. */ attach_to_queues(seg, toc, myworkernumber, &inqh, &outqh); /* * Indicate that we're fully initialized and ready to begin the main part * of the parallel operation. * * Once we signal that we're ready, the user backend is entitled to assume * that our on_dsm_detach callbacks will fire before we disconnect from * the shared memory segment and exit. Generally, that means we must have * attached to all relevant dynamic shared memory data structures by now. */ SpinLockAcquire(&hdr->mutex); ++hdr->workers_ready; SpinLockRelease(&hdr->mutex); registrant = BackendPidGetProc(MyBgworkerEntry->bgw_notify_pid); if (registrant == NULL) { elog(DEBUG1, "registrant backend has exited prematurely"); proc_exit(1); } SetLatch(®istrant->procLatch); /* Do the work. */ copy_messages(inqh, outqh); /* * We're done. Explicitly detach the shared memory segment so that we * don't get a resource leak warning at commit time. This will fire any * on_dsm_detach callbacks we've registered, as well. Once that's done, * we can go ahead and exit. */ dsm_detach(seg); proc_exit(1); }
void worker_test_main(Datum main_arg) { dsm_segment *seg; volatile test_shm_mq_header *hdr; PGPROC *registrant; pqsignal(SIGHUP, handle_sighup); pqsignal(SIGTERM, handle_sigterm); BackgroundWorkerUnblockSignals(); printf("worker_test_main: %d\n", DatumGetInt32(main_arg)); CurrentResourceOwner = ResourceOwnerCreate(NULL, "worker test"); seg = dsm_attach(DatumGetInt32(main_arg)); if (seg == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("unable to map dynamic shared memory segment"))); hdr = dsm_segment_address(seg); /* 開始 */ SpinLockAcquire(&hdr->mutex); hdr->workers_ready++; hdr->workers_attached++; SpinLockRelease(&hdr->mutex); registrant = BackendPidGetProc(MyBgworkerEntry->bgw_notify_pid); if (registrant == NULL) { elog(DEBUG1, "registrant backend has exited prematurely"); proc_exit(1); } SetLatch(®istrant->procLatch); /* Do the work */ BackgroundWorkerInitializeConnection(hdr->dbname, NULL); printf("DSM: %p\n", dsm_segment_address); #if 0 SetCurrentStatementStartTimestamp(); StartTransactionCommand(); SPI_connect(); PushActiveSnapshot(GetTransactionSnapshot()); pgstat_report_activity(STATE_RUNNING, "initializing spi_worker schema"); SPI_finish(); PopActiveSnapshot(); CommitTransactionCommand(); pgstat_report_activity(STATE_IDLE, NULL); #endif dsm_detach(seg); proc_exit(0); }