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

Commit ddb7987

Browse files
committed
1. Do not release suplementary index locks in COPY
2. Correctly handle multiple LSM3 indexes per class
1 parent e4cc42c commit ddb7987

File tree

1 file changed

+102
-55
lines changed

1 file changed

+102
-55
lines changed

lsm3.c

Lines changed: 102 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ extern void _PG_fini(void);
5050
extern void lsm3_merger_main(Datum arg);
5151

5252
/* Lsm3 dictionary (hashtable with control data for all indexes) */
53-
static Lsm3DictEntry* Lsm3Entry;
5453
static HTAB* Lsm3Dict;
5554
static LWLock* Lsm3DictLock;
5655
static List* Lsm3ReleasedLocks;
56+
static List* Lsm3Entries;
57+
static bool Lsm3InsideCopy;
5758

5859
/* Kind of relation optioms for Lsm3 index */
5960
static relopt_kind Lsm3ReloptKind;
@@ -423,11 +424,20 @@ lsm3_build(Relation heap, Relation index, IndexInfo *indexInfo)
423424
Oid save_am = index->rd_rel->relam;
424425
IndexBuildResult * result;
425426
bool found;
426-
LWLockAcquire(Lsm3DictLock, LW_EXCLUSIVE); /* Obtain exclusive lock on dictionary: it will be released in utility hook */
427-
Lsm3Entry = hash_search(Lsm3Dict, &RelationGetRelid(index), HASH_ENTER, &found); /* Setting Lsm3Entry indicates to utility hook that Lsm3 index was created */
427+
Lsm3DictEntry* entry;
428+
if (Lsm3Entries == NULL) { // multiple indexes can be rebuilt by truncate
429+
LWLockAcquire(Lsm3DictLock, LW_EXCLUSIVE); /* Obtain exclusive lock on dictionary: it will be released in utility hook */
430+
}
431+
elog(LOG, "lsm3_build %s", index->rd_rel->relname.data);
432+
entry = hash_search(Lsm3Dict, &RelationGetRelid(index), HASH_ENTER, &found); /* Setting Lsm3Entry indicates to utility hook that Lsm3 index was created */
428433
if (!found)
429434
{
430-
lsm3_init_entry(Lsm3Entry, index);
435+
lsm3_init_entry(entry, index);
436+
}
437+
{
438+
MemoryContext old_context = MemoryContextSwitchTo(TopMemoryContext);
439+
Lsm3Entries = lappend(Lsm3Entries, entry);
440+
MemoryContextSwitchTo(old_context);
431441
}
432442
index->rd_rel->relam = BTREE_AM_OID;
433443
result = btbuild(heap, index, indexInfo);
@@ -436,6 +446,25 @@ lsm3_build(Relation heap, Relation index, IndexInfo *indexInfo)
436446
return result;
437447
}
438448

