📄 database.java
字号:
dummy = DataPage.create(this, 0);
if (persistent) {
if (readOnly) {
traceSystem = new TraceSystem(null, false);
} else {
traceSystem = new TraceSystem(databaseName + Constants.SUFFIX_TRACE_FILE, true);
}
if (cipher != null) {
traceSystem.setManualEnabling(false);
}
traceSystem.setLevelFile(traceLevelFile);
traceSystem.setLevelSystemOut(traceLevelSystemOut);
traceSystem.getTrace(Trace.DATABASE)
.info("opening " + databaseName + " (build " + Constants.BUILD_ID + ")");
if (!readOnly && fileLockMethod != FileLock.LOCK_NO) {
lock = new FileLock(traceSystem, Constants.LOCK_SLEEP);
lock.lock(databaseName + Constants.SUFFIX_LOCK_FILE, fileLockMethod == FileLock.LOCK_SOCKET);
}
deleteOldTempFiles();
log = new LogSystem(this, databaseName, readOnly, accessModeLog);
openFileData();
log.open();
openFileIndex();
log.recover();
fileData.init();
try {
fileIndex.init();
} catch (Throwable e) {
if (recovery) {
traceSystem.getTrace(Trace.DATABASE).error("opening index", e);
fileIndex.close();
fileIndex.delete();
openFileIndex();
} else {
throw Message.convert(e);
}
}
reserveLobFileObjectIds();
writer = WriterThread.create(this, writeDelay);
} else {
traceSystem = new TraceSystem(null, false);
log = new LogSystem(null, null, false, null);
}
systemUser = new User(this, 0, Constants.DBA_NAME, true);
mainSchema = new Schema(this, 0, Constants.SCHEMA_MAIN, systemUser, true);
infoSchema = new Schema(this, -1, Constants.SCHEMA_INFORMATION, systemUser, true);
schemas.put(mainSchema.getName(), mainSchema);
schemas.put(infoSchema.getName(), infoSchema);
publicRole = new Role(this, 0, Constants.PUBLIC_ROLE_NAME, true);
roles.put(Constants.PUBLIC_ROLE_NAME, publicRole);
systemUser.setAdmin(true);
systemSession = new Session(this, systemUser, ++nextSessionId);
ObjectArray cols = new ObjectArray();
Column columnId = new Column("ID", Value.INT);
columnId.setNullable(false);
cols.add(columnId);
cols.add(new Column("HEAD", Value.INT));
cols.add(new Column("TYPE", Value.INT));
cols.add(new Column("SQL", Value.STRING));
meta = mainSchema.createTable("SYS", 0, cols, persistent, false);
IndexColumn[] pkCols = IndexColumn.wrap(new Column[] { columnId });
metaIdIndex = meta.addIndex(systemSession, "SYS_ID", 0, pkCols, IndexType.createPrimaryKey(
false, false), Index.EMPTY_HEAD, null);
objectIds.set(0);
// there could be views on system tables, so they must be added first
addMetaData(MetaTable.TABLES);
addMetaData(MetaTable.COLUMNS);
addMetaData(MetaTable.INDEXES);
addMetaData(MetaTable.TABLE_TYPES);
addMetaData(MetaTable.TYPE_INFO);
addMetaData(MetaTable.CATALOGS);
addMetaData(MetaTable.SETTINGS);
addMetaData(MetaTable.HELP);
addMetaData(MetaTable.SEQUENCES);
addMetaData(MetaTable.USERS);
addMetaData(MetaTable.ROLES);
addMetaData(MetaTable.RIGHTS);
addMetaData(MetaTable.FUNCTION_ALIASES);
addMetaData(MetaTable.SCHEMATA);
addMetaData(MetaTable.TABLE_PRIVILEGES);
addMetaData(MetaTable.COLUMN_PRIVILEGES);
addMetaData(MetaTable.COLLATIONS);
addMetaData(MetaTable.VIEWS);
addMetaData(MetaTable.IN_DOUBT);
addMetaData(MetaTable.CROSS_REFERENCES);
addMetaData(MetaTable.CONSTRAINTS);
addMetaData(MetaTable.FUNCTION_COLUMNS);
addMetaData(MetaTable.CONSTANTS);
addMetaData(MetaTable.DOMAINS);
addMetaData(MetaTable.TRIGGERS);
addMetaData(MetaTable.SESSIONS);
addMetaData(MetaTable.LOCKS);
starting = true;
Cursor cursor = metaIdIndex.find(systemSession, null, null);
// first, create all function aliases and sequences because
// they might be used in create table / view / constraints and so on
ObjectArray records = new ObjectArray();
while (cursor.next()) {
MetaRecord rec = new MetaRecord(cursor.get());
objectIds.set(rec.getId());
records.add(rec);
}
MetaRecord.sort(records);
for (int i = 0; i < records.size(); i++) {
MetaRecord rec = (MetaRecord) records.get(i);
rec.execute(this, systemSession, eventListener);
}
// try to recompile the views that are invalid
recompileInvalidViews(systemSession);
starting = false;
addDefaultSetting(systemSession, SetTypes.DEFAULT_LOCK_TIMEOUT, null, Constants.INITIAL_LOCK_TIMEOUT);
addDefaultSetting(systemSession, SetTypes.DEFAULT_TABLE_TYPE, null, Constants.DEFAULT_TABLE_TYPE);
addDefaultSetting(systemSession, SetTypes.TRACE_LEVEL_FILE, null, traceSystem.getLevelFile());
addDefaultSetting(systemSession, SetTypes.TRACE_LEVEL_SYSTEM_OUT, null, traceSystem.getLevelSystemOut());
addDefaultSetting(systemSession, SetTypes.CACHE_SIZE, null, SysProperties.CACHE_SIZE_DEFAULT);
addDefaultSetting(systemSession, SetTypes.CLUSTER, Constants.CLUSTERING_DISABLED, 0);
addDefaultSetting(systemSession, SetTypes.WRITE_DELAY, null, Constants.DEFAULT_WRITE_DELAY);
addDefaultSetting(systemSession, SetTypes.CREATE_BUILD, null, Constants.BUILD_ID);
if (!readOnly) {
removeUnusedStorages(systemSession);
}
systemSession.commit(true);
if (!readOnly && persistent) {
emergencyReserve = openFile(createTempFile(), "rw", false);
emergencyReserve.autoDelete();
emergencyReserve.setLength(SysProperties.EMERGENCY_SPACE_INITIAL);
}
traceSystem.getTrace(Trace.DATABASE).info("opened " + databaseName);
}
private void recompileInvalidViews(Session session) {
boolean recompileSuccessful;
do {
recompileSuccessful = false;
ObjectArray list = getAllSchemaObjects(DbObject.TABLE_OR_VIEW);
for (int i = 0; i < list.size(); i++) {
DbObject obj = (DbObject) list.get(i);
if (obj instanceof TableView) {
TableView view = (TableView) obj;
if (view.getInvalid()) {
try {
view.recompile(session);
} catch (Throwable e) {
// ignore
}
if (!view.getInvalid()) {
recompileSuccessful = true;
}
}
}
}
} while (recompileSuccessful);
// when opening a database, views are initialized before indexes,
// so they may not have the optimal plan yet
// this is not a problem, it is just nice to see the newest plan
ObjectArray list = getAllSchemaObjects(DbObject.TABLE_OR_VIEW);
for (int i = 0; i < list.size(); i++) {
DbObject obj = (DbObject) list.get(i);
if (obj instanceof TableView) {
TableView view = (TableView) obj;
if (!view.getInvalid()) {
try {
view.recompile(systemSession);
} catch (SQLException e) {
// ignore
}
}
}
}
}
private void removeUnusedStorages(Session session) throws SQLException {
if (persistent) {
ObjectArray storages = getAllStorages();
for (int i = 0; i < storages.size(); i++) {
Storage storage = (Storage) storages.get(i);
if (storage != null && storage.getRecordReader() == null) {
storage.delete(session);
}
}
}
}
private void addDefaultSetting(Session session, int type, String stringValue, int intValue) throws SQLException {
if (readOnly) {
return;
}
String name = SetTypes.getTypeName(type);
if (settings.get(name) == null) {
Setting setting = new Setting(this, allocateObjectId(false, true), name);
if (stringValue == null) {
setting.setIntValue(intValue);
} else {
setting.setStringValue(stringValue);
}
addDatabaseObject(session, setting);
}
}
public void removeStorage(int id, DiskFile file) {
if (SysProperties.CHECK) {
Storage s = (Storage) storageMap.get(id);
if (s == null || s.getDiskFile() != file) {
throw Message.getInternalError();
}
}
storageMap.remove(id);
}
public Storage getStorage(int id, DiskFile file) {
Storage storage = (Storage) storageMap.get(id);
if (storage != null) {
if (SysProperties.CHECK && storage.getDiskFile() != file) {
throw Message.getInternalError();
}
} else {
storage = new Storage(this, file, null, id);
storageMap.put(id, storage);
}
return storage;
}
private void addMetaData(int type) throws SQLException {
MetaTable m = new MetaTable(infoSchema, -1 - type, type);
infoSchema.add(m);
}
private synchronized void addMeta(Session session, DbObject obj) throws SQLException {
if (obj.getTemporary()) {
return;
}
Row r = meta.getTemplateRow();
MetaRecord rec = new MetaRecord(obj);
rec.setRecord(r);
objectIds.set(obj.getId());
meta.lock(session, true, true);
meta.addRow(session, r);
if (isMultiVersion()) {
// TODO this should work without MVCC, but avoid risks at the moment
session.log(meta, UndoLogRecord.INSERT, r);
}
}
public synchronized void removeMeta(Session session, int id) throws SQLException {
SearchRow r = meta.getTemplateSimpleRow(false);
r.setValue(0, ValueInt.get(id));
Cursor cursor = metaIdIndex.find(session, r, r);
if (cursor.next()) {
Row found = cursor.get();
meta.lock(session, true, true);
meta.removeRow(session, found);
if (isMultiVersion()) {
// TODO this should work without MVCC, but avoid risks at the
// moment
session.log(meta, UndoLogRecord.DELETE, found);
}
objectIds.clear(id);
if (SysProperties.CHECK) {
checkMetaFree(session, id);
}
}
}
private HashMap getMap(int type) {
switch (type) {
case DbObject.USER:
return users;
case DbObject.SETTING:
return settings;
case DbObject.ROLE:
return roles;
case DbObject.RIGHT:
return rights;
case DbObject.FUNCTION_ALIAS:
return functionAliases;
case DbObject.SCHEMA:
return schemas;
case DbObject.USER_DATATYPE:
return userDataTypes;
case DbObject.COMMENT:
return comments;
case DbObject.AGGREGATE:
return aggregates;
default:
throw Message.getInternalError("type=" + type);
}
}
public synchronized void addSchemaObject(Session session, SchemaObject obj) throws SQLException {
obj.getSchema().add(obj);
int id = obj.getId();
if (id > 0 && !starting) {
addMeta(session, obj);
}
}
public synchronized void addDatabaseObject(Session session, DbObject obj) throws SQLException {
HashMap map = getMap(obj.getType());
if (obj.getType() == DbObject.USER) {
User user = (User) obj;
if (user.getAdmin() && systemUser.getName().equals(Constants.DBA_NAME)) {
systemUser.rename(user.getName());
}
}
String name = obj.getName();
if (SysProperties.CHECK && map.get(name) != null) {
throw Message.getInternalError("object already exists");
}
int id = obj.getId();
if (id > 0 && !starting) {
addMeta(session, obj);
}
map.put(name, obj);
}
public Setting findSetting(String name) {
return (Setting) settings.get(name);
}
public Comment findComment(DbObject object) {
if (object.getType() == DbObject.COMMENT) {
return null;
}
String key = Comment.getKey(object);
return (Comment) comments.get(key);
}
public User findUser(String name) {
return (User) users.get(name);
}
public FunctionAlias findFunctionAlias(String name) {
return (FunctionAlias) functionAliases.get(name);
}
public UserAggregate findAggregate(String name) {
return (UserAggregate) aggregates.get(name);
}
public UserDataType findUserDataType(String name) {
return (UserDataType) userDataTypes.get(name);
}
public User getUser(String name, SQLException notFound) throws SQLException {
User user = (User) users.get(name);
if (user == null) {
try {
Thread.sleep(Constants.DELAY_WRONG_PASSWORD);
} catch (InterruptedException e) {
// ignore
}
throw notFound;
}
return user;
}
public User getUser(String name) throws SQLException {
return getUser(name, Message.getSQLException(ErrorCode.USER_NOT_FOUND_1, name));
}
public synchronized Session createSession(User user) throws SQLException {
if (exclusiveSession != null) {
throw Message.getSQLException(ErrorCode.DATABASE_IS_IN_EXCLUSIVE_MODE);
}
Session session = new Session(this, user, ++nextSessionId);
sessions.add(session);
traceSystem.getTrace(Trace.SESSION).info("connecting #" + session.getId() + " to " + databaseName);
if (delayedCloser != null) {
delayedCloser.reset();
delayedCloser = null;
}
return session;
}
public synchronized void removeSession(Session session) throws SQLException {
if (session != null) {
if (exclusiveSession == session) {
exclusiveSession = null;
}
sessions.remove(session);
if (session != systemSession) {
traceSystem.getTrace(Trace.SESSION).info("disconnecting #" + session.getId());
}
}
if (sessions.size() == 0 && session != systemSession) {
if (closeDelay == 0) {
close(false);
} else if (closeDelay < 0) {
return;
} else {
delayedCloser = new DatabaseCloser(this, closeDelay * 1000, false);
delayedCloser.setName("H2 Close Delay " + getShortName());
delayedCloser.setDaemon(true);
delayedCloser.start();
}
}
if (session != systemSession && session != null) {
traceSystem.getTrace(Trace.SESSION).info("disconnected #" + session.getId());
}
}
synchronized void close(boolean fromShutdownHook) {
closing = true;
if (sessions.size() > 0) {
if (!fromShutdownHook) {
return;
}
traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName + " from shutdown hook");
Session[] all = new Session[sessions.size()];
sessions.toArray(all);
for (int i = 0; i < all.length; i++) {
Session s = all[i];
try {
s.close();
} catch (SQLException e) {
traceSystem.getTrace(Trace.SESSION).error("disconnecting #" + s.getId(), e);
}
}
}
if (log != null) {
log.setDisabled(false);
}
traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName);
if (eventListener != null) {
// allow the event listener to connect to the database
closing = false;
DatabaseEventListener e = eventListener;
// set it to null, to make sure it's called only once
eventListener = null;
e.closingDatabase();
if (sessions.size() > 0) {
// if a connection was opened, we can't close the database
return;
}
closing = true;
}
try {
if (systemSession != null) {
ObjectArray tablesAndViews = getAllSchemaObjects(DbObject.TABLE_OR_VIEW);
for (int i = 0; i < tablesAndViews.size(); i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -