Skip to content

Commit eed959a

Browse files
committed
Fix lock assertions in dshash.c.
dshash.c previously maintained flags to be able to assert that you didn't hold any partition lock. These flags could get out of sync with reality in error scenarios. Get rid of all that, and make assertions about the locks themselves instead. Since LWLockHeldByMe() loops internally, we don't want to put that inside another loop over all partition locks. Introduce a new debugging-only interface LWLockAnyHeldByMe() to avoid that. This problem was noted by Tom and Andres while reviewing changes to support the new shared memory stats system, and later showed up in reality while working on commit 389869a. Back-patch to 11, where dshash.c arrived. Reported-by: Tom Lane <tgl@sss.pgh.pa.us> Reported-by: Andres Freund <andres@anarazel.de> Reviewed-by: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> Reviewed-by: Zhihong Yu <zyu@yugabyte.com> Reviewed-by: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/20220311012712.botrpsikaufzteyt@alap3.anarazel.de Discussion: https://postgr.es/m/CA%2BhUKGJ31Wce6HJ7xnVTKWjFUWQZPBngxfJVx4q0E98pDr3kAw%40mail.gmail.com
1 parent 3838fa2 commit eed959a

File tree

3 files changed

+37
-34
lines changed

3 files changed

+37
-34
lines changed

src/backend/lib/dshash.c

+10-34
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,6 @@ struct dshash_table
110110
dshash_table_control *control; /* Control object in DSM. */
111111
dsa_pointer *buckets; /* Current bucket pointers in DSM. */
112112
size_t size_log2; /* log2(number of buckets) */
113-
bool find_locked; /* Is any partition lock held by 'find'? */
114-
bool find_exclusively_locked; /* ... exclusively? */
115113
};
116114

117115
/* Given a pointer to an item, find the entry (user data) it holds. */
@@ -194,6 +192,10 @@ static inline bool equal_keys(dshash_table *hash_table,
194192
#define PARTITION_LOCK(hash_table, i) \
195193
(&(hash_table)->control->partitions[(i)].lock)
196194

195+
#define ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table) \
196+
Assert(!LWLockAnyHeldByMe(&(hash_table)->control->partitions[0].lock, \
197+
DSHASH_NUM_PARTITIONS, sizeof(dshash_partition)))
198+
197199
/*
198200
* Create a new hash table backed by the given dynamic shared area, with the
199201
* given parameters. The returned object is allocated in backend-local memory
@@ -234,9 +236,6 @@ dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
234236
}
235237
}
236238

237-
hash_table->find_locked = false;
238-
hash_table->find_exclusively_locked = false;
239-
240239
/*
241240
* Set up the initial array of buckets. Our initial size is the same as
242241
* the number of partitions.
@@ -285,8 +284,6 @@ dshash_attach(dsa_area *area, const dshash_parameters *params,
285284
hash_table->params = *params;
286285
hash_table->arg = arg;
287286
hash_table->control = dsa_get_address(area, control);
288-
hash_table->find_locked = false;
289-
hash_table->find_exclusively_locked = false;
290287
Assert(hash_table->control->magic == DSHASH_MAGIC);
291288

292289
/*
@@ -309,7 +306,7 @@ dshash_attach(dsa_area *area, const dshash_parameters *params,
309306
void
310307
dshash_detach(dshash_table *hash_table)
311308
{
312-
Assert(!hash_table->find_locked);
309+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
313310

314311
/* The hash table may have been destroyed. Just free local memory. */
315312
pfree(hash_table);
@@ -400,7 +397,7 @@ dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
400397
partition = PARTITION_FOR_HASH(hash);
401398

402399
Assert(hash_table->control->magic == DSHASH_MAGIC);
403-
Assert(!hash_table->find_locked);
400+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
404401

405402
LWLockAcquire(PARTITION_LOCK(hash_table, partition),
406403
exclusive ? LW_EXCLUSIVE : LW_SHARED);
@@ -418,8 +415,6 @@ dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
418415
else
419416
{
420417
/* The caller will free the lock by calling dshash_release_lock. */
421-
hash_table->find_locked = true;
422-
hash_table->find_exclusively_locked = exclusive;
423418
return ENTRY_FROM_ITEM(item);
424419
}
425420
}
@@ -449,7 +444,7 @@ dshash_find_or_insert(dshash_table *hash_table,
449444
partition = &hash_table->control->partitions[partition_index];
450445

451446
Assert(hash_table->control->magic == DSHASH_MAGIC);
452-
Assert(!hash_table->find_locked);
447+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
453448

454449
restart:
455450
LWLockAcquire(PARTITION_LOCK(hash_table, partition_index),
@@ -494,8 +489,6 @@ dshash_find_or_insert(dshash_table *hash_table,
494489
}
495490

496491
/* The caller must release the lock with dshash_release_lock. */
497-
hash_table->find_locked = true;
498-
hash_table->find_exclusively_locked = true;
499492
return ENTRY_FROM_ITEM(item);
500493
}
501494

@@ -514,7 +507,7 @@ dshash_delete_key(dshash_table *hash_table, const void *key)
514507
bool found;
515508

516509
Assert(hash_table->control->magic == DSHASH_MAGIC);
517-
Assert(!hash_table->find_locked);
510+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
518511

519512
hash = hash_key(hash_table, key);
520513
partition = PARTITION_FOR_HASH(hash);
@@ -551,14 +544,10 @@ dshash_delete_entry(dshash_table *hash_table, void *entry)
551544
size_t partition = PARTITION_FOR_HASH(item->hash);
552545

553546
Assert(hash_table->control->magic == DSHASH_MAGIC);
554-
Assert(hash_table->find_locked);
555-
Assert(hash_table->find_exclusively_locked);
556547
Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition),
557548
LW_EXCLUSIVE));
558549

