提交 36f3c9ef authored 作者: Thomas Mueller's avatar Thomas Mueller

Formatting, javadocs

上级 c4af37cd
......@@ -32,21 +32,24 @@ import org.h2.value.ValueLob;
import org.h2.value.ValueLobDb;
/**
* This class stores LOB objects in the database.
* This is the back-end i.e. the server side of the LOB storage.
* This class stores LOB objects in the database. This is the back-end i.e. the
* server side of the LOB storage.
* <p>
* Using the system session
* <p>
* Why do we use the system session to store the data? Some LOB operations can take a very long time.
* If we did them on a normal session, we would be locking the LOB tables for long periods of time,
* which is extremely detrimental to the rest of the system.
* Perhaps when we shift to the MVStore engine, we can revisit this design decision.
* Why do we use the system session to store the data? Some LOB operations can
* take a very long time. If we did them on a normal session, we would be
* locking the LOB tables for long periods of time, which is extremely
* detrimental to the rest of the system. Perhaps when we shift to the MVStore
* engine, we can revisit this design decision.
* <p>
* Locking Discussion
* <p>
* Normally, the locking order in H2 is: first lock the Session object, then lock the Database object.
* However, in the case of the LOB data, we are using the system session to store the data.
* If we locked the normal way, we see deadlocks caused by the following pattern:
* Normally, the locking order in H2 is: first lock the Session object, then
* lock the Database object. However, in the case of the LOB data, we are using
* the system session to store the data. If we locked the normal way, we see
* deadlocks caused by the following pattern:
*
* <pre>
* Thread 1:
* locks normal session
......@@ -56,9 +59,11 @@ import org.h2.value.ValueLobDb;
* locks system session
* waiting to lock database.
* </pre>
* So, in this class alone, we do two things: we have our very own dedicated session, the LOB session,
* and we take the locks in this order: first the Database object, and then the LOB session.
* Since we own the LOB session, no-one else can lock on it, and we are safe.
*
* So, in this class alone, we do two things: we have our very own dedicated
* session, the LOB session, and we take the locks in this order: first the
* Database object, and then the LOB session. Since we own the LOB session,
* no-one else can lock on it, and we are safe.
*/
public class LobStorageBackend implements LobStorageInterface {
......@@ -389,12 +394,14 @@ public class LobStorageBackend implements LobStorageInterface {
small = new byte[0];
}
if (small != null) {
// For a BLOB, precision is length in bytes. For a CLOB, precision is length in chars
// For a BLOB, precision is length in bytes.
// For a CLOB, precision is length in chars
long precision = countingReaderForClob == null ? small.length : countingReaderForClob.getLength();
ValueLobDb v = ValueLobDb.createSmallLob(type, small, precision);
return v;
}
// For a BLOB, precision is length in bytes. For a CLOB, precision is length in chars
// For a BLOB, precision is length in bytes.
// For a CLOB, precision is length in chars
long precision = countingReaderForClob == null ? length : countingReaderForClob.getLength();
return registerLob(type, lobId, LobStorageFrontend.TABLE_TEMP, length, precision);
} catch (IOException e) {
......@@ -585,19 +592,24 @@ public class LobStorageBackend implements LobStorageInterface {
}
}
}
private static void assertNotHolds(Object lock) {
if (Thread.holdsLock(lock)) {
throw DbException.throwInternalError();
}
}
/**
* Check whether this thread has synchronized on this object.
*
* @param lock the object
*/
static void assertHoldsLock(Object lock) {
if (!Thread.holdsLock(lock)) {
throw DbException.throwInternalError();
}
}
/**
* An input stream that reads from a LOB.
*/
......@@ -636,7 +648,7 @@ public class LobStorageBackend implements LobStorageInterface {
// before the lock on the database to prevent ABBA deadlocks
assertHoldsLock(conn.getSession());
assertHoldsLock(database);
if (byteCount == -1) {
String sql = "SELECT BYTE_COUNT FROM " + LOBS + " WHERE ID = ?";
PreparedStatement prep = prepare(sql);
......
......@@ -104,7 +104,7 @@ public class FilePathCrypt extends FilePathWrapper {
/**
* Convert a char array to a byte array, in UTF-16 format. The char array is
* not cleared after use (this must be done by the caller).
*
*
* @param passwordChars the password characters
* @return the byte array
*/
......
......@@ -165,7 +165,7 @@ public abstract class Table extends SchemaObjectBase {
*/
public abstract Index addIndex(Session session, String indexName, int indexId, IndexColumn[] cols, IndexType indexType,
boolean create, String indexComment);
/**
* Get the given row.
*
......
......@@ -236,7 +236,7 @@ public class MultiDimension implements Comparator<long[]> {
/**
* Combine entries if the size of the list is too large.
*
* @param list list of pairs(low, high)
* @param list list of pairs(low, high)
* @param total product of the gap lengths
*/
private void combineEntries(ArrayList<long[]> list, int total) {
......
......@@ -44,12 +44,15 @@ import javax.tools.ToolProvider;
*/
public class SourceCompiler {
/**
* The "com.sun.tools.javac.Main" (if available).
*/
static final JavaCompiler JAVA_COMPILER;
private static final Class<?> JAVAC_SUN;
private static final String COMPILE_DIR = Utils.getProperty("java.io.tmpdir", ".");
/**
* The class name to source code map.
*/
......@@ -59,7 +62,10 @@ public class SourceCompiler {
* The class name to byte code map.
*/
final HashMap<String, Class<?>> compiled = New.hashMap();
/**
* Whether to use the ToolProvider.getSystemJavaCompiler().
*/
boolean useJavaSystemCompiler = SysProperties.JAVA_SYSTEM_COMPILER;
static {
......@@ -91,10 +97,10 @@ public class SourceCompiler {
sources.put(className, source);
compiled.clear();
}
/**
* Enable or disable the usage of the Java system compiler.
*
*
* @param enabled true to enable
*/
public void setJavaSystemCompiler(boolean enabled) {
......@@ -221,7 +227,16 @@ public class SourceCompiler {
classFile.delete();
}
}
/**
* Get the complete source code (including package name, imports, and so
* on).
*
* @param packageName the package name
* @param className the class name
* @param source the (possibly shortened) source code
* @return the full source code
*/
static String getCompleteSourceCode(String packageName, String className, String source) {
if (source.startsWith("package ")) {
return source;
......@@ -231,7 +246,7 @@ public class SourceCompiler {
buff.append("package ").append(packageName).append(";\n");
}
int endImport = source.indexOf("@CODE");
String importCode =
String importCode =
"import java.util.*;\n" +
"import java.math.*;\n" +
"import java.sql.*;\n";
......@@ -246,13 +261,21 @@ public class SourceCompiler {
"}\n");
return buff.toString();
}
/**
* Compile using the standard java compiler.
*
* @param packageName the package name
* @param className the class name
* @param source the source code
* @return the class
*/
Class<?> javaxToolsJavac(String packageName, String className, String source) {
String fullClassName = packageName + "." + className;
StringWriter writer = new StringWriter();
JavaFileManager fileManager = new
ClassFileManager(JAVA_COMPILER
.getStandardFileManager(null, null, null));
.getStandardFileManager(null, null, null));
ArrayList<JavaFileObject> compilationUnits = new ArrayList<JavaFileObject>();
compilationUnits.add(new StringJavaFileObject(fullClassName, source));
JAVA_COMPILER.getTask(writer, fileManager, null, null,
......@@ -344,7 +367,7 @@ public class SourceCompiler {
* compile-time dependency unnecessarily.
*/
private static final class GroovyCompiler {
private static final Object LOADER;
private static final Throwable INIT_FAIL_EXCEPTION;
......@@ -358,12 +381,12 @@ public class SourceCompiler {
Object importCustomizer = Utils.newInstance(
"org.codehaus.groovy.control.customizers.ImportCustomizer");
// Call the method ImportCustomizer.addImports(String[])
String[] importsArray = new String[] {
"java.sql.Connection",
"java.sql.Types",
String[] importsArray = new String[] {
"java.sql.Connection",
"java.sql.Types",
"java.sql.ResultSet",
"groovy.sql.Sql",
"org.h2.tools.SimpleResultSet"
"groovy.sql.Sql",
"org.h2.tools.SimpleResultSet"
};
Utils.callMethod(importCustomizer, "addImports", new Object[] { importsArray });
......@@ -373,7 +396,7 @@ public class SourceCompiler {
Array.set(importCustomizerArray, 0, importCustomizer);
Object configuration = Utils.newInstance(
"org.codehaus.groovy.control.CompilerConfiguration");
Utils.callMethod(configuration,
Utils.callMethod(configuration,
"addCompilationCustomizers", new Object[] { importCustomizerArray });
ClassLoader parent = GroovyCompiler.class.getClassLoader();
......@@ -391,7 +414,7 @@ public class SourceCompiler {
throw new RuntimeException("Compile fail: no Groovy jar in the classpath", INIT_FAIL_EXCEPTION);
}
try {
Object codeSource = Utils.newInstance("groovy.lang.GroovyCodeSource",
Object codeSource = Utils.newInstance("groovy.lang.GroovyCodeSource",
source, packageAndClassName + ".groovy", "UTF-8");
Utils.callMethod(codeSource, "setCachable", false);
Class<?> clazz = (Class<?>) Utils.callMethod(LOADER, "parseClass", codeSource);
......@@ -401,7 +424,7 @@ public class SourceCompiler {
}
}
}
/**
* An in-memory java source file object.
*/
......@@ -419,15 +442,15 @@ public class SourceCompiler {
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return sourceCode;
}
}
/**
/**
* An in-memory java class object.
*/
static class JavaClassObject extends SimpleJavaFileObject {
protected final ByteArrayOutputStream out = new ByteArrayOutputStream();
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
public JavaClassObject(String name, Kind kind) {
super(URI.create("string:///" + name.replace('.', '/')
......@@ -443,12 +466,15 @@ public class SourceCompiler {
return out;
}
}
/**
* An in-memory class file manager.
*/
static class ClassFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
/**
* The class (only one class is kept).
*/
JavaClassObject classObject;
public ClassFileManager(StandardJavaFileManager standardManager) {
......
......@@ -200,7 +200,7 @@ public class ValueLob extends Value {
long m = compress ? Constants.IO_BUFFER_SIZE_COMPRESS : Constants.IO_BUFFER_SIZE;
if (m < remaining && m <= inplace) {
// using "1L" to force long arithmetic
m = Math.min(remaining, inplace + 1L);
m = Math.min(remaining, inplace + 1L);
// the buffer size must be bigger than the inplace lob, otherwise we can't
// know if it must be stored in-place or not
m = MathUtils.roundUpLong(m, Constants.IO_BUFFER_SIZE);
......
......@@ -41,13 +41,13 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
private final byte[] hmac;
private final byte[] small;
private final DataHandler handler;
/**
* For a BLOB, precision is length in bytes.
* For a CLOB, precision is length in chars.
*/
private final long precision;
private final String fileName;
private final FileStore tempFile;
private int tableId;
......@@ -121,7 +121,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
}
this.precision = tmpPrecision;
}
/**
* Create temporary BLOB from InputStream.
*/
......@@ -157,7 +157,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
}
this.precision = tmpPrecision;
}
private static String createTempLobFileName(DataHandler handler) throws IOException {
String path = handler.getDatabasePath();
if (path.length() == 0) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论