> Um, that's not too surprising, because they're exactly the same patch?

Wrong diff. Here is correct one. 

Everything else is right. I just re-checked :)

step2a:

number of transactions actually processed: 16325
latency average: 49.008 ms
latency stddev: 8.780 ms
tps = 163.182594 (including connections establishing)
tps = 163.189818 (excluding connections establishing)

step2b-fixed:

number of transactions actually processed: 16374
latency average: 48.867 ms
latency stddev: 8.223 ms
tps = 163.658269 (including connections establishing)
tps = 163.666318 (excluding connections establishing)

diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c
index dabaf5a..39f3115 100644
--- a/src/backend/access/hash/hashfunc.c
+++ b/src/backend/access/hash/hashfunc.c
@@ -297,6 +297,9 @@ hashvarlena(PG_FUNCTION_ARGS)
  * of 2.  There is no need to do mod a prime (mod is sooo slow!).
  * If you need less than 32 bits, use a bitmask.
  *
+ * This procedure never fails. Its important. Some code notably ResourceOwner
+ * relies on this.
+ *
  * Note: we could easily change this function to return a 64-bit hash value
  * by using the final values of both b and c.  b is perhaps a little less
  * well mixed than c, however.
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index 69217b5..02319ef 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -37,17 +37,35 @@
  * which should be called before corresponding ResourceOwnerRemember* calls
  * (see below). Internally each type of resource is stored in separate
  * ResourceArray.
+ *
+ * There are two major reasons for using ResourceArray instead of, say,
+ * regular C arrays.
+ *
+ * Firstly we would like to prevent code duplication. For instance
+ * ResourceArray provides generic Remember/Forget/Enlarge procedures, so
+ * corresponding ResourceOwner* procedures are just a typesafe wrappers for
+ * these procedures.
+ *
+ * Secondly ResourceArray must be more efficient than regular C array.
+ * Current implementation in general could be considered a hash table. It has
+ * O(1) complexity of both Remember and Forget procedures.
  */
 typedef struct ResourceArray
 {
 	Datum	   *itemsarr;		/* buffer for storing values */
+	Datum		invalidval;		/* value that is considered invalid */
 	uint32		capacity;		/* capacity of array */
 	uint32		nitems;			/* how many items is stored in items array */
+	uint32		maxitems;		/* precalculated RESARRAY_MAX_ITEMS(capacity) */
+	uint32		lastidx;		/* index of last item returned by GetAny */
 }	ResourceArray;
 
 /*
  * This number is used as initial size of resource array. If given number of
  * items is not enough, we double array size and reallocate memory.
+ *
+ * Should be power of two since we use (arrsize - 1) as mask for hash value.
+ *
  */
 #define RESARRAY_INIT_SIZE 16
 
@@ -64,14 +82,27 @@ typedef struct ResourceArray
 #define DatumGetBuffer(datum)((Buffer)(datum))
 
 /*
+ * How many items could be stored in a resource array of given capacity. If
+ * this number is reached we need to resize an array to prevent hash collisions.
+ *
+ * This computation actually costs only two additions and one binary shift.
+ */
+#define RESARRAY_MAX_ITEMS(capacity) ((capacity)*3/4)
+
+/*
  * Initialize ResourceArray
  */
 static void
-ResourceArrayInit(ResourceArray * resarr)
+ResourceArrayInit(ResourceArray * resarr, Datum invalidval)
 {
 	Assert(resarr->itemsarr == NULL);
 	Assert(resarr->capacity == 0);
 	Assert(resarr->nitems == 0);
+	Assert(resarr->maxitems == 0);
+	Assert(resarr->invalidval == 0);
+	Assert(resarr->lastidx == 0);
+
+	resarr->invalidval = invalidval;
 }
 
 /*
@@ -82,11 +113,32 @@ ResourceArrayInit(ResourceArray * resarr)
 static void
 ResourceArrayAdd(ResourceArray * resarr, Datum data)
 {
+	Datum		idx;
+	Datum		mask = resarr->capacity - 1;
+
+	Assert(resarr->maxitems > resarr->nitems);
 	Assert(resarr->capacity > 0);
 	Assert(resarr->itemsarr != NULL);
-	Assert(resarr->nitems < resarr->capacity);
+	Assert(data != resarr->invalidval);
+
+	/* For small arrays don't calculate hashes */
+	if (resarr->capacity == RESARRAY_INIT_SIZE)
+	{
+		resarr->itemsarr[resarr->nitems] = data;
+		resarr->nitems++;
+		return;
+	}
+
+	idx = hash_any((void *) &data, sizeof(data)) & mask;
+
+	while (true)
+	{
+		if (resarr->itemsarr[idx] == resarr->invalidval)
+			break;
+		idx = (idx + 1) & mask;
+	}
 
-	resarr->itemsarr[resarr->nitems] = data;
+	resarr->itemsarr[idx] = data;
 	resarr->nitems++;
 }
 
