use of org.h2.mvstore.db.TransactionStore.Change in project h2database by h2database.
the class PageBtreeLeaf method remove.
@Override
SearchRow remove(SearchRow row) {
int at = find(row, false, false, true);
SearchRow delete = getRow(at);
if (index.compareRows(row, delete) != 0 || delete.getKey() != row.getKey()) {
throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, index.getSQL() + ": " + row);
}
index.getPageStore().logUndo(this, data);
if (entryCount == 1) {
// the page is now empty
return row;
}
removeRow(at);
memoryChange();
index.getPageStore().update(this);
if (at == entryCount) {
// the last row changed
return getRow(at - 1);
}
// the last row didn't change
return null;
}
use of org.h2.mvstore.db.TransactionStore.Change in project h2database by h2database.
the class TestDateStorage method testDateTimeTimestampWithCalendar.
private void testDateTimeTimestampWithCalendar() throws SQLException {
Connection conn = getConnection(getTestName());
Statement stat = conn.createStatement();
stat.execute("create table ts(x timestamp primary key)");
stat.execute("create table t(x time primary key)");
stat.execute("create table d(x date)");
Calendar utcCalendar = new GregorianCalendar(new SimpleTimeZone(0, "Z"));
TimeZone old = TimeZone.getDefault();
DateTimeUtils.resetCalendar();
TimeZone.setDefault(TimeZone.getTimeZone("PST"));
try {
Timestamp ts1 = Timestamp.valueOf("2010-03-13 18:15:00");
Time t1 = new Time(ts1.getTime());
Date d1 = new Date(ts1.getTime());
// when converted to UTC, this is 03:15, which doesn't actually
// exist because of summer time change at that day
Timestamp ts2 = Timestamp.valueOf("2010-03-13 19:15:00");
Time t2 = new Time(ts2.getTime());
Date d2 = new Date(ts2.getTime());
PreparedStatement prep;
ResultSet rs;
prep = conn.prepareStatement("insert into ts values(?)");
prep.setTimestamp(1, ts1, utcCalendar);
prep.execute();
prep.setTimestamp(1, ts2, utcCalendar);
prep.execute();
prep = conn.prepareStatement("insert into t values(?)");
prep.setTime(1, t1, utcCalendar);
prep.execute();
prep.setTime(1, t2, utcCalendar);
prep.execute();
prep = conn.prepareStatement("insert into d values(?)");
prep.setDate(1, d1, utcCalendar);
prep.execute();
prep.setDate(1, d2, utcCalendar);
prep.execute();
rs = stat.executeQuery("select * from ts order by x");
rs.next();
assertEquals("2010-03-14 02:15:00", rs.getString(1));
assertEquals("2010-03-13 18:15:00.0", rs.getTimestamp(1, utcCalendar).toString());
assertEquals("2010-03-14 03:15:00.0", rs.getTimestamp(1).toString());
assertEquals("2010-03-14 02:15:00", rs.getString("x"));
assertEquals("2010-03-13 18:15:00.0", rs.getTimestamp("x", utcCalendar).toString());
assertEquals("2010-03-14 03:15:00.0", rs.getTimestamp("x").toString());
rs.next();
assertEquals("2010-03-14 03:15:00", rs.getString(1));
assertEquals("2010-03-13 19:15:00.0", rs.getTimestamp(1, utcCalendar).toString());
assertEquals("2010-03-14 03:15:00.0", rs.getTimestamp(1).toString());
assertEquals("2010-03-14 03:15:00", rs.getString("x"));
assertEquals("2010-03-13 19:15:00.0", rs.getTimestamp("x", utcCalendar).toString());
assertEquals("2010-03-14 03:15:00.0", rs.getTimestamp("x").toString());
rs = stat.executeQuery("select * from t order by x");
rs.next();
assertEquals("02:15:00", rs.getString(1));
assertEquals("18:15:00", rs.getTime(1, utcCalendar).toString());
assertEquals("02:15:00", rs.getTime(1).toString());
assertEquals("02:15:00", rs.getString("x"));
assertEquals("18:15:00", rs.getTime("x", utcCalendar).toString());
assertEquals("02:15:00", rs.getTime("x").toString());
rs.next();
assertEquals("03:15:00", rs.getString(1));
assertEquals("19:15:00", rs.getTime(1, utcCalendar).toString());
assertEquals("03:15:00", rs.getTime(1).toString());
assertEquals("03:15:00", rs.getString("x"));
assertEquals("19:15:00", rs.getTime("x", utcCalendar).toString());
assertEquals("03:15:00", rs.getTime("x").toString());
rs = stat.executeQuery("select * from d order by x");
rs.next();
assertEquals("2010-03-14", rs.getString(1));
assertEquals("2010-03-13", rs.getDate(1, utcCalendar).toString());
assertEquals("2010-03-14", rs.getDate(1).toString());
assertEquals("2010-03-14", rs.getString("x"));
assertEquals("2010-03-13", rs.getDate("x", utcCalendar).toString());
assertEquals("2010-03-14", rs.getDate("x").toString());
rs.next();
assertEquals("2010-03-14", rs.getString(1));
assertEquals("2010-03-13", rs.getDate(1, utcCalendar).toString());
assertEquals("2010-03-14", rs.getDate(1).toString());
assertEquals("2010-03-14", rs.getString("x"));
assertEquals("2010-03-13", rs.getDate("x", utcCalendar).toString());
assertEquals("2010-03-14", rs.getDate("x").toString());
} finally {
TimeZone.setDefault(old);
DateTimeUtils.resetCalendar();
}
stat.execute("drop table ts");
stat.execute("drop table t");
stat.execute("drop table d");
conn.close();
}
use of org.h2.mvstore.db.TransactionStore.Change in project h2database by h2database.
the class TestTransactionStore method testMultiStatement.
/**
* Tests behavior when used for a sequence of SQL statements. Each statement
* uses a savepoint. Within a statement, changes by the statement itself are
* not seen; the change is only seen when the statement finished.
* <p>
* Update statements that change the key of multiple rows may use delete/add
* pairs to do so (they don't need to first delete all entries and then
* re-add them). Trying to add multiple values for the same key is not
* allowed (an update statement that would result in a duplicate key).
*/
private void testMultiStatement() {
MVStore s = MVStore.open(null);
TransactionStore ts = new TransactionStore(s);
ts.init();
Transaction tx;
TransactionMap<String, String> m;
long startUpdate;
tx = ts.begin();
// start of statement
// create table test
startUpdate = tx.setSavepoint();
m = tx.openMap("test");
m.setSavepoint(startUpdate);
// start of statement
// insert into test(id, name) values(1, 'Hello'), (2, 'World')
startUpdate = tx.setSavepoint();
m.setSavepoint(startUpdate);
assertTrue(m.trySet("1", "Hello", true));
assertTrue(m.trySet("2", "World", true));
// not seen yet (within the same statement)
assertNull(m.get("1"));
assertNull(m.get("2"));
// start of statement
startUpdate = tx.setSavepoint();
// now we see the newest version
m.setSavepoint(startUpdate);
assertEquals("Hello", m.get("1"));
assertEquals("World", m.get("2"));
// update test set primaryKey = primaryKey + 1
// (this is usually a tricky case)
assertEquals("Hello", m.get("1"));
assertTrue(m.trySet("1", null, true));
assertTrue(m.trySet("2", "Hello", true));
assertEquals("World", m.get("2"));
// already updated by this statement, so it has no effect
// but still returns true because it was changed by this transaction
assertTrue(m.trySet("2", null, true));
assertTrue(m.trySet("3", "World", true));
// not seen within this statement
assertEquals("Hello", m.get("1"));
assertEquals("World", m.get("2"));
assertNull(m.get("3"));
// start of statement
startUpdate = tx.setSavepoint();
m.setSavepoint(startUpdate);
// select * from test
assertNull(m.get("1"));
assertEquals("Hello", m.get("2"));
assertEquals("World", m.get("3"));
// start of statement
startUpdate = tx.setSavepoint();
m.setSavepoint(startUpdate);
// update test set id = 1
// should fail: duplicate key
assertTrue(m.trySet("2", null, true));
assertTrue(m.trySet("1", "Hello", true));
assertTrue(m.trySet("3", null, true));
assertFalse(m.trySet("1", "World", true));
tx.rollbackToSavepoint(startUpdate);
startUpdate = tx.setSavepoint();
m.setSavepoint(startUpdate);
assertNull(m.get("1"));
assertEquals("Hello", m.get("2"));
assertEquals("World", m.get("3"));
tx.commit();
ts.close();
s.close();
}
use of org.h2.mvstore.db.TransactionStore.Change in project h2database by h2database.
the class TestTransactionStore method testGetModifiedMaps.
private void testGetModifiedMaps() {
MVStore s = MVStore.open(null);
TransactionStore ts = new TransactionStore(s);
ts.init();
Transaction tx;
TransactionMap<String, String> m1, m2, m3;
long sp;
tx = ts.begin();
m1 = tx.openMap("m1");
m2 = tx.openMap("m2");
m3 = tx.openMap("m3");
assertFalse(tx.getChanges(0).hasNext());
tx.commit();
tx = ts.begin();
m1 = tx.openMap("m1");
m2 = tx.openMap("m2");
m3 = tx.openMap("m3");
m1.put("1", "100");
sp = tx.setSavepoint();
m2.put("1", "100");
m3.put("1", "100");
Iterator<Change> it = tx.getChanges(sp);
assertTrue(it.hasNext());
Change c;
c = it.next();
assertEquals("m3", c.mapName);
assertEquals("1", c.key.toString());
assertNull(c.value);
assertTrue(it.hasNext());
c = it.next();
assertEquals("m2", c.mapName);
assertEquals("1", c.key.toString());
assertNull(c.value);
assertFalse(it.hasNext());
it = tx.getChanges(0);
assertTrue(it.hasNext());
c = it.next();
assertEquals("m3", c.mapName);
assertEquals("1", c.key.toString());
assertNull(c.value);
assertTrue(it.hasNext());
c = it.next();
assertEquals("m2", c.mapName);
assertEquals("1", c.key.toString());
assertNull(c.value);
assertTrue(it.hasNext());
c = it.next();
assertEquals("m1", c.mapName);
assertEquals("1", c.key.toString());
assertNull(c.value);
assertFalse(it.hasNext());
tx.rollbackToSavepoint(sp);
it = tx.getChanges(0);
assertTrue(it.hasNext());
c = it.next();
assertEquals("m1", c.mapName);
assertEquals("1", c.key.toString());
assertNull(c.value);
assertFalse(it.hasNext());
tx.commit();
s.close();
}
use of org.h2.mvstore.db.TransactionStore.Change in project h2database by h2database.
the class ArchiveToolStore method compress.
private void compress(String sourceDir) throws Exception {
start();
long tempSize = 8 * 1024 * 1024;
String tempFileName = fileName + ".temp";
ArrayList<String> fileNames = New.arrayList();
System.out.println("Reading the file list");
long totalSize = addFiles(sourceDir, fileNames);
System.out.println("Compressing " + totalSize / MB + " MB");
FileUtils.delete(tempFileName);
FileUtils.delete(fileName);
MVStore storeTemp = new MVStore.Builder().fileName(tempFileName).autoCommitDisabled().open();
final MVStore store = new MVStore.Builder().fileName(fileName).pageSplitSize(2 * 1024 * 1024).compressHigh().autoCommitDisabled().open();
MVMap<String, int[]> filesTemp = storeTemp.openMap("files");
long currentSize = 0;
int segmentId = 1;
int segmentLength = 0;
ByteBuffer buff = ByteBuffer.allocate(1024 * 1024);
for (String s : fileNames) {
String name = s.substring(sourceDir.length() + 1);
if (FileUtils.isDirectory(s)) {
// directory
filesTemp.put(name, new int[1]);
continue;
}
buff.clear();
buff.flip();
ArrayList<Integer> posList = new ArrayList<>();
try (FileChannel fc = FileUtils.open(s, "r")) {
boolean eof = false;
while (true) {
while (!eof && buff.remaining() < 512 * 1024) {
int remaining = buff.remaining();
buff.compact();
buff.position(remaining);
int l = fc.read(buff);
if (l < 0) {
eof = true;
}
buff.flip();
}
if (buff.remaining() == 0) {
break;
}
int position = buff.position();
int c = getChunkLength(buff.array(), position, buff.limit()) - position;
byte[] bytes = Arrays.copyOfRange(buff.array(), position, position + c);
buff.position(position + c);
int[] key = getKey(bucket, bytes);
key[3] = segmentId;
while (true) {
MVMap<int[], byte[]> data = storeTemp.openMap("data" + segmentId);
byte[] old = data.get(key);
if (old == null) {
// new
data.put(key, bytes);
break;
}
if (Arrays.equals(old, bytes)) {
// duplicate
break;
}
// same checksum: change checksum
key[2]++;
}
for (int i = 0; i < key.length; i++) {
posList.add(key[i]);
}
segmentLength += c;
currentSize += c;
if (segmentLength > tempSize) {
storeTemp.commit();
segmentId++;
segmentLength = 0;
}
printProgress(0, 50, currentSize, totalSize);
}
}
int[] posArray = new int[posList.size()];
for (int i = 0; i < posList.size(); i++) {
posArray[i] = posList.get(i);
}
filesTemp.put(name, posArray);
}
storeTemp.commit();
ArrayList<Cursor<int[], byte[]>> list = New.arrayList();
totalSize = 0;
for (int i = 1; i <= segmentId; i++) {
MVMap<int[], byte[]> data = storeTemp.openMap("data" + i);
totalSize += data.sizeAsLong();
Cursor<int[], byte[]> c = data.cursor(null);
if (c.hasNext()) {
c.next();
list.add(c);
}
}
segmentId = 1;
segmentLength = 0;
currentSize = 0;
MVMap<int[], byte[]> data = store.openMap("data" + segmentId);
MVMap<int[], Boolean> keepSegment = storeTemp.openMap("keep");
while (list.size() > 0) {
Collections.sort(list, new Comparator<Cursor<int[], byte[]>>() {
@Override
public int compare(Cursor<int[], byte[]> o1, Cursor<int[], byte[]> o2) {
int[] k1 = o1.getKey();
int[] k2 = o2.getKey();
int comp = 0;
for (int i = 0; i < k1.length - 1; i++) {
long x1 = k1[i];
long x2 = k2[i];
if (x1 > x2) {
comp = 1;
break;
} else if (x1 < x2) {
comp = -1;
break;
}
}
return comp;
}
});
Cursor<int[], byte[]> top = list.get(0);
int[] key = top.getKey();
byte[] bytes = top.getValue();
int[] k2 = Arrays.copyOf(key, key.length);
k2[key.length - 1] = 0;
// TODO this lookup can be avoided
// if we remember the last entry with k[..] = 0
byte[] old = data.get(k2);
if (old == null) {
if (segmentLength > tempSize) {
// switch only for new entries
// where segmentId is 0,
// so that entries with the same
// key but different segmentId
// are in the same segment
store.commit();
segmentLength = 0;
segmentId++;
data = store.openMap("data" + segmentId);
}
key = k2;
// new entry
data.put(key, bytes);
segmentLength += bytes.length;
} else if (Arrays.equals(old, bytes)) {
// duplicate
} else {
// almost a duplicate:
// keep segment id
keepSegment.put(key, Boolean.TRUE);
data.put(key, bytes);
segmentLength += bytes.length;
}
if (!top.hasNext()) {
list.remove(0);
} else {
top.next();
}
currentSize++;
printProgress(50, 100, currentSize, totalSize);
}
MVMap<String, int[]> files = store.openMap("files");
for (Entry<String, int[]> e : filesTemp.entrySet()) {
String k = e.getKey();
int[] ids = e.getValue();
if (ids.length == 1) {
// directory
files.put(k, ids);
continue;
}
int[] newIds = Arrays.copyOf(ids, ids.length);
for (int i = 0; i < ids.length; i += 4) {
int[] id = new int[4];
id[0] = ids[i];
id[1] = ids[i + 1];
id[2] = ids[i + 2];
id[3] = ids[i + 3];
if (!keepSegment.containsKey(id)) {
newIds[i + 3] = 0;
}
}
files.put(k, newIds);
}
store.commit();
storeTemp.close();
FileUtils.delete(tempFileName);
store.close();
System.out.println();
System.out.println("Compressed to " + FileUtils.size(fileName) / MB + " MB");
printDone();
}
Aggregations