src/backend/utils/resowner/resowner.c | 76 +++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index 0955bcc..ef6e6bd 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -229,6 +229,7 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceOwner child; ResourceOwner save; ResourceReleaseCallbackItem *item; + int i; /* Recurse to handle descendants */ for (child = owner->firstchild; child != NULL; child = child->nextchild) @@ -256,11 +257,13 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, * We are careful to do the releasing back-to-front, so as to avoid * O(N^2) behavior in ResourceOwnerForgetBuffer(). */ - while (owner->nbuffers > 0) + for (i=0; owner->nbuffers > 0; i = (i + 1) % owner->maxbuffers) { + if (!BufferIsValid(owner->buffers[i])) + continue; if (isCommit) - PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]); - ReleaseBuffer(owner->buffers[owner->nbuffers - 1]); + PrintBufferLeakWarning(owner->buffers[i]); + ReleaseBuffer(owner->buffers[i]); } /* @@ -578,21 +581,38 @@ ResourceOwnerEnlargeBuffers(ResourceOwner owner) int newmax; if (owner == NULL || - owner->nbuffers < owner->maxbuffers) + owner->nbuffers < owner->maxbuffers / 2) return; /* nothing to do */ if (owner->buffers == NULL) { newmax = 16; owner->buffers = (Buffer *) - MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Buffer)); + MemoryContextAllocZero(TopMemoryContext, newmax * sizeof(Buffer)); owner->maxbuffers = newmax; } else { + Buffer *newbuf; + int i, j; + newmax = owner->maxbuffers * 2; - owner->buffers = (Buffer *) - repalloc(owner->buffers, newmax * sizeof(Buffer)); + newbuf = (Buffer *) + MemoryContextAllocZero(TopMemoryContext, newmax * sizeof(Buffer)); + + for (i=0; i < owner->maxbuffers; i++) + { + Buffer buffer = owner->buffers[i]; + + if (!BufferIsValid(buffer)) + continue; + j = hash_uint32((uint32)buffer) % newmax; + while (BufferIsValid(newbuf[j])) + j = (j + 1) % newmax; + newbuf[j] = buffer; + } + pfree(owner->buffers); + owner->buffers = newbuf; owner->maxbuffers = newmax; } } @@ -610,9 +630,21 @@ ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer) { if (owner != NULL) { + int start = hash_uint32((uint32)buffer) % owner->maxbuffers; + int curr = start; + Assert(owner->nbuffers < owner->maxbuffers); - owner->buffers[owner->nbuffers] = buffer; - owner->nbuffers++; + do { + if (!BufferIsValid(owner->buffers[curr])) + { + owner->buffers[curr] = buffer; + owner->nbuffers++; + return; + } + curr = (curr + 1) % owner->maxbuffers; + } while (curr != start); + Assert(false); + elog(ERROR, "Couldn't find a slot to remember buffer"); } } @@ -628,27 +660,19 @@ ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer) if (owner != NULL) { Buffer *buffers = owner->buffers; - int nb1 = owner->nbuffers - 1; - int i; + int start = hash_uint32((uint32)buffer) % owner->maxbuffers; + int curr = start; - /* - * Scan back-to-front because it's more likely we are releasing a - * recently pinned buffer. This isn't always the case of course, but - * it's the way to bet. - */ - for (i = nb1; i >= 0; i--) - { - if (buffers[i] == buffer) + do { + if (buffers[curr] == buffer) { - while (i < nb1) - { - buffers[i] = buffers[i + 1]; - i++; - } - owner->nbuffers = nb1; + buffers[curr] = InvalidBuffer; + owner->nbuffers--; return; } - } + curr = (curr + 1) % owner->maxbuffers; + } while (curr != start); + Assert(false); elog(ERROR, "buffer %d is not owned by resource owner %s", buffer, owner->name); }