diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2011-08-16 01:13:21 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2011-08-16 01:13:21 +0000 |
commit | 1dd198ece14ae2c801e2e4195edd7d15a4fbf9b1 (patch) | |
tree | df4889bc54ebcf9083641594e7428b18acad4d74 /src/java/com/healthmarketscience | |
parent | 0d3bcef76d08155d9874138692e24cf5e96d4fbd (diff) | |
download | jackcess-1dd198ece14ae2c801e2e4195edd7d15a4fbf9b1.tar.gz jackcess-1dd198ece14ae2c801e2e4195edd7d15a4fbf9b1.zip |
make table loading re-entrant; load ace table on first use
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@573 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src/java/com/healthmarketscience')
-rw-r--r-- | src/java/com/healthmarketscience/jackcess/Database.java | 187 |
1 files changed, 129 insertions, 58 deletions
diff --git a/src/java/com/healthmarketscience/jackcess/Database.java b/src/java/com/healthmarketscience/jackcess/Database.java index 7326d69..3682f13 100644 --- a/src/java/com/healthmarketscience/jackcess/Database.java +++ b/src/java/com/healthmarketscience/jackcess/Database.java @@ -286,6 +286,8 @@ public class Database private static final String TABLE_SYSTEM_RELATIONSHIPS = "MSysRelationships"; /** Name of the table that contains queries */ private static final String TABLE_SYSTEM_QUERIES = "MSysQueries"; + /** Name of the table that contains complex type information */ + private static final String TABLE_SYSTEM_COMPLEX_COLS = "MSysComplexColumns"; /** Name of the main database properties object */ private static final String OBJECT_NAME_DB_PROPS = "MSysDb"; /** Name of the summary properties object */ @@ -381,12 +383,14 @@ public class Database private Table _systemCatalog; /** utility table finder */ private TableFinder _tableFinder; - /** System access control entries table */ + /** System access control entries table (initialized on first use) */ private Table _accessControlEntries; /** System relationships table (initialized on first use) */ private Table _relationships; /** System queries table (initialized on first use) */ private Table _queries; + /** System complex columns table (initialized on first use) */ + private Table _complexCols; /** SIDs to use for the ACEs added for new tables */ private final List<byte[]> _newTableSIDs = new ArrayList<byte[]>(); /** "big index support" is optional, but enabled by default */ @@ -735,7 +739,7 @@ public class Database } } } - + public PageChannel getPageChannel() { return _pageChannel; } @@ -752,13 +756,35 @@ public class Database } /** - * @return The system Access Control Entries table + * @return The system Access Control Entries table (loaded on demand) */ - public Table getAccessControlEntries() { + public Table getAccessControlEntries() throws IOException { + if(_accessControlEntries == null) { + _accessControlEntries = getSystemTable(TABLE_SYSTEM_ACES); + if(_accessControlEntries == null) { + throw new IOException("Could not find system table " + + TABLE_SYSTEM_ACES); + } + + } return _accessControlEntries; } /** + * @return the complex column system table (loaded on demand) + */ + public Table getSystemComplexColumns() throws IOException { + if(_complexCols == null) { + _complexCols = getSystemTable(TABLE_SYSTEM_COMPLEX_COLS); + if(_complexCols == null) { + throw new IOException("Could not find system table " + + TABLE_SYSTEM_COMPLEX_COLS); + } + } + return _complexCols; + } + + /** * Whether or not big index support is enabled for tables. */ public boolean doUseBigIndex() { @@ -892,6 +918,36 @@ public class Database } /** + * @return a (possibly cached) page ByteBuffer for internal use. the + * returned buffer should be released using + * {@link #releaseSharedBuffer} when no longer in use + */ + private ByteBuffer takeSharedBuffer() { + // we try to re-use a single shared _buffer, but occassionally, it may be + // needed by multiple operations at the same time (e.g. loading a + // secondary table while loading a primary table). this method ensures + // that we don't corrupt the _buffer, but instead force the second caller + // to use a new buffer. + if(_buffer != null) { + ByteBuffer curBuffer = _buffer; + _buffer = null; + return curBuffer; + } + return _pageChannel.createPageBuffer(); + } + + /** + * Relinquishes use of a page ByteBuffer returned by + * {@link #takeSharedBuffer}. + */ + private void releaseSharedBuffer(ByteBuffer buffer) { + // we always stuff the returned buffer back into _buffer. it doesn't + // really matter if multiple values over-write, at the end of the day, we + // just need one shared buffer + _buffer = buffer; + } + + /** * @return the currently configured database default language sort order for * textual columns */ @@ -919,10 +975,15 @@ public class Database * Reads various config info from the db page 0. */ private void initRootPageInfo() throws IOException { - _pageChannel.readPage(_buffer, 0); - _defaultSortOrder = Column.readSortOrder( - _buffer, _format.OFFSET_SORT_ORDER, _format); - _defaultCodePage = _buffer.getShort(_format.OFFSET_CODE_PAGE); + ByteBuffer buffer = takeSharedBuffer(); + try { + _pageChannel.readPage(buffer, 0); + _defaultSortOrder = Column.readSortOrder( + buffer, _format.OFFSET_SORT_ORDER, _format); + _defaultCodePage = buffer.getShort(_format.OFFSET_CODE_PAGE); + } finally { + releaseSharedBuffer(buffer); + } } /** @@ -965,8 +1026,6 @@ public class Database throw new IOException("Did not find required parent table id"); } - _accessControlEntries = getSystemTable(TABLE_SYSTEM_ACES); - if (LOG.isDebugEnabled()) { LOG.debug("Finished reading system catalog. Tables: " + getTableNames()); @@ -1033,7 +1092,7 @@ public class Database * @param tableDefPageNumber the page number of a table definition * @return The table, or null if it doesn't exist */ - protected Table getTable(int tableDefPageNumber) throws IOException { + public Table getTable(int tableDefPageNumber) throws IOException { // first, check for existing table Table table = _tableCache.get(tableDefPageNumber); @@ -1374,43 +1433,48 @@ public class Database */ public String getDatabasePassword() throws IOException { - _pageChannel.readPage(_buffer, 0); - - byte[] pwdBytes = new byte[_format.SIZE_PASSWORD]; - _buffer.position(_format.OFFSET_PASSWORD); - _buffer.get(pwdBytes); - - // de-mask password using extra password mask if necessary (the extra - // password mask is generated from the database creation date stored in - // the header) - byte[] pwdMask = getPasswordMask(_buffer, _format); - if(pwdMask != null) { - for(int i = 0; i < pwdBytes.length; ++i) { - pwdBytes[i] ^= pwdMask[i % pwdMask.length]; + ByteBuffer buffer = takeSharedBuffer(); + try { + _pageChannel.readPage(buffer, 0); + + byte[] pwdBytes = new byte[_format.SIZE_PASSWORD]; + buffer.position(_format.OFFSET_PASSWORD); + buffer.get(pwdBytes); + + // de-mask password using extra password mask if necessary (the extra + // password mask is generated from the database creation date stored in + // the header) + byte[] pwdMask = getPasswordMask(buffer, _format); + if(pwdMask != null) { + for(int i = 0; i < pwdBytes.length; ++i) { + pwdBytes[i] ^= pwdMask[i % pwdMask.length]; + } } - } - boolean hasPassword = false; - for(int i = 0; i < pwdBytes.length; ++i) { - if(pwdBytes[i] != 0) { - hasPassword = true; - break; + boolean hasPassword = false; + for(int i = 0; i < pwdBytes.length; ++i) { + if(pwdBytes[i] != 0) { + hasPassword = true; + break; + } } - } - if(!hasPassword) { - return null; - } + if(!hasPassword) { + return null; + } - String pwd = Column.decodeUncompressedText(pwdBytes, getCharset()); + String pwd = Column.decodeUncompressedText(pwdBytes, getCharset()); - // remove any trailing null chars - int idx = pwd.indexOf('\0'); - if(idx >= 0) { - pwd = pwd.substring(0, idx); - } + // remove any trailing null chars + int idx = pwd.indexOf('\0'); + if(idx >= 0) { + pwd = pwd.substring(0, idx); + } - return pwd; + return pwd; + } finally { + releaseSharedBuffer(buffer); + } } /** @@ -1506,28 +1570,29 @@ public class Database * @param pageNumber Page number that contains the table definition */ private void addToAccessControlEntries(int pageNumber) throws IOException { - + if(_newTableSIDs.isEmpty()) { initNewTableSIDs(); } - Column acmCol = _accessControlEntries.getColumn(ACE_COL_ACM); - Column inheritCol = _accessControlEntries.getColumn(ACE_COL_F_INHERITABLE); - Column objIdCol = _accessControlEntries.getColumn(ACE_COL_OBJECT_ID); - Column sidCol = _accessControlEntries.getColumn(ACE_COL_SID); + Table acEntries = getAccessControlEntries(); + Column acmCol = acEntries.getColumn(ACE_COL_ACM); + Column inheritCol = acEntries.getColumn(ACE_COL_F_INHERITABLE); + Column objIdCol = acEntries.getColumn(ACE_COL_OBJECT_ID); + Column sidCol = acEntries.getColumn(ACE_COL_SID); // construct a collection of ACE entries mimicing those of our parent, the // "Tables" system object List<Object[]> aceRows = new ArrayList<Object[]>(_newTableSIDs.size()); for(byte[] sid : _newTableSIDs) { - Object[] aceRow = new Object[_accessControlEntries.getColumnCount()]; + Object[] aceRow = new Object[acEntries.getColumnCount()]; aceRow[acmCol.getColumnIndex()] = SYS_FULL_ACCESS_ACM; aceRow[inheritCol.getColumnIndex()] = Boolean.FALSE; aceRow[objIdCol.getColumnIndex()] = Integer.valueOf(pageNumber); aceRow[sidCol.getColumnIndex()] = sid; aceRows.add(aceRow); } - _accessControlEntries.addRows(aceRows); + acEntries.addRows(aceRows); } /** @@ -1538,7 +1603,7 @@ public class Database // search for ACEs matching the tableParentId. use the index on the // objectId column if found (should be there) Cursor cursor = createCursorWithOptionalIndex( - _accessControlEntries, ACE_COL_OBJECT_ID, _tableParentId); + getAccessControlEntries(), ACE_COL_OBJECT_ID, _tableParentId); for(Map<String, Object> row : cursor) { Integer objId = (Integer)row.get(ACE_COL_OBJECT_ID); @@ -1565,16 +1630,22 @@ public class Database if(table != null) { return table; } - - // need to load table from db - _pageChannel.readPage(_buffer, pageNumber); - byte pageType = _buffer.get(0); - if (pageType != PageTypes.TABLE_DEF) { - throw new IOException("Looking for " + name + " at page " + pageNumber + - ", but page type is " + pageType); + + ByteBuffer buffer = takeSharedBuffer(); + try { + // need to load table from db + _pageChannel.readPage(buffer, pageNumber); + byte pageType = buffer.get(0); + if (pageType != PageTypes.TABLE_DEF) { + throw new IOException( + "Looking for " + name + " at page " + pageNumber + + ", but page type is " + pageType); + } + return _tableCache.put( + new Table(this, buffer, pageNumber, name, flags, useBigIndex)); + } finally { + releaseSharedBuffer(buffer); } - return _tableCache.put( - new Table(this, _buffer, pageNumber, name, flags, useBigIndex)); } /** |