提交 cec0e8e0 authored 作者: Thomas Mueller Graf's avatar Thomas Mueller Graf

Docs

上级 8527b90d
...@@ -21,6 +21,11 @@ Change Log ...@@ -21,6 +21,11 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>MVStore CLOB and BLOB: An exception with the message "Block not found" could be thrown
when using the MVStore storage, when copying LOB objects
(for example due to "alter table" on a table with a LOB object),
and then re-opening the database.
</li>
<li>Fix for issue #171: Broken QueryStatisticsData duration data when trace level < TraceSystem.INFO <li>Fix for issue #171: Broken QueryStatisticsData duration data when trace level < TraceSystem.INFO
</li> </li>
<li>Pull request #170: Added SET QUERY_STATISTICS_MAX_ENTRIES <li>Pull request #170: Added SET QUERY_STATISTICS_MAX_ENTRIES
......
...@@ -19,6 +19,7 @@ Check docs, versions and links in main, downloads, build numbers ...@@ -19,6 +19,7 @@ Check docs, versions and links in main, downloads, build numbers
Check the PDF file size Check the PDF file size
Upload to SourceForge Upload to SourceForge
Upload to ftp://h2database.com/javadoc
Upload to ftp://h2database.com Upload to ftp://h2database.com
Upload to ftp://h2database.com/m2-repo Upload to ftp://h2database.com/m2-repo
Github: create a release Github: create a release
......
...@@ -24,6 +24,7 @@ import org.h2.mvstore.StreamStore; ...@@ -24,6 +24,7 @@ import org.h2.mvstore.StreamStore;
import org.h2.mvstore.db.MVTableEngine.Store; import org.h2.mvstore.db.MVTableEngine.Store;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLobDb; import org.h2.value.ValueLobDb;
...@@ -101,19 +102,26 @@ public class LobStorageMap implements LobStorageInterface { ...@@ -101,19 +102,26 @@ public class LobStorageMap implements LobStorageInterface {
if (dataMap.isEmpty()) { if (dataMap.isEmpty()) {
return; return;
} }
// search the last referenced block // search for the last block
// (a lob may not have any referenced blocks if data is kept inline, // (in theory, only the latest lob can have unreferenced blocks,
// so we need to loop) // but the latest lob could by a copy of another one, and
// we don't know that, so we iterate over all lobs)
long lastUsedKey = -1; long lastUsedKey = -1;
Long lobId = lobMap.lastKey(); for (Entry<Long, Object[]> e : lobMap.entrySet()) {
while (lobId != null) { long lobId = e.getKey();
Object[] v = lobMap.get(lobId); Object[] v = e.getValue();
byte[] id = (byte[]) v[0]; byte[] id = (byte[]) v[0];
lastUsedKey = streamStore.getMaxBlockKey(id); long max = streamStore.getMaxBlockKey(id);
if (lastUsedKey >= 0) { // a lob may not have a referenced blocks if data is kept inline
break; if (max != -1 && max > lastUsedKey) {
lastUsedKey = max;
if (TRACE) {
trace("lob " + lobId + " lastUsedKey=" + lastUsedKey);
} }
lobId = lobMap.lowerKey(lobId); }
}
if (TRACE) {
trace("lastUsedKey=" + lastUsedKey);
} }
// delete all blocks that are newer // delete all blocks that are newer
while (true) { while (true) {
...@@ -121,6 +129,9 @@ public class LobStorageMap implements LobStorageInterface { ...@@ -121,6 +129,9 @@ public class LobStorageMap implements LobStorageInterface {
if (last == null || last <= lastUsedKey) { if (last == null || last <= lastUsedKey) {
break; break;
} }
if (TRACE) {
trace("gc " + last);
}
dataMap.remove(last); dataMap.remove(last);
} }
// don't re-use block ids, except at the very end // don't re-use block ids, except at the very end
...@@ -349,10 +360,16 @@ public class LobStorageMap implements LobStorageInterface { ...@@ -349,10 +360,16 @@ public class LobStorageMap implements LobStorageInterface {
if (value != null) { if (value != null) {
byte[] s2 = (byte[]) value[0]; byte[] s2 = (byte[]) value[0];
if (Arrays.equals(streamStoreId, s2)) { if (Arrays.equals(streamStoreId, s2)) {
if (TRACE) {
trace(" stream still needed in lob " + value[1]);
}
hasMoreEntries = true; hasMoreEntries = true;
} }
} }
if (!hasMoreEntries) { if (!hasMoreEntries) {
if (TRACE) {
trace(" remove stream " + StringUtils.convertBytesToHex(streamStoreId));
}
streamStore.remove(streamStoreId); streamStore.remove(streamStoreId);
} }
} }
......
...@@ -50,6 +50,7 @@ public class TestMVTableEngine extends TestBase { ...@@ -50,6 +50,7 @@ public class TestMVTableEngine extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
testLobCopy();
testLobReuse(); testLobReuse();
testShutdownDuringLobCreation(); testShutdownDuringLobCreation();
testLobCreationThenShutdown(); testLobCreationThenShutdown();
...@@ -87,6 +88,27 @@ public class TestMVTableEngine extends TestBase { ...@@ -87,6 +88,27 @@ public class TestMVTableEngine extends TestBase {
testSimple(); testSimple();
} }
private void testLobCopy() throws Exception {
deleteDb(getTestName());
Connection conn = getConnection(getTestName());
Statement stat = conn.createStatement();
stat.execute("create table test(id int primary key, data clob)");
stat = conn.createStatement();
stat.execute("insert into test(id, data) values(2, space(300))");
stat.execute("insert into test(id, data) values(1, space(300))");
stat.execute("alter table test add column x int");
if (!config.memory) {
conn.close();
conn = getConnection(getTestName());
}
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select data from test");
while (rs.next()) {
rs.getString(1);
}
conn.close();
}
private void testLobReuse() throws Exception { private void testLobReuse() throws Exception {
deleteDb(getTestName()); deleteDb(getTestName());
Connection conn = getConnection(getTestName()); Connection conn = getConnection(getTestName());
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论