559550
delete_item(hash_table, item);
560-
hash_table->find_locked = false;
561-
hash_table->find_exclusively_locked = false;
562551
LWLockRelease(PARTITION_LOCK(hash_table, partition));
563552
}
564553

@@ -572,13 +561,7 @@ dshash_release_lock(dshash_table *hash_table, void *entry)
572561
size_t partition_index = PARTITION_FOR_HASH(item->hash);
573562

574563
Assert(hash_table->control->magic == DSHASH_MAGIC);
575-
Assert(hash_table->find_locked);
576-
Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition_index),
577-
hash_table->find_exclusively_locked
578-
? LW_EXCLUSIVE : LW_SHARED));
579564

580-
hash_table->find_locked = false;
581-
hash_table->find_exclusively_locked = false;
582565
LWLockRelease(PARTITION_LOCK(hash_table, partition_index));
583566
}
584567

@@ -644,7 +627,7 @@ dshash_seq_next(dshash_seq_status *status)
644627
if (status->curpartition == -1)
645628
{
646629
Assert(status->curbucket == 0);
647-
Assert(!status->hash_table->find_locked);
630+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(status->hash_table);
648631

649632
status->curpartition = 0;
650633

@@ -702,8 +685,6 @@ dshash_seq_next(dshash_seq_status *status)
702685

703686
status->curitem =
704687
dsa_get_address(status->hash_table->area, next_item_pointer);
705-
status->hash_table->find_locked = true;
706-
status->hash_table->find_exclusively_locked = status->exclusive;
707688

708689
/*
709690
* The caller may delete the item. Store the next item in case of
@@ -722,9 +703,6 @@ dshash_seq_next(dshash_seq_status *status)
722703
void
723704
dshash_seq_term(dshash_seq_status *status)
724705
{
725-
status->hash_table->find_locked = false;
726-
status->hash_table->find_exclusively_locked = false;
727-
728706
if (status->curpartition >= 0)
729707
LWLockRelease(PARTITION_LOCK(status->hash_table, status->curpartition));
730708
}
@@ -743,8 +721,6 @@ dshash_delete_current(dshash_seq_status *status)
743721

744722
Assert(status->exclusive);
745723
Assert(hash_table->control->magic == DSHASH_MAGIC);
746-
Assert(hash_table->find_locked);
747-
Assert(hash_table->find_exclusively_locked);
748724
Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition),
749725
LW_EXCLUSIVE));
750726

@@ -762,7 +738,7 @@ dshash_dump(dshash_table *hash_table)
762738
size_t j;
763739

764740
Assert(hash_table->control->magic == DSHASH_MAGIC);
765-
Assert(!hash_table->find_locked);
741+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
766742

767743
for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
768744
{

src/backend/storage/lmgr/lwlock.c

+26
Original file line numberDiff line numberDiff line change
@@ -1925,6 +1925,32 @@ LWLockHeldByMe(LWLock *l)
19251925
return false;
19261926
}
19271927

1928+
/*
1929+
* LWLockHeldByMe - test whether my process holds any of an array of locks
1930+
*
1931+
* This is meant as debug support only.
1932+
*/
1933+
bool
1934+
LWLockAnyHeldByMe(LWLock *l, int nlocks, size_t stride)
1935+
{
1936+
char *held_lock_addr;
1937+
char *begin;
1938+
char *end;
1939+
int i;
1940+
1941+
begin = (char *) l;
1942+
end = begin + nlocks * stride;
1943+
for (i = 0; i < num_held_lwlocks; i++)
1944+
{
1945+
held_lock_addr = (char *) held_lwlocks[i].lock;
1946+
if (held_lock_addr >= begin &&
1947+
held_lock_addr < end &&
1948+
(held_lock_addr - begin) % stride == 0)
1949+
return true;
1950+
}
1951+
return false;
1952+
}
1953+
19281954
/*
19291955
* LWLockHeldByMeInMode - test whether my process holds a lock in given mode
19301956
*

src/include/storage/lwlock.h

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ extern void LWLockRelease(LWLock *lock);
120120
extern void LWLockReleaseClearVar(LWLock *lock, uint64 *valptr, uint64 val);
121121
extern void LWLockReleaseAll(void);
122122
extern bool LWLockHeldByMe(LWLock *lock);
123+
extern bool LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride);
123124
extern bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode);
124125

125126
extern bool LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval);

0 commit comments

Comments
 (0)