table.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 912 行 · 第 1/2 页
JAVA
912 行
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */package com.caucho.db.table;import com.caucho.db.Database;import com.caucho.db.index.BTree;import com.caucho.db.index.KeyCompare;import com.caucho.db.sql.CreateQuery;import com.caucho.db.sql.Expr;import com.caucho.db.sql.Parser;import com.caucho.db.sql.QueryContext;import com.caucho.db.store.Block;import com.caucho.db.store.Lock;import com.caucho.db.store.Store;import com.caucho.db.store.Transaction;import com.caucho.log.Log;import com.caucho.sql.SQLExceptionWrapper;import com.caucho.util.L10N;import com.caucho.vfs.Path;import com.caucho.vfs.ReadStream;import com.caucho.vfs.TempBuffer;import com.caucho.vfs.TempStream;import com.caucho.vfs.WriteStream;import java.io.IOException;import java.sql.SQLException;import java.util.ArrayList;import java.util.logging.Level;import java.util.logging.Logger;/** * Table format: * * <pre> * Block 0: allocation table * Block 1: fragment table * Block 2: table definition * 0 - store data * 1024 - table data * 1024 - index pointers * 2048 - CREATE text * Block 3: first data * </pre> */public class Table extends Store { private final static Logger log = Log.open(Table.class); private final static L10N L = new L10N(Table.class); private final static int ROOT_DATA_OFFSET = STORE_CREATE_END; private final static int INDEX_ROOT_OFFSET = ROOT_DATA_OFFSET + 32; private final static int ROOT_DATA_END = ROOT_DATA_OFFSET + 1024; public final static int INLINE_BLOB_SIZE = 120; public final static long ROW_CLOCK_MIN = 1024; public final static byte ROW_VALID = 0x1; public final static byte ROW_ALLOC = 0x2; public final static byte ROW_MASK = 0x3; private final static String DB_VERSION = "Resin-DB 3.1.1"; private final static String MIN_VERSION = "Resin-DB 3.1.1"; private final Row _row; private final int _rowLength; private final int _rowsPerBlock; private final int _rowEnd; private final Constraint[]_constraints; private final Column _autoIncrementColumn; private long _entries; private final Object _rowClockLock = new Object(); private long _rowClockAddr; private long _rowClockTotal; private long _rowClockUsed; private int _rowClockCount; private int _rowAllocCount; private long _autoIncrementValue = -1; private Lock _allocLock; private Lock _insertLock; Table(Database database, String name, Row row, Constraint constraints[]) { super(database, name, null); _row = row; _constraints = constraints; _rowLength = _row.getLength(); _rowsPerBlock = BLOCK_SIZE / _rowLength; _rowEnd = _rowLength * _rowsPerBlock; _rowClockAddr = 0; Column []columns = _row.getColumns(); Column autoIncrementColumn = null; for (int i = 0; i < columns.length; i++) { columns[i].setTable(this); if (columns[i].getAutoIncrement() >= 0) autoIncrementColumn = columns[i]; } _autoIncrementColumn = autoIncrementColumn; _insertLock = new Lock("table-insert:" + name); _allocLock = new Lock("table-alloc:" + name); } Row getRow() { return _row; } /** * Returns the length of a row. */ int getRowLength() { return _rowLength; } /** * Returns the end of the row */ int getRowEnd() { return _rowEnd; } public final Column []getColumns() { return _row.getColumns(); } /** * Returns the table's constraints. */ public final Constraint []getConstraints() { return _constraints; } /** * Returns the auto-increment column. */ public Column getAutoIncrementColumn() { return _autoIncrementColumn; } /** * Returns the column for the given column name. * * @param name the column name * * @return the column */ public Column getColumn(String name) { Column []columns = getColumns(); for (int i = 0; i < columns.length; i++) { if (columns[i].getName().equals(name)) return columns[i]; } return null; } /** * Returns the column index for the given column name. * * @param name the column name * * @return the column index. */ public int getColumnIndex(String name) throws SQLException { Column []columns = getColumns(); for (int i = 0; i < columns.length; i++) { if (columns[i].getName().equals(name)) return i; } return -1; } /** * Loads the table from the file. */ public static Table loadFromFile(Database db, String name) throws IOException, SQLException { Path path = db.getPath().lookup(name + ".db"); if (! path.exists()) { if (log.isLoggable(Level.FINE)) log.fine(db + " '" + path.getNativePath() + "' is an unknown table"); return null; //throw new SQLException(L.l("table {0} does not exist", name)); } String version = null; ReadStream is = path.openRead(); try { // skip allocation table and fragment table is.skip(DATA_START + ROOT_DATA_OFFSET); StringBuilder sb = new StringBuilder(); int ch; while ((ch = is.read()) > 0) { sb.append((char) ch); } version = sb.toString(); if (! version.startsWith("Resin-DB")) { throw new SQLException(L.l("table {0} is not a Resin DB. Version '{1}'", name, version)); } else if (version.compareTo(MIN_VERSION) < 0 || DB_VERSION.compareTo(version) < 0) { throw new SQLException(L.l("table {0} is out of date. Old version {1}.", name, version)); } } finally { is.close(); } is = path.openRead(); try { // skip allocation table and fragment table is.skip(DATA_START + ROOT_DATA_END); StringBuilder cb = new StringBuilder(); int ch; while ((ch = is.read()) > 0) { cb.append((char) ch); } String sql = cb.toString(); if (log.isLoggable(Level.FINER)) log.finer("Table[" + name + "] " + version + " loading\n" + sql); try { CreateQuery query = (CreateQuery) Parser.parse(db, sql); TableFactory factory = query.getFactory(); if (! factory.getName().equalsIgnoreCase(name)) throw new IOException(L.l("factory {0} does not match", name)); Table table = new Table(db, factory.getName(), factory.getRow(), factory.getConstraints()); table.init(); table.clearIndexes(); table.initIndexes(); table.rebuildIndexes(); return table; } catch (Exception e) { log.log(Level.FINE, e.toString(), e); log.warning(e.toString()); throw new SQLException(L.l("can't load table {0} in {1}.\n{2}", name, path.getNativePath(), e.toString())); } } finally { is.close(); } } /** * Creates the table. */ public void create() throws IOException, SQLException { super.create(); initIndexes(); byte []tempBuffer = new byte[BLOCK_SIZE]; readBlock(BLOCK_SIZE, tempBuffer, 0, BLOCK_SIZE); TempStream ts = new TempStream(); WriteStream os = new WriteStream(ts); try { for (int i = 0; i < ROOT_DATA_OFFSET; i++) os.write(tempBuffer[i]); writeTableHeader(os); } finally { os.close(); } TempBuffer head = ts.getHead(); int offset = 0; for (; head != null; head = head.getNext()) { byte []buffer = head.getBuffer(); int length = head.getLength(); System.arraycopy(buffer, 0, tempBuffer, offset, length); for (; length < buffer.length; length++) { tempBuffer[offset + length] = 0; } offset += buffer.length; } for (; offset < BLOCK_SIZE; offset++) tempBuffer[offset] = 0; writeBlock(BLOCK_SIZE, tempBuffer, 0, BLOCK_SIZE); _database.addTable(this); } /** * Initialize the indexes */ private void initIndexes() throws IOException, SQLException { Column []columns = _row.getColumns(); for (int i = 0; i < columns.length; i++) { Column column = columns[i]; if (! column.isUnique()) continue; KeyCompare keyCompare = column.getIndexKeyCompare(); if (keyCompare == null) continue; Block rootBlock = allocateIndexBlock(); long rootBlockId = rootBlock.getBlockId(); rootBlock.free(); BTree btree = new BTree(this, rootBlockId, column.getLength(), keyCompare); column.setIndex(btree); } } /** * Clears the indexes */ private void clearIndexes() throws IOException { Column []columns = _row.getColumns(); for (int i = 0; i < columns.length; i++) { BTree index = columns[i].getIndex(); if (index == null) continue; long rootAddr = index.getIndexRoot(); Block block = readBlock(addressToBlockId(rootAddr)); try { byte []blockBuffer = block.getBuffer(); synchronized (blockBuffer) { for (int j = 0; j < blockBuffer.length; j++) { blockBuffer[j] = 0; } block.setDirty(0, BLOCK_SIZE); } } finally { block.free(); } } long blockAddr = 0; while ((blockAddr = firstBlock(blockAddr + BLOCK_SIZE, ALLOC_INDEX)) > 0) { freeBlock(blockAddr); } } /** * Rebuilds the indexes */ private void rebuildIndexes() throws IOException, SQLException { Transaction xa = Transaction.create(); xa.setAutoCommit(true); try { TableIterator iter = createTableIterator(); iter.init(xa); Column []columns = _row.getColumns(); while (iter.nextBlock()) { iter.initRow(); byte []blockBuffer = iter.getBuffer();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?