mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
The original coding was quite fast so long as objects were always released in reverse order of addition; otherwise, it degenerated into O(N^2) behavior due to searching for the array element to delete. Improve matters by switching to hashed storage when the number of objects of a given type exceeds 64. (The cutover point is open to discussion, of course, but some simple performance testing suggests that hashing has enough overhead to be a loser below there.) Also, refactor resowner.c so that we don't need N copies of the array management code. Since all the resource IDs the code currently needs to deal with are either pointers or integers, it seems sufficient to create a one-size-fits-all infrastructure in which everything is converted to a Datum for storage. Aleksander Alekseev, reviewed by Stas Kelvich, further fixes by me
src/backend/utils/resowner/README Notes About Resource Owners =========================== ResourceOwner objects are a concept invented to simplify management of query-related resources, such as buffer pins and table locks. These resources need to be tracked in a reliable way to ensure that they will be released at query end, even if the query fails due to an error. Rather than expecting the entire executor to have bulletproof data structures, we localize the tracking of such resources into a single module. The design of the ResourceOwner API is modeled on our MemoryContext API, which has proven very flexible and successful in preventing memory leaks. In particular we allow ResourceOwners to have child ResourceOwner objects so that there can be forests of the things; releasing a parent ResourceOwner acts on all its direct and indirect children as well. (It is tempting to consider unifying ResourceOwners and MemoryContexts into a single object type, but their usage patterns are sufficiently different that this is probably not really a helpful thing to do.) We create a ResourceOwner for each transaction or subtransaction as well as one for each Portal. During execution of a Portal, the global variable CurrentResourceOwner points to the Portal's ResourceOwner. This causes operations such as ReadBuffer and LockAcquire to record ownership of the acquired resources in that ResourceOwner object. When a Portal is closed, any remaining resources (typically only locks) become the responsibility of the current transaction. This is represented by making the Portal's ResourceOwner a child of the current transaction's ResourceOwner. resowner.c automatically transfers the resources to the parent object when releasing the child. Similarly, subtransaction ResourceOwners are children of their immediate parent. We need transaction-related ResourceOwners as well as Portal-related ones because transactions may initiate operations that require resources (such as query parsing) when no associated Portal exists yet. API Overview ------------ The basic operations on a ResourceOwner are: * create a ResourceOwner * associate or deassociate some resource with a ResourceOwner * release a ResourceOwner's assets (free all owned resources, but not the owner object itself) * delete a ResourceOwner (including child owner objects); all resources must have been released beforehand Locks are handled specially because in non-error situations a lock should be held until end of transaction, even if it was originally taken by a subtransaction or portal. Therefore, the "release" operation on a child ResourceOwner transfers lock ownership to the parent instead of actually releasing the lock, if isCommit is true. Currently, ResourceOwners contain direct support for recording ownership of buffer pins, lmgr locks, and catcache, relcache, plancache, tupdesc, and snapshot references. Other objects can be associated with a ResourceOwner by recording the address of the owning ResourceOwner in such an object. There is an API for other modules to get control during ResourceOwner release, so that they can scan their own data structures to find the objects that need to be deleted. Whenever we are inside a transaction, the global variable CurrentResourceOwner shows which resource owner should be assigned ownership of acquired resources. Note however that CurrentResourceOwner is NULL when not inside any transaction (or when inside a failed transaction). In this case it is not valid to acquire query-lifespan resources. When unpinning a buffer or releasing a lock or cache reference, CurrentResourceOwner must point to the same resource owner that was current when the buffer, lock, or cache reference was acquired. It would be possible to relax this restriction given additional bookkeeping effort, but at present there seems no need. Code that transiently changes CurrentResourceOwner should generally use a PG_TRY construct to ensure that the previous value of CurrentResourceOwner is restored if control is lost during an error exit.