449+
/*
450+
* Grab previously release self locks (to let merger to proceed).
451+
*/
452+
static void
453+
lsm3_reacquire_locks(void)
454+
{
455+
if (Lsm3ReleasedLocks)
456+
{
457+
ListCell* cell;
458+
foreach (cell, Lsm3ReleasedLocks)
459+
{
460+
Oid indexOid = lfirst_oid(cell);
461+
LockRelationOid(indexOid, RowExclusiveLock);
462+
}
463+
list_free(Lsm3ReleasedLocks);
464+
Lsm3ReleasedLocks = NULL;
465+
}
466+
}
467+
439468
/* Insert in active top index, on overflow swap active indexes and initiate merge to base index */
440469
static bool
441470
lsm3_insert(Relation rel, Datum *values, bool *isnull,
@@ -475,7 +504,7 @@ lsm3_insert(Relation rel, Datum *values, bool *isnull,
475504
index->rd_rel->relam = save_am;
476505

477506
overflow = !entry->merge_in_progress /* do not check for overflow if merge was already initiated */
478-
&& (entry->n_inserts % LSM3_CHECK_TOP_INDEX_SIZE_PERIOD) == 0 /* perform check only each N-th insert */
507+
&& (entry->n_inserts % LSM3_CHECK_TOP_INDEX_SIZE_PERIOD) == 0 /* perform check only each N-th insert */
479508
&& RelationGetNumberOfBlocks(index)*(BLCKSZ/1024) > top_index_size;
480509

481510
SpinLockAcquire(&entry->spinlock);
@@ -499,8 +528,18 @@ lsm3_insert(Relation rel, Datum *values, bool *isnull,
499528
/* Holding lock on non-ative index prevent merger bgworker from truncation this index */
500529
if (LockHeldByMe(&tag, RowExclusiveLock))
501530
{
502-
LockRelease(&tag, RowExclusiveLock, false);
503-
Lsm3ReleasedLocks = lappend_oid(Lsm3ReleasedLocks, entry->top[1-active_index]);
531+
/* Copy locks all indexes and hold this locks until end of copy.
532+
* We can not just release lock, because otherwise CopyFrom produces
533+
* "you don't own a lock of type" warning.
534+
* So just try to periodically release this lock and let merger grab it.
535+
*/
536+
if (!Lsm3InsideCopy ||
537+
(entry->n_inserts % LSM3_CHECK_TOP_INDEX_SIZE_PERIOD) == 0) /* release lock only each N-th insert */
538+
539+
{
540+
LockRelease(&tag, RowExclusiveLock, false);
541+
Lsm3ReleasedLocks = lappend_oid(Lsm3ReleasedLocks, entry->top[1-active_index]);
542+
}
504543
}
505544

506545
/* If all inserts in previous active index are completed then we can start merge */
@@ -516,6 +555,12 @@ lsm3_insert(Relation rel, Datum *values, bool *isnull,
516555
}
517556
SpinLockRelease(&entry->spinlock);
518557

558+
/* We have to require released locks because othervise CopyFrom will produce warning */
559+
if (Lsm3InsideCopy && Lsm3ReleasedLocks)
560+
{
561+
pg_usleep(1); /* give merge thread a chance to grab the lock before we require it */
562+
lsm3_reacquire_locks();
563+
}
519564
return false;
520565
}
521566

@@ -849,7 +894,8 @@ lsm3_process_utility(PlannedStmt *plannedStmt,
849894
List* drop_oids = NULL;
850895
ListCell* cell;
851896

852-
Lsm3Entry = NULL; /* Reset entry to check it after utility statement execution */
897+
Lsm3Entries = NULL; /* Reset entry to check it after utility statement execution */
898+
Lsm3InsideCopy = false;
853899
if (IsA(parseTree, DropStmt))
854900
{
855901
drop = (DropStmt*)parseTree;
@@ -880,6 +926,10 @@ lsm3_process_utility(PlannedStmt *plannedStmt,
880926
}
881927
}
882928
}
929+
else if (IsA(parseTree, CopyStmt))
930+
{
931+
Lsm3InsideCopy = true;
932+
}
883933

884934
(PreviousProcessUtilityHook ? PreviousProcessUtilityHook : standard_ProcessUtility)
885935
(plannedStmt,
@@ -890,23 +940,26 @@ lsm3_process_utility(PlannedStmt *plannedStmt,
890940
destReceiver,
891941
completionTag);
892942

893-
if (Lsm3Entry)
943+
if (Lsm3Entries)
894944
{
895-
if (IsA(parseTree, IndexStmt)) /* This is Lsm3 creation statement */
945+
foreach (cell, Lsm3Entries)
896946
{
897-
IndexStmt* stmt = (IndexStmt*)parseTree;
898-
char* originIndexName = stmt->idxname;
899-
char* originAccessMethod = stmt->accessMethod;
900-
901-
for (int i = 0; i < 2; i++)
947+
Lsm3DictEntry* entry = (Lsm3DictEntry*)lfirst(cell);
948+
if (IsA(parseTree, IndexStmt)) /* This is Lsm3 creation statement */
902949
{
903-
if (stmt->concurrent)
950+
IndexStmt* stmt = (IndexStmt*)parseTree;
951+
char* originIndexName = stmt->idxname;
952+
char* originAccessMethod = stmt->accessMethod;
953+
954+
for (int i = 0; i < 2; i++)
904955
{
905-
PushActiveSnapshot(GetTransactionSnapshot());
906-
}
907-
stmt->accessMethod = "lsm3_btree_wrapper";
908-
stmt->idxname = psprintf("%s_top%d", get_rel_name(Lsm3Entry->base), i);
909-
Lsm3Entry->top[i] = DefineIndex(Lsm3Entry->heap,
956+
if (stmt->concurrent)
957+
{
958+
PushActiveSnapshot(GetTransactionSnapshot());
959+
}
960+
stmt->accessMethod = "lsm3_btree_wrapper";
961+
stmt->idxname = psprintf("%s_top%d", get_rel_name(entry->base), i);
962+
entry->top[i] = DefineIndex(entry->heap,
910963
stmt,
911964
InvalidOid,
912965
InvalidOid,
@@ -916,36 +969,39 @@ lsm3_process_utility(PlannedStmt *plannedStmt,
916969
false,
917970
false,
918971
true).objectId;
972+
}
973+
stmt->accessMethod = originAccessMethod;
974+
stmt->idxname = originIndexName;
919975
}
920-
stmt->accessMethod = originAccessMethod;
921-
stmt->idxname = originIndexName;
922-
}
923-
else
924-
{
925-
for (int i = 0; i < 2; i++)
976+
else
926977
{
927-
if (Lsm3Entry->top[i] == InvalidOid)
978+
for (int i = 0; i < 2; i++)
928979
{
929-
char* topidxname = psprintf("%s_top%d", get_rel_name(Lsm3Entry->base), i);
930-
Lsm3Entry->top[i] = get_relname_relid(topidxname, get_rel_namespace(Lsm3Entry->base));
931-
if (Lsm3Entry->top[i] == InvalidOid)
980+
if (entry->top[i] == InvalidOid)
932981
{
933-
elog(ERROR, "Lsm3: failed to lookup %s index", topidxname);
982+
char* topidxname = psprintf("%s_top%d", get_rel_name(entry->base), i);
983+
entry->top[i] = get_relname_relid(topidxname, get_rel_namespace(entry->base));
984+
if (entry->top[i] == InvalidOid)
985+
{
986+
elog(ERROR, "Lsm3: failed to lookup %s index", topidxname);
987+
}
934988
}
935989
}
936990
}
991+
if (ActiveSnapshotSet())
992+
{
993+
PopActiveSnapshot();
994+
}
995+
CommitTransactionCommand();
996+
StartTransactionCommand();
997+
/* Mark top index as invalid to prevent planner from using it in queries */
998+
for (int i = 0; i < 2; i++)
999+
{
1000+
index_set_state_flags(entry->top[i], INDEX_DROP_CLEAR_VALID);
1001+
}
9371002
}
938-
if (ActiveSnapshotSet())
939-
{
940-
PopActiveSnapshot();
941-
}
942-
CommitTransactionCommand();
943-
StartTransactionCommand();
944-
/* Mark top index as invalid to prevent planner from using it in queries */
945-
for (int i = 0; i < 2; i++)
946-
{
947-
index_set_state_flags(Lsm3Entry->top[i], INDEX_DROP_CLEAR_VALID);
948-
}
1003+
list_free(Lsm3Entries);
1004+
Lsm3Entries = NULL;
9491005
LWLockRelease(Lsm3DictLock); /* Release lock set by lsm3_build */
9501006
}
9511007
else if (drop_objects)
@@ -961,23 +1017,14 @@ lsm3_process_utility(PlannedStmt *plannedStmt,
9611017
}
9621018

9631019
/*
964-
* Executor sinish hookto reclaim released locks on non-active top indexes
1020+
* Executor finish hook to reclaim released locks on non-active top indexes
9651021
* to avoid "you don't own a lock of type RowExclusiveLock" warning
9661022
*/
9671023
static void
9681024
lsm3_executor_finish(QueryDesc *queryDesc)
9691025
{
970-
if (Lsm3ReleasedLocks)
971-
{
972-
ListCell* cell;
973-
foreach (cell, Lsm3ReleasedLocks)
974-
{
975-
Oid indexOid = lfirst_oid(cell);
976-
LockRelationOid(indexOid, RowExclusiveLock);
977-
}
978-
list_free(Lsm3ReleasedLocks);
979-
Lsm3ReleasedLocks = NULL;
980-
}
1026+
lsm3_reacquire_locks();
1027+
Lsm3InsideCopy = false;
9811028
if (PreviousExecutorFinish)
9821029
PreviousExecutorFinish(queryDesc);
9831030
else

0 commit comments

Comments
 (0)