Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7cdd0c2

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 e5b5b44 commit 7cdd0c2

File tree

3 files changed

+36
-26
lines changed

3 files changed

+36
-26
lines changed

src/backend/lib/dshash.c

Lines changed: 9 additions & 26 deletions
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. */
@@ -186,6 +184,10 @@ static inline bool equal_keys(dshash_table *hash_table,
186184
#define PARTITION_LOCK(hash_table, i) \
187185
(&(hash_table)->control->partitions[(i)].lock)
188186

187+
#define ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table) \
188+
Assert(!LWLockAnyHeldByMe(&(hash_table)->control->partitions[0].lock, \
189+
DSHASH_NUM_PARTITIONS, sizeof(dshash_partition)))
190+
189191
/*
190192
* Create a new hash table backed by the given dynamic shared area, with the
191193
* given parameters. The returned object is allocated in backend-local memory
@@ -226,9 +228,6 @@ dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
226228
}
227229
}
228230

229-
hash_table->find_locked = false;
230-
hash_table->find_exclusively_locked = false;
231-
232231
/*
233232
* Set up the initial array of buckets. Our initial size is the same as
234233
* the number of partitions.
@@ -277,8 +276,6 @@ dshash_attach(dsa_area *area, const dshash_parameters *params,
277276
hash_table->params = *params;
278277
hash_table->arg = arg;
279278
hash_table->control = dsa_get_address(area, control);
280-
hash_table->find_locked = false;
281-
hash_table->find_exclusively_locked = false;
282279
Assert(hash_table->control->magic == DSHASH_MAGIC);
283280

284281
/*
@@ -301,7 +298,7 @@ dshash_attach(dsa_area *area, const dshash_parameters *params,
301298
void
302299
dshash_detach(dshash_table *hash_table)
303300
{
304-
Assert(!hash_table->find_locked);
301+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
305302

306303
/* The hash table may have been destroyed. Just free local memory. */
307304
pfree(hash_table);
@@ -392,7 +389,7 @@ dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
392389
partition = PARTITION_FOR_HASH(hash);
393390

394391
Assert(hash_table->control->magic == DSHASH_MAGIC);
395-
Assert(!hash_table->find_locked);
392+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
396393

397394
LWLockAcquire(PARTITION_LOCK(hash_table, partition),
398395
exclusive ? LW_EXCLUSIVE : LW_SHARED);
@@ -410,8 +407,6 @@ dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
410407
else
411408
{
412409
/* The caller will free the lock by calling dshash_release_lock. */
413-
hash_table->find_locked = true;
414-
hash_table->find_exclusively_locked = exclusive;
415410
return ENTRY_FROM_ITEM(item);
416411
}
417412
}
@@ -441,7 +436,7 @@ dshash_find_or_insert(dshash_table *hash_table,
441436
partition = &hash_table->control->partitions[partition_index];
442437

443438
Assert(hash_table->control->magic == DSHASH_MAGIC);
444-
Assert(!hash_table->find_locked);
439+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
445440

446441
restart:
447442
LWLockAcquire(PARTITION_LOCK(hash_table, partition_index),
@@ -486,8 +481,6 @@ dshash_find_or_insert(dshash_table *hash_table,
486481
}
487482

488483
/* The caller must release the lock with dshash_release_lock. */
489-
hash_table->find_locked = true;
490-
hash_table->find_exclusively_locked = true;
491484
return ENTRY_FROM_ITEM(item);
492485
}
493486

@@ -506,7 +499,7 @@ dshash_delete_key(dshash_table *hash_table, const void *key)
506499
bool found;
507500

508501
Assert(hash_table->control->magic == DSHASH_MAGIC);
509-
Assert(!hash_table->find_locked);
502+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
510503

511504
hash = hash_key(hash_table, key);
512505
partition = PARTITION_FOR_HASH(hash);
@@ -543,14 +536,10 @@ dshash_delete_entry(dshash_table *hash_table, void *entry)
543536
size_t partition = PARTITION_FOR_HASH(item->hash);
544537

545538
Assert(hash_table->control->magic == DSHASH_MAGIC);
546-
Assert(hash_table->find_locked);
547-
Assert(hash_table->find_exclusively_locked);
548539
Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition),
549540
LW_EXCLUSIVE));
550541

551542
delete_item(hash_table, item);
552-
hash_table->find_locked = false;
553-
hash_table->find_exclusively_locked = false;
554543
LWLockRelease(PARTITION_LOCK(hash_table, partition));
555544
}
556545

@@ -564,13 +553,7 @@ dshash_release_lock(dshash_table *hash_table, void *entry)
564553
size_t partition_index = PARTITION_FOR_HASH(item->hash);
565554

566555
Assert(hash_table->control->magic == DSHASH_MAGIC);
567-
Assert(hash_table->find_locked);
568-
Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition_index),
569-
hash_table->find_exclusively_locked
570-
? LW_EXCLUSIVE : LW_SHARED));
571556

572-
hash_table->find_locked = false;
573-
hash_table->find_exclusively_locked = false;
574557
LWLockRelease(PARTITION_LOCK(hash_table, partition_index));
575558
}
576559

@@ -603,7 +586,7 @@ dshash_dump(dshash_table *hash_table)
603586
size_t j;
604587

605588
Assert(hash_table->control->magic == DSHASH_MAGIC);
606-
Assert(!hash_table->find_locked);
589+
ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table);
607590

608591
for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
609592
{

src/backend/storage/lmgr/lwlock.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,6 +1941,32 @@ LWLockHeldByMe(LWLock *l)
19411941
return false;
19421942
}
19431943

1944+
/*
1945+
* LWLockHeldByMe - test whether my process holds any of an array of locks
1946+
*
1947+
* This is meant as debug support only.
1948+
*/
1949+
bool
1950+
LWLockAnyHeldByMe(LWLock *l, int nlocks, size_t stride)
1951+
{
1952+
char *held_lock_addr;
1953+
char *begin;
1954+
char *end;
1955+
int i;
1956+
1957+
begin = (char *) l;
1958+
end = begin + nlocks * stride;
1959+
for (i = 0; i < num_held_lwlocks; i++)
1960+
{
1961+
held_lock_addr = (char *) held_lwlocks[i].lock;
1962+
if (held_lock_addr >= begin &&
1963+
held_lock_addr < end &&
1964+
(held_lock_addr - begin) % stride == 0)
1965+
return true;
1966+
}
1967+
return false;
1968+
}
1969+
19441970
/*
19451971
* LWLockHeldByMeInMode - test whether my process holds a lock in given mode
19461972
*

src/include/storage/lwlock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ extern void LWLockRelease(LWLock *lock);
149149
extern void LWLockReleaseClearVar(LWLock *lock, uint64 *valptr, uint64 val);
150150
extern void LWLockReleaseAll(void);
151151
extern bool LWLockHeldByMe(LWLock *lock);
152+
extern bool LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride);
152153
extern bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode);
153154

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

0 commit comments

Comments
 (0)