Exemple #1
0
const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* node)
{
/**************************************
 *
 *	E X E _ l o o p e r
 *
 **************************************
 *
 * Functional description
 *	Cycle thru request execution tree.  Return next node for
 *	execution on stall or request complete.
 *
 **************************************/
	if (!request->req_transaction)
		ERR_post(Arg::Gds(isc_req_no_trans));

	SET_TDBB(tdbb);
	Jrd::Attachment* attachment = tdbb->getAttachment();
	jrd_tra* sysTransaction = attachment->getSysTransaction();
	Database* dbb = tdbb->getDatabase();

	if (!node || node->kind != DmlNode::KIND_STATEMENT)
		BUGCHECK(147);

	// Save the old pool and request to restore on exit
	StmtNode::ExeState exeState(tdbb, request, request->req_transaction);
	Jrd::ContextPoolHolder context(tdbb, request->req_pool);

	fb_assert(request->req_caller == NULL);
	request->req_caller = exeState.oldRequest;

	const SLONG save_point_number = (request->req_transaction->tra_save_point) ?
		request->req_transaction->tra_save_point->sav_number : 0;

	tdbb->tdbb_flags &= ~(TDBB_stack_trace_done | TDBB_sys_error);

	// Execute stuff until we drop

	const JrdStatement* statement = request->getStatement();

	while (node && !(request->req_flags & req_stall))
	{
		try
		{
			if (request->req_operation == jrd_req::req_evaluate)
			{
				if (--tdbb->tdbb_quantum < 0)
					JRD_reschedule(tdbb, 0, true);

				if (node->hasLineColumn)
				{
					request->req_src_line = node->line;
					request->req_src_column = node->column;
				}
			}

			node = node->execute(tdbb, request, &exeState);

			if (exeState.exit)
				return node;
		}	// try
		catch (const Firebird::Exception& ex)
		{
			ex.stuffException(tdbb->tdbb_status_vector);

			request->adjustCallerStats();

			// Ensure the transaction hasn't disappeared in the meantime
			fb_assert(request->req_transaction);

			// Skip this handling for errors coming from the nested looper calls,
			// as they're already handled properly. The only need is to undo
			// our own savepoints.
			if (exeState.catchDisabled)
			{
				if (request->req_transaction != sysTransaction)
				{
					while (request->req_transaction->tra_save_point &&
						request->req_transaction->tra_save_point->sav_number >= save_point_number)
					{
						++request->req_transaction->tra_save_point->sav_verb_count;
						VIO_verb_cleanup(tdbb, request->req_transaction);
					}
				}

				ERR_punt();
			}

			// If the database is already bug-checked, then get out
			if (dbb->dbb_flags & DBB_bugcheck)
				Firebird::status_exception::raise(tdbb->tdbb_status_vector);

			// Since an error happened, the current savepoint needs to be undone
			if (request->req_transaction != sysTransaction &&
				request->req_transaction->tra_save_point)
			{
				++request->req_transaction->tra_save_point->sav_verb_count;
				VIO_verb_cleanup(tdbb, request->req_transaction);
			}

			exeState.errorPending = true;
			exeState.catchDisabled = true;
			request->req_operation = jrd_req::req_unwind;
			request->req_label = 0;

			if (!(tdbb->tdbb_flags & TDBB_stack_trace_done) && !(tdbb->tdbb_flags & TDBB_sys_error))
			{
				stuff_stack_trace(request);
				tdbb->tdbb_flags |= TDBB_stack_trace_done;
			}
		}
	} // while()

	request->adjustCallerStats();

	fb_assert(request->req_auto_trans.getCount() == 0);

	// If there is no node, assume we have finished processing the
	// request unless we are in the middle of processing an
	// asynchronous message

	if (!node)
	{
		// Close active cursors
		for (const Cursor* const* ptr = request->req_cursors.begin();
			 ptr < request->req_cursors.end(); ++ptr)
		{
			if (*ptr)
				(*ptr)->close(tdbb);
		}

		request->req_flags &= ~(req_active | req_reserved);
		request->req_timestamp.invalidate();
		release_blobs(tdbb, request);
	}

	request->req_next = node;

	fb_assert(request->req_caller == exeState.oldRequest);
	request->req_caller = NULL;

	// Ensure the transaction hasn't disappeared in the meantime
	fb_assert(request->req_transaction);

	// In the case of a pending error condition (one which did not
	// result in a exception to the top of looper), we need to
	// delete the last savepoint

	if (exeState.errorPending)
	{
		if (request->req_transaction != sysTransaction)
		{
			while (request->req_transaction->tra_save_point &&
				request->req_transaction->tra_save_point->sav_number >= save_point_number)
			{
				++request->req_transaction->tra_save_point->sav_verb_count;
				VIO_verb_cleanup(tdbb, request->req_transaction);
			}
		}

		ERR_punt();
	}

	// if the request was aborted, assume that we have already
	// longjmp'ed to the top of looper, and therefore that the
	// last savepoint has already been deleted

	if (request->req_flags & req_abort) {
		ERR_post(Arg::Gds(isc_req_sync));
	}

	return node;
}
Exemple #2
0
RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages)
{
	if (tdbb->tdbb_flags & TDBB_use_db_page_space)
		return &rel_pages_base;

	Jrd::Attachment* attachment = tdbb->getAttachment();
	Database* dbb = tdbb->getDatabase();

	ULONG inst_id;
	// Vlad asked for this compile-time check to make sure we can contain a txn number here
	typedef int RangeCheck[sizeof(inst_id) >= sizeof(TraNumber)];

	if (rel_flags & REL_temp_tran)
	{
		if (tran > 0 && tran != MAX_TRA_NUMBER) //if (tran > 0)
			inst_id = tran;
		else if (tdbb->tdbb_temp_traid)
			inst_id = tdbb->tdbb_temp_traid;
		else if (tdbb->getTransaction())
			inst_id = tdbb->getTransaction()->tra_number;
		else // called without transaction, maybe from OPT or CMP ?
			return &rel_pages_base;
	}
	else
		inst_id = PAG_attachment_id(tdbb);

	if (!rel_pages_inst)
		rel_pages_inst = FB_NEW(*rel_pool) RelationPagesInstances(*rel_pool);

	FB_SIZE_T pos;
	if (!rel_pages_inst->find(inst_id, pos))
	{
		if (!allocPages)
			return 0;

		RelationPages* newPages = rel_pages_free;
		if (!newPages)
		{
			const size_t BULK_ALLOC = 8;

			RelationPages* allocatedPages = newPages =
				FB_NEW(*rel_pool) RelationPages[BULK_ALLOC];

			rel_pages_free = ++allocatedPages;
			for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocatedPages++)
				allocatedPages->rel_next_free = allocatedPages + 1;
		}
		else
		{
			rel_pages_free = newPages->rel_next_free;
			newPages->rel_next_free = 0;
		}

		fb_assert(newPages->useCount == 0);

		newPages->addRef();
		newPages->rel_instance_id = inst_id;
		newPages->rel_pg_space_id = dbb->dbb_page_manager.getTempPageSpaceID(tdbb);
		rel_pages_inst->add(newPages);

		// create primary pointer page and index root page
		DPM_create_relation_pages(tdbb, this, newPages);

#ifdef VIO_DEBUG
		VIO_trace(DEBUG_WRITES,
			"jrd_rel::getPages inst %"ULONGFORMAT", ppp %"SLONGFORMAT", irp %"SLONGFORMAT", addr 0x%x\n",
			newPages->rel_instance_id,
			newPages->rel_pages ? (*newPages->rel_pages)[0] : 0,
			newPages->rel_index_root,
			newPages);
#endif

		// create indexes
		MemoryPool* pool = tdbb->getDefaultPool();
		const bool poolCreated = !pool;

		if (poolCreated)
			pool = dbb->createPool();
		Jrd::ContextPoolHolder context(tdbb, pool);

		jrd_tra* idxTran = tdbb->getTransaction();
		if (!idxTran)
			idxTran = attachment->getSysTransaction();

		IndexDescAlloc* indices = NULL;
		// read indices from "base" index root page
		const USHORT idx_count = BTR_all(tdbb, this, &indices, &rel_pages_base);

		const index_desc* const end = indices->items + idx_count;
		for (index_desc* idx = indices->items; idx < end; idx++)
		{
			Firebird::MetaName idx_name;
			MET_lookup_index(tdbb, idx_name, this->rel_name, idx->idx_id + 1);

			idx->idx_root = 0;
			SelectivityList selectivity(*pool);
			IDX_create_index(tdbb, this, idx, idx_name.c_str(), NULL, idxTran, selectivity);

#ifdef VIO_DEBUG
			VIO_trace(DEBUG_WRITES,
				"jrd_rel::getPages inst %"ULONGFORMAT", irp %"SLONGFORMAT", idx %u, idx_root %"SLONGFORMAT", addr 0x%x\n",
				newPages->rel_instance_id,
				newPages->rel_index_root,
				idx->idx_id,
				idx->idx_root,
				newPages);
#endif
		}

		if (poolCreated)
			dbb->deletePool(pool);
		delete indices;

		return newPages;
	}

	RelationPages* pages = (*rel_pages_inst)[pos];
	fb_assert(pages->rel_instance_id == inst_id);
	return pages;
}