@@ -98,24 +150,45 @@ ResourceArrayAdd(ResourceArray * resarr, Datum data)
 static bool
 ResourceArrayRemove(ResourceArray * resarr, Datum data)
 {
-	int			i,
+	uint32		i,
 				j,
 				lastidx;
+	Datum		idx;
+	Datum		mask = resarr->capacity - 1;
 
 	Assert(resarr->capacity > 0);
 	Assert(resarr->itemsarr != NULL);
+	Assert(data != resarr->invalidval);
+
+	/* For small arrays don't calculate hashes */
+	if (resarr->capacity == RESARRAY_INIT_SIZE)
+	{
+		lastidx = resarr->nitems - 1;
+
+		for (i = lastidx; i >= 0; i--)
+		{
+			if (resarr->itemsarr[i] == data)
+			{
+				for (j = i; j < lastidx; j++)
+					resarr->itemsarr[j] = resarr->itemsarr[j + 1];
+				resarr->nitems--;
+				return true;
+			}
+		}
 
-	lastidx = ((int) resarr->nitems) - 1;
+		return false;
+	}
 
-	for (i = lastidx; i >= 0; i--)
+	idx = hash_any((void *) &data, sizeof(data)) & mask;
+	for (i = 0; i < resarr->capacity; i++)
 	{
-		if (resarr->itemsarr[i] == data)
+		if (resarr->itemsarr[idx] == data)
 		{
-			for (j = i; j < lastidx; j++)
-				resarr->itemsarr[j] = resarr->itemsarr[j + 1];
+			resarr->itemsarr[idx] = resarr->invalidval;
 			resarr->nitems--;
 			return true;
 		}
+		idx = (idx + 1) & mask;
 	}
 
 	return false;
@@ -131,27 +204,33 @@ static void
 ResourceArrayEnlarge(ResourceArray * resarr)
 {
 	uint32		i,
-				oldcap,
-				oldnitems;
+				oldcap;
 	Datum	   *olditemsarr;
 
-	if (resarr->nitems < resarr->capacity)
+	if (resarr->nitems < resarr->maxitems)
 		return;					/* nothing to do */
 
 	olditemsarr = resarr->itemsarr;
 	oldcap = resarr->capacity;
-	oldnitems = resarr->nitems;
 
 	resarr->capacity = oldcap > 0 ? oldcap * 2 : RESARRAY_INIT_SIZE;
 	resarr->itemsarr = (Datum *)
 		MemoryContextAlloc(TopMemoryContext,
 						   resarr->capacity * sizeof(Datum));
+	resarr->maxitems = RESARRAY_MAX_ITEMS(resarr->capacity);
 	resarr->nitems = 0;
 
+	for (i = 0; i < resarr->capacity; i++)
+		resarr->itemsarr[i] = resarr->invalidval;
+
 	if (olditemsarr != NULL)
 	{
-		for (i = 0; i < oldnitems; i++)
-			ResourceArrayAdd(resarr, olditemsarr[i]);
+		while (oldcap > 0)
+		{
+			oldcap--;
+			if (olditemsarr[oldcap] != resarr->invalidval)
+				ResourceArrayAdd(resarr, olditemsarr[oldcap]);
+		}
 		pfree(olditemsarr);
 	}
 }
@@ -164,12 +243,24 @@ ResourceArrayEnlarge(ResourceArray * resarr)
 static bool
 ResourceArrayGetAny(ResourceArray * resarr, Datum *out)
 {
+	uint32		mask;
+
 	if (resarr->nitems == 0)
 		return false;
 
 	Assert(resarr->capacity > 0);
+	mask = resarr->capacity - 1;
+
+	for (;;)
+	{
+		resarr->lastidx = resarr->lastidx & mask;
+		if (resarr->itemsarr[resarr->lastidx] != resarr->invalidval)
+			break;
+
+		resarr->lastidx++;
+	}
 
-	*out = resarr->itemsarr[resarr->nitems - 1];
+	*out = resarr->itemsarr[resarr->lastidx];
 	return true;
 }
 
@@ -182,6 +273,7 @@ ResourceArrayFree(ResourceArray * resarr)
 	Assert(resarr->nitems == 0);
 
 	resarr->capacity = 0;
+	resarr->maxitems = 0;
 
 	if (!resarr->itemsarr)
 		return;
@@ -299,15 +391,15 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name)
 		parent->firstchild = owner;
 	}
 
-	ResourceArrayInit(&(owner->catrefarr));
-	ResourceArrayInit(&(owner->catlistrefarr));
-	ResourceArrayInit(&(owner->relrefarr));
-	ResourceArrayInit(&(owner->planrefarr));
-	ResourceArrayInit(&(owner->tupdescarr));
-	ResourceArrayInit(&(owner->snapshotarr));
-	ResourceArrayInit(&(owner->dsmarr));
-	ResourceArrayInit(&(owner->bufferarr));
-	ResourceArrayInit(&(owner->filearr));
+	ResourceArrayInit(&(owner->catrefarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->catlistrefarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->relrefarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->planrefarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->tupdescarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->bufferarr), BufferGetDatum(InvalidBuffer));
+	ResourceArrayInit(&(owner->filearr), FileGetDatum(-1));
 
 	return owner;
 }
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to