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

Storing LOBs in separate files (outside of the database) is no longer supported for new databases.

上级 5c58a48f
......@@ -1323,10 +1323,8 @@ SET MAX_LENGTH_INPLACE_LOB int
","
Sets the maximum size of an in-place LOB object.
If the 'h2.lobInDatabase' property is true, this is the maximum length of an LOB that is stored with the record itself,
This is the maximum length of an LOB that is stored with the record itself,
and the default value is 128.
If the 'h2.lobInDatabase' property is false, this is the maximum length of an LOB that is stored in the database file,
and the default value is 4096.
This setting has no effect for in-memory databases.
......
......@@ -140,9 +140,6 @@ should never be used for columns with a maximum size below about 200 bytes.
The best threshold depends on the use case; reading in-place objects is faster
than reading from separate files, but slows down the performance of operations
that don't involve this column.
</p><p>
It is possible to configure the database to store LOB objects outside the database file,
see the <a href="../javadoc/org/h2/constant/SysProperties.html#h2.lobInDatabase">h2.lobInDatabase</a> property.
</p>
<h3>Large Object Compression</h3>
......
......@@ -18,7 +18,8 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>Lucene 2 is no longer supported.
<ul><li>Storing LOBs in separate files (outside of the database) is no longer supported for new databases.
</li><li>Lucene 2 is no longer supported.
</li></ul>
<h2>Version 1.3.175 (2014-01-18)</h2>
......
......@@ -198,12 +198,6 @@ public class SysProperties {
*/
public static final int LOB_FILES_PER_DIRECTORY = Utils.getProperty("h2.lobFilesPerDirectory", 256);
/**
* System property <code>h2.lobInDatabase</code> (default: true).<br />
* Store LOB files in the database.
*/
public static final boolean LOB_IN_DATABASE = Utils.getProperty("h2.lobInDatabase", true);
/**
* System property <code>h2.lobClientMaxSizeMemory</code> (default:
* 1048576).<br />
......
......@@ -199,18 +199,11 @@ public class Constants {
*/
public static final int DEFAULT_LOCK_MODE = LOCK_MODE_READ_COMMITTED;
/**
* The default maximum length of an LOB that is stored in the database file.
* Only used if h2.lobInDatabase==false.
*/
public static final int DEFAULT_MAX_LENGTH_INPLACE_LOB = 4096;
/**
* The default maximum length of an LOB that is stored with the record itself,
* and not in a separate place.
* Only used if h2.lobInDatabase==true.
*/
public static final int DEFAULT_MAX_LENGTH_INPLACE_LOB2 = 128;
public static final int DEFAULT_MAX_LENGTH_INPLACE_LOB = 128;
/**
* The default value for the maximum transaction log size.
......
......@@ -196,8 +196,7 @@ public class Database implements DataHandler {
this.fileEncryptionKey = ci.getFileEncryptionKey();
this.databaseName = name;
this.databaseShortName = parseDatabaseShortName();
this.maxLengthInplaceLob = SysProperties.LOB_IN_DATABASE ?
Constants.DEFAULT_MAX_LENGTH_INPLACE_LOB2 : Constants.DEFAULT_MAX_LENGTH_INPLACE_LOB;
this.maxLengthInplaceLob = Constants.DEFAULT_MAX_LENGTH_INPLACE_LOB;
this.cipher = cipher;
String lockMethodName = ci.getProperty("FILE_LOCK", null);
this.accessModeData = StringUtils.toLowerEnglish(ci.getProperty("ACCESS_MODE_DATA", "rw"));
......
......@@ -37,7 +37,6 @@ import org.h2.value.ValueFloat;
import org.h2.value.ValueGeometry;
import org.h2.value.ValueInt;
import org.h2.value.ValueJavaObject;
import org.h2.value.ValueLob;
import org.h2.value.ValueLobDb;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
......@@ -332,38 +331,16 @@ public class ValueDataType implements DataType {
case Value.BLOB:
case Value.CLOB: {
buff.put((byte) type);
if (v instanceof ValueLob) {
ValueLob lob = (ValueLob) v;
lob.convertToFileIfRequired(handler);
byte[] small = lob.getSmall();
if (small == null) {
int t = -1;
if (!lob.isLinked()) {
t = -2;
}
buff.putVarInt(t).
putVarInt(lob.getTableId()).
putVarInt(lob.getObjectId()).
putVarLong(lob.getPrecision()).
put((byte) (lob.isCompressed() ? 1 : 0));
if (t == -2) {
writeString(buff, lob.getFileName());
}
} else {
buff.putVarInt(small.length).put(small);
}
ValueLobDb lob = (ValueLobDb) v;
byte[] small = lob.getSmall();
if (small == null) {
buff.putVarInt(-3).
putVarInt(lob.getTableId()).
putVarLong(lob.getLobId()).
putVarLong(lob.getPrecision());
} else {
ValueLobDb lob = (ValueLobDb) v;
byte[] small = lob.getSmall();
if (small == null) {
buff.putVarInt(-3).
putVarInt(lob.getTableId()).
putVarLong(lob.getLobId()).
putVarLong(lob.getPrecision());
} else {
buff.putVarInt(small.length).
put(small);
}
buff.putVarInt(small.length).
put(small);
}
break;
}
......@@ -524,22 +501,7 @@ public class ValueDataType implements DataType {
ValueLobDb lob = ValueLobDb.create(type, handler, tableId, lobId, null, precision);
return lob;
} else {
int tableId = readVarInt(buff);
int objectId = readVarInt(buff);
long precision = 0;
boolean compression = false;
// -1: regular
// -2: regular, but not linked (in this case: including file name)
if (smallLen == -1 || smallLen == -2) {
precision = readVarLong(buff);
compression = buff.get() == 1;
}
if (smallLen == -2) {
String filename = readString(buff);
return ValueLob.openUnlinked(type, handler, tableId, objectId, precision, compression, filename);
}
ValueLob lob = ValueLob.openLinked(type, handler, tableId, objectId, precision, compression);
return lob;
throw DbException.get(ErrorCode.FILE_CORRUPTED_1, "lob type: " + smallLen);
}
}
case Value.ARRAY: {
......
......@@ -32,7 +32,6 @@ import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.New;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueLobDb;
/**
......@@ -196,27 +195,22 @@ public class LobStorageBackend implements LobStorageInterface {
* @param tableId the table id
*/
public void removeAllForTable(int tableId) {
if (SysProperties.LOB_IN_DATABASE) {
init();
try {
String sql = "SELECT ID FROM " + LOBS + " WHERE TABLE = ?";
PreparedStatement prep = prepare(sql);
prep.setInt(1, tableId);
ResultSet rs = prep.executeQuery();
while (rs.next()) {
removeLob(rs.getLong(1));
}
reuse(sql, prep);
} catch (SQLException e) {
throw DbException.convert(e);
}
if (tableId == LobStorageFrontend.TABLE_ID_SESSION_VARIABLE) {
removeAllForTable(LobStorageFrontend.TABLE_TEMP);
init();
try {
String sql = "SELECT ID FROM " + LOBS + " WHERE TABLE = ?";
PreparedStatement prep = prepare(sql);
prep.setInt(1, tableId);
ResultSet rs = prep.executeQuery();
while (rs.next()) {
removeLob(rs.getLong(1));
}
// remove both lobs in the database as well as in the file system
// (compatibility)
reuse(sql, prep);
} catch (SQLException e) {
throw DbException.convert(e);
}
if (tableId == LobStorageFrontend.TABLE_ID_SESSION_VARIABLE) {
removeAllForTable(LobStorageFrontend.TABLE_TEMP);
}
ValueLob.removeAllForTable(database, tableId);
}
/**
......@@ -554,23 +548,17 @@ public class LobStorageBackend implements LobStorageInterface {
@Override
public Value createBlob(InputStream in, long maxLength) {
if (SysProperties.LOB_IN_DATABASE) {
init();
return addLob(in, maxLength, Value.BLOB, null);
}
return ValueLob.createBlob(in, maxLength, database);
init();
return addLob(in, maxLength, Value.BLOB, null);
}
@Override
public Value createClob(Reader reader, long maxLength) {
if (SysProperties.LOB_IN_DATABASE) {
init();
long max = maxLength == -1 ? Long.MAX_VALUE : maxLength;
CountingReaderInputStream in = new CountingReaderInputStream(reader, max);
ValueLobDb lob = addLob(in, Long.MAX_VALUE, Value.CLOB, in);
return lob;
}
return ValueLob.createClob(reader, maxLength, database);
init();
long max = maxLength == -1 ? Long.MAX_VALUE : maxLength;
CountingReaderInputStream in = new CountingReaderInputStream(reader, max);
ValueLobDb lob = addLob(in, Long.MAX_VALUE, Value.CLOB, in);
return lob;
}
@Override
......
......@@ -10,10 +10,8 @@ import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueLobDb;
/**
......@@ -77,13 +75,10 @@ public class LobStorageFrontend implements LobStorageInterface {
@Override
public Value createBlob(InputStream in, long maxLength) {
if (SysProperties.LOB_IN_DATABASE) {
// need to use a temp file, because the input stream could come from
// the same database, which would create a weird situation (trying
// to read a block while write something)
return ValueLobDb.createTempBlob(in, maxLength, handler);
}
return ValueLob.createBlob(in, maxLength, handler);
// need to use a temp file, because the input stream could come from
// the same database, which would create a weird situation (trying
// to read a block while write something)
return ValueLobDb.createTempBlob(in, maxLength, handler);
}
/**
......@@ -95,13 +90,10 @@ public class LobStorageFrontend implements LobStorageInterface {
*/
@Override
public Value createClob(Reader reader, long maxLength) {
if (SysProperties.LOB_IN_DATABASE) {
// need to use a temp file, because the input stream could come from
// the same database, which would create a weird situation (trying
// to read a block while write something)
return ValueLobDb.createTempClob(reader, maxLength, handler);
}
return ValueLob.createClob(reader, maxLength, handler);
// need to use a temp file, because the input stream could come from
// the same database, which would create a weird situation (trying
// to read a block while write something)
return ValueLobDb.createTempClob(reader, maxLength, handler);
}
......@@ -113,16 +105,13 @@ public class LobStorageFrontend implements LobStorageInterface {
* @return the LOB
*/
public static Value createSmallLob(int type, byte[] small) {
if (SysProperties.LOB_IN_DATABASE) {
int precision;
if (type == Value.CLOB) {
precision = new String(small, Constants.UTF8).length();
} else {
precision = small.length;
}
return ValueLobDb.createSmallLob(type, small, precision);
int precision;
if (type == Value.CLOB) {
precision = new String(small, Constants.UTF8).length();
} else {
precision = small.length;
}
return ValueLob.createSmallLob(type, small);
return ValueLobDb.createSmallLob(type, small, precision);
}
}
......@@ -602,11 +602,32 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
if (this.precision <= precision) {
return this;
}
ValueLob lob;
ValueLobDb lob;
if (type == CLOB) {
lob = ValueLob.createClob(getReader(), precision, handler);
if (handler == null) {
try {
int p = MathUtils.convertLongToInt(precision);
String s = IOUtils.readStringAndClose(getReader(), p);
byte[] data = s.getBytes(Constants.UTF8);
lob = ValueLobDb.createSmallLob(type, data, s.length());
} catch (IOException e) {
throw DbException.convertIOException(e, null);
}
} else {
lob = ValueLobDb.createTempClob(getReader(), precision, handler);
}
} else {
lob = ValueLob.createBlob(getInputStream(), precision, handler);
if (handler == null) {
try {
int p = MathUtils.convertLongToInt(precision);
byte[] data = IOUtils.readBytesAndClose(getInputStream(), p);
lob = ValueLobDb.createSmallLob(type, data, data.length);
} catch (IOException e) {
throw DbException.convertIOException(e, null);
}
} else {
lob = ValueLobDb.createTempBlob(getInputStream(), precision, handler);
}
}
return lob;
}
......
......@@ -427,7 +427,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
if ("reopen".equals(args[0])) {
System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.check2", "false");
System.setProperty("h2.lobInDatabase", "true");
System.setProperty("h2.analyzeAuto", "100");
System.setProperty("h2.pageSize", "64");
System.setProperty("h2.reopenShift", "5");
......
......@@ -23,23 +23,20 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException;
import org.h2.store.FileLister;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
import org.h2.tools.DeleteDbFiles;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
import org.h2.util.Task;
import org.h2.util.Utils;
import org.h2.value.ValueLob;
/**
* Tests LOB and CLOB data types.
......@@ -81,11 +78,9 @@ public class TestLob extends TestBase {
testUniqueIndex();
testConvert();
testCreateAsSelect();
testDropAllObjects();
testDelete();
testTempFilesDeleted(true);
testTempFilesDeleted(false);
testAddLobRestart();
testLobServerMemory();
testUpdatingLobRow();
if (config.memory) {
......@@ -93,8 +88,6 @@ public class TestLob extends TestBase {
}
testLobCleanupSessionTemporaries();
testLobUpdateMany();
testLobDeleteTemp();
testLobDelete();
testLobVariable();
testLobDrop();
testLobNoClose();
......@@ -533,39 +526,8 @@ public class TestLob extends TestBase {
conn.close();
}
private void testDropAllObjects() throws Exception {
if (SysProperties.LOB_IN_DATABASE || config.memory) {
return;
}
deleteDb("lob");
Connection conn;
Statement stat;
conn = getConnection("lob");
stat = conn.createStatement();
stat.execute("create table test(id int primary key, name clob)");
stat.execute("insert into test values(1, space(10000))");
assertEquals(1, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
stat.execute("drop table test");
assertEquals(0, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
stat.execute("create table test(id int primary key, name clob)");
stat.execute("insert into test values(1, space(10000))");
assertEquals(1, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
stat.execute("drop all objects");
assertEquals(0, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
stat.execute("create table test(id int primary key, name clob)");
stat.execute("insert into test values(1, space(10000))");
assertEquals(1, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
stat.execute("truncate table test");
assertEquals(0, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
conn.close();
}
private void testDelete() throws Exception {
if (!SysProperties.LOB_IN_DATABASE || config.memory) {
if (config.memory) {
return;
}
deleteDb("lob");
......@@ -631,27 +593,6 @@ public class TestLob extends TestBase {
assertEquals("Unexpected temp file: " + list, 0, list.size());
}
private static 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 < 2000; 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");
......@@ -663,24 +604,7 @@ public class TestLob extends TestBase {
conn.close();
}
private void testLobDeleteTemp() throws SQLException {
if (SysProperties.LOB_IN_DATABASE) {
return;
}
deleteDb("lob");
Connection conn = getConnection("lob");
Statement stat = conn.createStatement();
stat.execute("create table test(data clob) as select space(100000) from dual");
assertEquals(1, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
stat.execute("delete from test");
conn.close();
assertEquals(0, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
}
private void testLobCleanupSessionTemporaries() throws SQLException {
if (!SysProperties.LOB_IN_DATABASE) {
return;
}
deleteDb("lob");
Connection conn = getConnection("lob");
Statement stat = conn.createStatement();
......@@ -716,44 +640,6 @@ public class TestLob extends TestBase {
conn.close();
}
private void testLobDelete() throws SQLException {
if (config.memory || SysProperties.LOB_IN_DATABASE) {
return;
}
deleteDb("lob");
Connection conn = reconnect(null);
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST(ID INT, DATA CLOB)");
stat.execute("INSERT INTO TEST SELECT X, SPACE(10000) FROM SYSTEM_RANGE(1, 10)");
ArrayList<String> list = FileLister.getDatabaseFiles(getBaseDir(), "lob", true);
stat.execute("UPDATE TEST SET DATA = SPACE(5000)");
collectAndWait();
stat.execute("CHECKPOINT");
ArrayList<String> list2 = FileLister.getDatabaseFiles(getBaseDir(), "lob", true);
if (list2.size() >= list.size() + 5) {
fail("Expected not many more files, got " + list2.size() + " was " + list.size());
}
stat.execute("DELETE FROM TEST");
collectAndWait();
stat.execute("CHECKPOINT");
ArrayList<String> list3 = FileLister.getDatabaseFiles(getBaseDir(), "lob", true);
if (list3.size() >= list.size()) {
fail("Expected less files, got " + list2.size() + " was " + list.size());
}
conn.close();
}
private static void collectAndWait() {
for (int i = 0; i < 3; i++) {
System.gc();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// ignore
}
}
private void testLobVariable() throws SQLException {
deleteDb("lob");
Connection conn = reconnect(null);
......@@ -1126,7 +1012,7 @@ public class TestLob extends TestBase {
time = System.currentTimeMillis() - time;
trace("time: " + time + " compress: " + compress);
conn.close();
if (!config.memory && SysProperties.LOB_IN_DATABASE) {
if (!config.memory) {
long length = new File(getBaseDir() + "/lob.h2.db").length();
trace("len: " + length + " compress: " + compress);
}
......
......@@ -40,7 +40,6 @@ public class TestLobApi extends TestBase {
* @param a ignored
*/
public static void main(String... a) throws Exception {
// System.setProperty("h2.lobInDatabase", "true");
TestBase.createCaller().init().test();
}
......
......@@ -27,7 +27,6 @@ public class TestDiskSpaceLeak {
* @param args ignored
*/
public static void main(String... args) throws Exception {
System.setProperty("h2.lobInDatabase", "true");
DeleteDbFiles.execute("data", null, true);
Class.forName("org.h2.Driver");
Connection conn;
......
......@@ -34,7 +34,6 @@ public class TestTempTableCrash {
System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.check2", "false");
System.setProperty("h2.lobInDatabase", "true");
FilePathRec.register();
System.setProperty("reopenShift", "4");
TestReopen reopen = new TestReopen();
......
......@@ -44,7 +44,6 @@ public class TestPageStore extends TestBase {
*/
public static void main(String... a) throws Exception {
System.setProperty("h2.check2", "true");
System.setProperty("h2.lobInDatabase", "true");
TestBase.createCaller().init().test();
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论