📄 table.java
字号:
final long getFirstPage(){
return firstPage;
}
/**
* Return a list of Links to not commited rows. The list include only the rows that are visible for
* the current isolation level.
*/
List getInserts(SSConnection con){
synchronized(locks){
ArrayList inserts = new ArrayList();
if(con.isolationLevel <= Connection.TRANSACTION_READ_UNCOMMITTED){
for(int i=0; i<locksInsert.size(); i++){
TableStorePageInsert lock = (TableStorePageInsert)locksInsert.get(i);
inserts.add(lock.getLink());
}
}else{
for(int i=0; i<locksInsert.size(); i++){
TableStorePageInsert lock = (TableStorePageInsert)locksInsert.get(i);
if(lock.con == con)
inserts.add(lock.getLink());
}
}
return inserts;
}
}
/**
* Request a page lock. If the request is valid then it return the StorePage.
* If the lock can not be created within 5 seconds then it throw an exception.
* @param con The connection that request the lock
* @param pageOperation The operation that should be perform
* @param page The offset of the page
* @return a valid StorePage
* @throws Exception if a timeout occurs
*/
final TableStorePage requestLock(SSConnection con, int pageOperation, long page) throws Exception{
synchronized(locks){
if(raFile == null){
throw Utils.createSQLException("Table '" + name + "' was modified.");
}
long endTime = 0;
while(true){
TableStorePage storePage = requestLockImpl( con, pageOperation, page);
if(storePage != null)
return storePage; // the normal case should be the fasted
if(endTime == 0)
endTime = System.currentTimeMillis() + 5000;
long waitTime = endTime - System.currentTimeMillis();
if(waitTime <= 0)
throw Utils.createSQLException("Deadlock, can not create a lock on table '"+name+"'");
locks.wait(waitTime);
}
}
}
/**
* Request a page lock. If the request is valid then it return the StorePage.
* In the other case it return null.
* @param page The fileOffset or -1 for a new page
* @throws SQLException
*/
final private TableStorePage requestLockImpl(SSConnection con, int pageOperation, long page) throws SQLException{
synchronized(locks){
if(tabLockConnection != null && tabLockConnection != con) return null;
switch(con.isolationLevel){
case Connection.TRANSACTION_SERIALIZABLE:
serializeConnections.put( con, con);
break;
}
switch(pageOperation){
case SQLTokenizer.CREATE:{
// first check if another connection has a lock before creating a table lock
if(locks.size() > 0){
Iterator values = locks.values().iterator();
while(values.hasNext()){
TableStorePage lock = (TableStorePage)values.next();
if(lock.con != con) return null;
}
}
for(int i=0; i<locksInsert.size(); i++){
//the first StorePage in the linked list must be ever TableStorePageInsert
TableStorePageInsert lock = (TableStorePageInsert)locksInsert.get(i);
if(lock.con != con) return null;
}
if(serializeConnections.size() > 0){
Iterator values = serializeConnections.values().iterator();
while(values.hasNext()){
TableStorePage lock = (TableStorePage)values.next();
if(lock.con != con) return null;
}
}
tabLockConnection = con;
tabLockCount++;
TableStorePage lock = new TableStorePage(con, this, LOCK_TAB, page);
con.add(lock);
return lock;
}
case SQLTokenizer.ALTER:{
// first check if there is any lock before creating a table lock
if(locks.size() > 0 || locksInsert.size() > 0){
return null;
}
if(serializeConnections.size() > 0){
Iterator values = serializeConnections.values().iterator();
while(values.hasNext()){
TableStorePage lock = (TableStorePage)values.next();
if(lock.con != con) return null;
}
}
tabLockConnection = con;
tabLockCount++;
TableStorePage lock = new TableStorePage(con, this, LOCK_TAB, page);
lock.rollback();
return lock;
}
case SQLTokenizer.INSERT:{
// if there are more as one Connection with a serializable lock then an INSERT is not valid
if(serializeConnections.size() > 1) return null;
if(serializeConnections.size() == 1 && serializeConnections.get(con) != null) return null;
TableStorePageInsert lock = new TableStorePageInsert(con, this, LOCK_INSERT);
locksInsert.add( lock );
con.add(lock);
return lock;
}
case SQLTokenizer.SELECT:{
Long pageKey = new Long(page); //TODO performance
TableStorePage lockFirst;
TableStorePage lock = lockFirst = (TableStorePage)locks.get( pageKey );
while(lock != null){
if(lock.con == con ||
con.isolationLevel <= Connection.TRANSACTION_READ_UNCOMMITTED) return lock;
if(lock.lockType == LOCK_WRITE) return null; // write lock of another Connection
lock = lock.nextLock;
}
lock = new TableStorePage( con, this, LOCK_NONE, page);
if(con.isolationLevel >= Connection.TRANSACTION_REPEATABLE_READ){
lock.lockType = LOCK_READ;
lock.nextLock = lockFirst;
locks.put( pageKey, lock );
con.add(lock);
}
return lock;
}
case SQLTokenizer.LONGVARBINARY:
// is used for written BLOB and CLOB
// the difference to INSERT is that page descript the size of the byte buffer
return new TableStorePage( con, this, LOCK_INSERT, -1);
default:
throw new Error("pageOperation:"+pageOperation);
}
}
}
/**
* Request a write lock for a page that is read.
* @throws SQLException
*/
TableStorePage requestWriteLock(SSConnection con, TableStorePage readlock) throws SQLException{
if(readlock.lockType == LOCK_INSERT){
TableStorePage lock = new TableStorePage( con, this, LOCK_INSERT, -1);
readlock.nextLock = lock;
con.add(lock);
return lock;
}
Long pageKey = new Long(readlock.fileOffset); //TODO performance
TableStorePage lockFirst;
TableStorePage lock = lockFirst = (TableStorePage)locks.get( pageKey );
while(lock != null){
if(lock.con != con) return null; // there is already any lock from another connection, we can not start write
if(lock.lockType < LOCK_WRITE){
// if there is only a read lock we can transfer it
// this is requied for rollback to a savepoint
lock.lockType = LOCK_WRITE;
return lock;
}
lock = lock.nextLock;
}
lock = new TableStorePage( con, this, LOCK_WRITE, readlock.fileOffset);
lock.nextLock = lockFirst;
locks.put( pageKey, lock );
con.add(lock);
return lock;
}
/**
* Remove the lock from this table.
*/
void freeLock(TableStorePage storePage){
final int lockType = storePage.lockType;
final long fileOffset = storePage.fileOffset;
synchronized(locks){
try{
TableStorePage lock;
TableStorePage prev;
switch(lockType){
case LOCK_INSERT:
for(int i=0; i<locksInsert.size(); i++){
prev = lock = (TableStorePage)locksInsert.get(i);
while(lock != null){
if(lock == storePage){
//remove lock
if(lock == prev){
if(lock.nextLock == null){
// the first lock is the only lock in the list
locksInsert.remove(i--);
}else{
// only the first lock of the list is remove
locksInsert.set( i, lock.nextLock );
}
}else{
// a lock in the mid or end is removed
prev.nextLock = lock.nextLock;
}
return;
}
prev = lock;
lock = lock.nextLock;
}
}
break;
case LOCK_READ:
case LOCK_WRITE:
Long pageKey = new Long(fileOffset); //TODO performance
lock = (TableStorePage)locks.get( pageKey );
prev = lock;
while(lock != null){
if(lock == storePage){
//lock entfernen
if(lock == prev){
if(lock.nextLock == null){
// erste und einzige Lock in Liste
locks.remove(pageKey);
}else{
// erste Lock in liste f鋖lt weg
locks.put( pageKey, lock.nextLock );
}
}else{
// lock in mitte oder ende der Liste f鋖lt weg
prev = lock.nextLock;
}
return;
}
prev = lock;
lock = lock.nextLock;
}
// Durchl鋟fer kann auftreten, wenn eine Lock hochgestuft wurde und damit der type nicht stimmt
break;
case LOCK_TAB:
assert storePage.con == tabLockConnection : "Internal Error with TabLock";
if(--tabLockCount == 0) tabLockConnection = null;
break;
default:
throw new Error();
}
}finally{
locks.notifyAll();
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -