@@ -54,7 +54,7 @@ BgwPoolMainLoop(BgwPool* pool)
54
54
{
55
55
int size ;
56
56
void * work ;
57
- size_t payload = sizeof (MtmReceiverContext ) + sizeof ( size_t );
57
+ int payload = INTALIGN ( sizeof (MtmReceiverContext ));
58
58
MtmReceiverContext ctx ;
59
59
static PortalData fakePortal ;
60
60
@@ -102,7 +102,6 @@ BgwPoolMainLoop(BgwPool* pool)
102
102
break ;
103
103
}
104
104
size = * (int * ) & pool -> queue [pool -> head ];
105
- ctx = * (MtmReceiverContext * ) & pool -> queue [pool -> head + sizeof (size_t )];
106
105
107
106
Assert (size < pool -> size );
108
107
work = palloc (size );
@@ -111,20 +110,33 @@ BgwPoolMainLoop(BgwPool* pool)
111
110
if (pool -> lastPeakTime == 0 && pool -> active == pool -> nWorkers && pool -> pending != 0 )
112
111
pool -> lastPeakTime = MtmGetSystemTime ();
113
112
114
- if (pool -> head + size + payload > pool -> size )
113
+ if (pool -> head + size + payload + sizeof ( int ) > pool -> size )
115
114
{
116
- memcpy (work , pool -> queue , size );
117
- pool -> head = INTALIGN (size );
115
+ ctx = * (MtmReceiverContext * ) & pool -> queue ;
116
+ memcpy (work , & pool -> queue [payload ], size );
117
+ pool -> head = payload + INTALIGN (size );
118
118
}
119
119
else
120
120
{
121
- memcpy (work , & pool -> queue [pool -> head + payload ], size );
122
- pool -> head += payload + INTALIGN (size );
121
+ memcpy (& ctx , & pool -> queue [pool -> head + sizeof (int )], payload );
122
+ memcpy (work , & pool -> queue [pool -> head + sizeof (int ) + payload ], size );
123
+ pool -> head += sizeof (int ) + payload + INTALIGN (size );
123
124
}
124
125
125
- if (pool -> size == pool -> head )
126
+ /* wrap head */
127
+ if (pool -> head == pool -> size )
126
128
pool -> head = 0 ;
127
129
130
+ /*
131
+ * We should reset head and tail in order to accept messages bigger
132
+ * than half of buffer size.
133
+ */
134
+ if (pool -> head == pool -> tail )
135
+ {
136
+ pool -> head = 0 ;
137
+ pool -> tail = 0 ;
138
+ }
139
+
128
140
if (pool -> producerBlocked )
129
141
{
130
142
pool -> producerBlocked = false;
@@ -160,7 +172,7 @@ BgwPoolInit(BgwPool* pool, BgwPoolExecutor executor, size_t queueSize, size_t nW
160
172
MtmPool = pool ;
161
173
162
174
pool -> bgwhandles = (BackgroundWorkerHandle * * ) ShmemAlloc (MtmMaxWorkers * sizeof (BackgroundWorkerHandle * ));
163
- pool -> queue = (char * )ShmemAlloc (queueSize );
175
+ pool -> queue = (char * )ShmemAlloc (INTALIGN ( queueSize ) );
164
176
if (pool -> queue == NULL ) {
165
177
elog (PANIC , "Failed to allocate memory for background workers pool: %zd bytes requested" , queueSize );
166
178
}
@@ -252,11 +264,12 @@ static void BgwStartExtraWorker(BgwPool* pool)
252
264
}
253
265
254
266
void
255
- BgwPoolExecute (BgwPool * pool , void * work , size_t size , MtmReceiverContext * ctx )
267
+ BgwPoolExecute (BgwPool * pool , void * work , int size , MtmReceiverContext * ctx )
256
268
{
257
- size_t payload = sizeof (MtmReceiverContext ) + sizeof ( size_t );
269
+ int payload = INTALIGN ( sizeof (MtmReceiverContext ));
258
270
259
- if (size + payload > pool -> size )
271
+ // XXX: align with spill size and assert that
272
+ if (size + sizeof (int ) + payload > pool -> size )
260
273
{
261
274
/*
262
275
* Size of work is larger than size of shared buffer:
@@ -269,18 +282,19 @@ BgwPoolExecute(BgwPool* pool, void* work, size_t size, MtmReceiverContext *ctx)
269
282
SpinLockAcquire (& pool -> lock );
270
283
while (!pool -> shutdown )
271
284
{
272
- if ((pool -> head <= pool -> tail && pool -> size - pool -> tail < size + payload && pool -> head < size )
273
- || (pool -> head > pool -> tail && pool -> head - pool -> tail < size + payload ))
274
- {
275
- if (pool -> lastPeakTime == 0 )
276
- pool -> lastPeakTime = MtmGetSystemTime ();
277
-
278
- pool -> producerBlocked = true;
279
- SpinLockRelease (& pool -> lock );
280
- PGSemaphoreLock (pool -> overflow );
281
- SpinLockAcquire (& pool -> lock );
282
- }
283
- else
285
+ /*
286
+ * If queue is not wrapped through the end of buffer (head <= tail) we can
287
+ * fit message either to the end (between tail and pool->size) or to the
288
+ * beginning (between queue beginning and head). In both cases we can fit
289
+ * size word after the tail.
290
+ * If queue is wrapped through the end of buffer (tail < head) we can fit
291
+ * message only between head and tail.
292
+ */
293
+ if ((pool -> head <= pool -> tail &&
294
+ (pool -> size - pool -> tail >= size + payload + sizeof (int ) ||
295
+ pool -> head >= size + payload ))
296
+ || (pool -> head > pool -> tail &&
297
+ pool -> head - pool -> tail >= size + payload + sizeof (int )))
284
298
{
285
299
pool -> pending += 1 ;
286
300
@@ -290,18 +304,24 @@ BgwPoolExecute(BgwPool* pool, void* work, size_t size, MtmReceiverContext *ctx)
290
304
if (pool -> lastPeakTime == 0 && pool -> active == pool -> nWorkers && pool -> pending != 0 )
291
305
pool -> lastPeakTime = MtmGetSystemTime ();
292
306
293
- * (int * )& pool -> queue [pool -> tail ] = size ;
294
- * (MtmReceiverContext * )& pool -> queue [pool -> tail + sizeof (size_t )] = * ctx ;
307
+ /*
308
+ * We always have free space for size at tail, as everything is
309
+ * int-aligded and when pool->tail becomes equal to pool->size it
310
+ * is switched to zero.
311
+ */
312
+ * (int * ) & pool -> queue [pool -> tail ] = size ;
295
313
296
- if (pool -> size - pool -> tail >= size + payload )
314
+ if (pool -> size - pool -> tail >= payload + size + sizeof ( int ) )
297
315
{
298
- memcpy (& pool -> queue [pool -> tail + payload ], work , size );
299
- pool -> tail += payload + INTALIGN (size );
316
+ memcpy (& pool -> queue [pool -> tail + sizeof (int )], ctx , payload );
317
+ memcpy (& pool -> queue [pool -> tail + sizeof (int ) + payload ], work , size );
318
+ pool -> tail += sizeof (int ) + payload + INTALIGN (size );
300
319
}
301
320
else
302
321
{
303
- memcpy (pool -> queue , work , size );
304
- pool -> tail = INTALIGN (size );
322
+ memcpy (pool -> queue , ctx , payload );
323
+ memcpy (& pool -> queue [payload ], work , size );
324
+ pool -> tail = payload + INTALIGN (size );
305
325
}
306
326
307
327
if (pool -> tail == pool -> size )
@@ -310,6 +330,16 @@ BgwPoolExecute(BgwPool* pool, void* work, size_t size, MtmReceiverContext *ctx)
310
330
PGSemaphoreUnlock (pool -> available );
311
331
break ;
312
332
}
333
+ else
334
+ {
335
+ if (pool -> lastPeakTime == 0 )
336
+ pool -> lastPeakTime = MtmGetSystemTime ();
337
+
338
+ pool -> producerBlocked = true;
339
+ SpinLockRelease (& pool -> lock );
340
+ PGSemaphoreLock (pool -> overflow );
341
+ SpinLockAcquire (& pool -> lock );
342
+ }
313
343
}
314
344
SpinLockRelease (& pool -> lock );
315
345
}
0 commit comments