提交 dfaf34f5 authored 作者: Thomas Mueller's avatar Thomas Mueller

Inserting LOBs got slower each time the process was restarted.

上级 fbb148e1
......@@ -28,6 +28,7 @@ import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils;
import org.h2.util.RandomUtils;
import org.h2.util.SmallLRUCache;
import org.h2.util.StringUtils;
......@@ -252,11 +253,12 @@ public class ValueLob extends Value {
private int getNewObjectId(DataHandler handler) throws SQLException {
String path = handler.getDatabasePath();
int objectId = 0;
int lobsPerDir = SysProperties.LOB_FILES_PER_DIRECTORY;
while (true) {
String dir = getFileNamePrefix(path, objectId);
String[] list = getFileList(handler, dir);
int fileCount = 0;
boolean[] used = new boolean[SysProperties.LOB_FILES_PER_DIRECTORY];
boolean[] used = new boolean[lobsPerDir];
for (String name : list) {
if (name.endsWith(Constants.SUFFIX_DB_FILE)) {
name = FileUtils.getFileName(name);
......@@ -269,13 +271,13 @@ public class ValueLob extends Value {
}
if (id > 0) {
fileCount++;
used[id % SysProperties.LOB_FILES_PER_DIRECTORY] = true;
used[id % lobsPerDir] = true;
}
}
}
int fileId = -1;
if (fileCount < SysProperties.LOB_FILES_PER_DIRECTORY) {
for (int i = 1; i < SysProperties.LOB_FILES_PER_DIRECTORY; i++) {
if (fileCount < lobsPerDir) {
for (int i = 1; i < lobsPerDir; i++) {
if (!used[i]) {
fileId = i;
break;
......@@ -287,26 +289,32 @@ public class ValueLob extends Value {
invalidateFileList(handler, dir);
break;
}
if (objectId > Integer.MAX_VALUE / SysProperties.LOB_FILES_PER_DIRECTORY) {
if (objectId > Integer.MAX_VALUE / lobsPerDir) {
// this directory path is full: start from zero
// (this can happen only theoretically,
// for example if the random number generator is broken)
objectId = 0;
dirCounter = RandomUtils.nextInt(lobsPerDir - 1) * lobsPerDir;
} else {
// calculate the directory
// start with 1 (otherwise we don't know the number of directories)
// it doesn't really matter what directory is used, it might as well be random
// (but that would generate more directories):
// int dirId = RandomUtils.nextInt(
// SysProperties.LOB_FILES_PER_DIRECTORY - 1) + 1;
int dirId = (dirCounter++ / (SysProperties.LOB_FILES_PER_DIRECTORY - 1)) + 1;
objectId = objectId * SysProperties.LOB_FILES_PER_DIRECTORY;
objectId += dirId * SysProperties.LOB_FILES_PER_DIRECTORY;
// int dirId = RandomUtils.nextInt(lobsPerDir - 1) + 1;
int dirId = (dirCounter++ / (lobsPerDir - 1)) + 1;
objectId = objectId * lobsPerDir;
objectId += dirId * lobsPerDir;
}
}
return objectId;
}
/**
* Reset the directory counter as if the process was stopped. This method is
* for debugging only (to simulate stopping a process).
*/
public static void resetDirCounter() {
dirCounter = 0;
}
private void invalidateFileList(DataHandler handler, String dir) {
SmallLRUCache<String, String[]> cache = handler.getLobFileListCache();
if (cache != null) {
......
......@@ -26,9 +26,11 @@ import java.util.Random;
import org.h2.constant.SysProperties;
import org.h2.store.FileLister;
import org.h2.test.TestBase;
import org.h2.tools.DeleteDbFiles;
import org.h2.util.IOUtils;
import org.h2.util.ObjectUtils;
import org.h2.util.StringUtils;
import org.h2.value.ValueLob;
/**
* Tests LOB and CLOB data types.
......@@ -45,6 +47,7 @@ public class TestLob extends TestBase {
}
public void test() throws Exception {
testAddLobRestart();
testLobServerMemory();
if (config.memory) {
return;
......@@ -74,6 +77,27 @@ public class TestLob extends TestBase {
deleteDb("lob");
}
private void testAddLobRestart() throws SQLException {
DeleteDbFiles.execute("memFS:", "lob", true);
Connection conn = org.h2.Driver.load().connect("jdbc:h2:memFS:lob", null);
Statement stat = conn.createStatement();
stat.execute("create table test(d blob)");
stat.execute("set MAX_LENGTH_INPLACE_LOB 1");
PreparedStatement prep = conn.prepareCall("insert into test values('0000')");
// long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
// if (i % 1000 == 0) {
// long now = System.currentTimeMillis();
// System.out.println(i + " " + (now - start));
// start = now;
// }
prep.execute();
ValueLob.resetDirCounter();
}
conn.close();
DeleteDbFiles.execute("memFS:", "lob", true);
}
private void testLobUpdateMany() throws SQLException {
deleteDb("lob");
Connection conn = getConnection("lob");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论