twok_string += twok_string;
}
T_AccessRow big_row = new T_AccessRow(2);
big_row.setCol(1, new SQLChar(twok_string));
// Create a heap conglomerate.
long orig_conglomid =
tc.createConglomerate(
"heap", // create a heap conglomerate
big_row.getRowArray(),
null, // column sort order not required for heap
null, // default properties
TransactionController.IS_DEFAULT); // not temporary
ConglomerateController cc =
tc.openConglomerate(
orig_conglomid,
false,
TransactionController.OPENMODE_FORUPDATE,
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_READ_UNCOMMITTED);
// add 5 pages worth of data.
for (int i = 0; i < 10; i++)
{
big_row.setCol(0, new SQLInteger(i));
cc.insert(big_row.getRowArray());
}
cc.close();
// Open another scan on the conglomerate.
ScanController base_scan = tc.openScan(
orig_conglomid,
true, // hold cursor open across commit
TransactionController.OPENMODE_FORUPDATE, // for update
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_SERIALIZABLE,
(FormatableBitSet) null, // all columns, all as objects
null, // start position - first row in conglomerate
0, // unused if start position is null.
null, // qualifier - accept all rows
null, // stop position - last row in conglomerate
0); // unused if stop position is null.
// now delete all the rows and remember the row location of the
// last row.
RowLocation deleted_page_rowloc = base_scan.newRowLocationTemplate();
for (int i = 0; i < 10; i++)
{
base_scan.next();
base_scan.fetchLocation(deleted_page_rowloc);
base_scan.delete();
tc.commit();
}
base_scan.close();
tc.commit();
// at this point the post commit thread should have reclaimed all the 5
// pages. Open it, at read uncommitted level.
cc = tc.openConglomerate(
orig_conglomid,
false,
0,
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_READ_UNCOMMITTED);
// Test heap fetch of row on page which does not exist.
if (cc.fetch(deleted_page_rowloc, big_row.getRowArray(), null))
{
throw T_Fail.testFailMsg(
"(readUncommitted) fetch should ret false for reclaimed page.");
}
// Test heap replace of row on page which does not exist.
FormatableBitSet update_desc = new FormatableBitSet(1);
if (cc.replace(deleted_page_rowloc, big_row.getRowArray(), update_desc))
{
throw T_Fail.testFailMsg(
"(readUncommitted) delete should ret false for reclaimed page.");
}
// Test heap fetch (overloaded call) of row on page which does not exist.
if (cc.fetch(deleted_page_rowloc, big_row.getRowArray(), null, true))
{
throw T_Fail.testFailMsg(
"(readUncommitted) fetch should ret false for reclaimed page.");
}
// Test heap delete of row on page which does not exist.
if (cc.delete(deleted_page_rowloc))
{
throw T_Fail.testFailMsg(
"(readUncommitted) delete should ret false for reclaimed page.");
}
cc.close();
/*
* TEST 2 - test heap fetch of row on page where row does not exist.
* <p>
* Do this by inserting enough rows to put 1 row on the 2nd page.
* Then delete this one row, which will queue a post commit to reclaim
* the row and page. Then insert one more row on the same page in
* the same xact. Now commit the xact, which will cause post commit
* to run which will reclaim the row but not the page. Then try and
* fetch the row which was deleted.
*/
// string column will be 1500 bytes, allowing 2 rows per page to fit.
SQLChar stringcol = new SQLChar();
stringcol.setValue(T_AccessFactory.repeatString("012345678901234", 100));
big_row.setCol(1, stringcol);
// Create a heap conglomerate.
orig_conglomid =
tc.createConglomerate(
"heap", // create a heap conglomerate
big_row.getRowArray(),
null, // column sort order not required for heap
null, // default properties
TransactionController.IS_DEFAULT); // not temporary
cc =
tc.openConglomerate(
orig_conglomid,
false,
TransactionController.OPENMODE_FORUPDATE,
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_READ_UNCOMMITTED);
// add 3 rows, should result in 1 row on second page.
for (int i = 0; i < 3; i++)
{
big_row.setCol(0, new SQLInteger(i));
cc.insert(big_row.getRowArray());
}
// Open another scan on the conglomerate.
base_scan = tc.openScan(
orig_conglomid,
true, // hold cursor open across commit
TransactionController.OPENMODE_FORUPDATE, // for update
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_SERIALIZABLE,
(FormatableBitSet) null, // all columns, all as objects
null, // start position - first row in conglomerate
0, // unused if start position is null.
null, // qualifier - accept all rows
null, // stop position - last row in conglomerate
0); // unused if stop position is null.
// now delete all the rows and remember the row location of the
// last row.
RowLocation deleted_row_rowloc = base_scan.newRowLocationTemplate();
for (int i = 0; i < 3; i++)
{
base_scan.next();
base_scan.fetchLocation(deleted_row_rowloc);
base_scan.delete();
}
// insert another row on page 2 to make sure page does not go away.
cc.insert(big_row.getRowArray());
cc.close();
base_scan.close();
tc.commit();
// at this point the post commit thread should have reclaimed all the
// deleted row on page 2, but not the page.
//
// Open it, at read uncommitted level.
cc = tc.openConglomerate(
orig_conglomid,
false,
0,
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_READ_UNCOMMITTED);
// the following will be attempting to fetch a row which has been
// reclaimed by post commit, on an existing page.
// test heap fetch of row on page where row does not exist.
if (cc.fetch(deleted_row_rowloc, big_row.getRowArray(), null))
{
throw T_Fail.testFailMsg(
"(readUncommitted) fetch should ret false for reclaimed row.");
}
// test heap replace of row on page where row does not exist.
if (cc.replace(deleted_page_rowloc, big_row.getRowArray(), update_desc))
{
throw T_Fail.testFailMsg(
"(readUncommitted) delete should ret false for reclaimed page.");
}
// test heap fetch (overloaded) of row on page where row does not exist.
if (cc.fetch(deleted_page_rowloc, big_row.getRowArray(), null, true))
{
throw T_Fail.testFailMsg(
"(readUncommitted) fetch should ret false for reclaimed page.");
}
// test heap delete of row on page where row does not exist.
if (cc.delete(deleted_page_rowloc))
{
throw T_Fail.testFailMsg(
"(readUncommitted) delete should ret false for reclaimed page.");
}
cc.close();
/*
* TEST 3 - test heap scan fetch of row on page prevents page from
* disappearing, but handles row being deleted.
* <p>
* A heap scan will maintain a scan lock on a page even if it is doing
* a read uncommitted scan. This will prevent the row/page from being
* reclaimed by post commit while the scan is positioned on the page.
* This presents no other concurrency issues for read uncommitted, it
* should be invisible to the user (deletes can still happen and the
* read uncommitted scanner will not block anyone).
*
* You need to at least get to the 2nd page, because the 1st page is
* never totally reclaimed and deleted by the system in a heap (it has
* some internal catalog information stored internally in row "0").
*/
big_row = new T_AccessRow(2);
big_row.setCol(1, new SQLChar(twok_string));
// Create a heap conglomerate.
orig_conglomid =
tc.createConglomerate(
"heap", // create a heap conglomerate