From 51fe8aff02967920f1f09ce408d5a861886f7f28 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 31 Jul 2022 20:48:15 -0700 Subject: [PATCH] Fixed unexpected data beyond EOF error - fixes #29 --- CHANGELOG.md | 4 ++++ src/ivfinsert.c | 49 ++++++++++++++++++++++++++----------------- test/t/007_inserts.pl | 33 +++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 test/t/007_inserts.pl diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e2158d..e61f436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.7 (unreleased) + +- Fixed `unexpected data beyond EOF` error + ## 0.2.6 (2022-05-22) - Improved performance of index creation for Postgres < 12 diff --git a/src/ivfinsert.c b/src/ivfinsert.c index 449d141..9a0f68c 100644 --- a/src/ivfinsert.c +++ b/src/ivfinsert.c @@ -53,18 +53,6 @@ FindInsertPage(Relation rel, Datum *values, BlockNumber *insertPage, ListInfo * } } -/* - * Prepare to insert an index tuple - */ -static void -LoadInsertPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state, BlockNumber insertPage) -{ - *buf = ReadBuffer(index, insertPage); - LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE); - *state = GenericXLogStart(index); - *page = GenericXLogRegisterBuffer(*state, *buf, 0); -} - /* * Insert a tuple into the index */ @@ -87,11 +75,18 @@ InsertTuple(Relation rel, IndexTuple itup, Relation heapRel, Datum *values) itemsz = MAXALIGN(IndexTupleSize(itup)); Assert(itemsz <= BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(IvfflatPageOpaqueData))); - LoadInsertPage(rel, &buf, &page, &state, insertPage); - /* Find a page to insert the item */ - while (PageGetFreeSpace(page) < itemsz) + for (;;) { + buf = ReadBuffer(rel, insertPage); + LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); + + state = GenericXLogStart(rel); + page = GenericXLogRegisterBuffer(state, buf, 0); + + if (PageGetFreeSpace(page) >= itemsz) + break; + insertPage = IvfflatPageGetOpaque(page)->nextblkno; if (BlockNumberIsValid(insertPage)) @@ -99,15 +94,31 @@ InsertTuple(Relation rel, IndexTuple itup, Relation heapRel, Datum *values) /* Move to next page */ GenericXLogAbort(state); UnlockReleaseBuffer(buf); - - LoadInsertPage(rel, &buf, &page, &state, insertPage); } else { /* Add a new page */ - IvfflatAppendPage(rel, &buf, &page, &state, MAIN_FORKNUM); + Buffer newbuf = IvfflatNewBuffer(rel, MAIN_FORKNUM); + Page newpage = GenericXLogRegisterBuffer(state, buf, GENERIC_XLOG_FULL_IMAGE); - insertPage = BufferGetBlockNumber(buf); + insertPage = BufferGetBlockNumber(newbuf); + + /* Update previous buffer */ + IvfflatPageGetOpaque(page)->nextblkno = insertPage; + + /* Init page */ + PageInit(newpage, BufferGetPageSize(newbuf), sizeof(IvfflatPageOpaqueData)); + IvfflatPageGetOpaque(newpage)->nextblkno = InvalidBlockNumber; + IvfflatPageGetOpaque(newpage)->page_id = IVFFLAT_PAGE_ID; + + /* Commit */ + MarkBufferDirty(buf); + MarkBufferDirty(newbuf); + GenericXLogFinish(state); + + /* Unlock */ + UnlockReleaseBuffer(buf); + UnlockReleaseBuffer(newbuf); } } diff --git a/test/t/007_inserts.pl b/test/t/007_inserts.pl new file mode 100644 index 0000000..40681de --- /dev/null +++ b/test/t/007_inserts.pl @@ -0,0 +1,33 @@ +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 3; + +# Initialize node +my $node = get_new_node('node'); +$node->init; +$node->start; + +# Create table and index +$node->safe_psql("postgres", "CREATE EXTENSION vector;"); +$node->safe_psql("postgres", "CREATE TABLE tst (v vector(768));"); +$node->safe_psql("postgres", + "INSERT INTO tst SELECT (SELECT array_agg(random()) FROM generate_series(1, 768)) FROM generate_series(1, 10000) i;" +); +$node->safe_psql("postgres", "CREATE INDEX ON tst USING ivfflat (v);"); + +$node->pgbench( + "--no-vacuum --client=5 --transactions=100", + 0, + [qr{actually processed}], + [qr{^$}], + "concurrent INSERTs", + { + "007_concurrent" => q( + BEGIN; + INSERT INTO tst SELECT (SELECT array_agg(random()) FROM generate_series(1, 768)) FROM generate_series(1, 10) i; + COMMIT; + ), + } +);