📄 rafcontainer.java
字号:
private boolean privRemoveFile(StorageFile file) throws StandardException { closeContainer(); dataFactory.writeInProgress(); try { if( file.exists()) return file.delete(); } finally { dataFactory.writeFinished(); } return true; } // end of privRemoveFile synchronized boolean openContainer(ContainerKey newIdentity) throws StandardException { actionCode = OPEN_CONTAINER_ACTION; actionIdentity = newIdentity; try { return AccessController.doPrivileged( this) != null; } catch( PrivilegedActionException pae){ throw (StandardException) pae.getException();} finally{ actionIdentity = null; } } private synchronized void stubbify(LogInstant instant) throws StandardException { // update header, synchronized this in case the cache is cleaning // this container at the same time. Make sure the clean and // stubbify is mutually exclusive. setDroppedState(true); setCommittedDropState(true); // The whole container should be shrunk into a 'stub'. // If the file system supports truncation, we can just truncate the // file after the header. Since it doesn't, we need to write out a // seperate file (the stub), then reset fileData to point to that, // then remove the current file. // // There may still be dirty pages that belongs to this file which are // still in the page cache. They need not really // be written since they don't really exist anymore // // there are 3 pieces of information on disk : // 1) the log operation that caused this file to be stubbified // 2) the stub // 3) the file // // The order of event, as far as persisent store is concerned, is // A) stub shows up // B) the file disappear // C) the log operation got flushed // (B and C may swap order) // // If neither A or B happens (we crashed before the sync call), // then nothing happened. // // if A happened but B and C did not, then when we recover, we will not // know the file has been stubbified. Hopefully, it will be stubbified // again if the post-commit queue manager is alerted to the fact. // // if A and B happened but C did not, then the file is stubbified but // there is no log record to indicate that. This is undesirable but // still safe because the only time we stubbify is on a post commit // operation, i.e., either a create container has rolled back or a // dropped container has committed. We end up having a a container // stub which behaves the same as a dropped container - only that all // the redo work is unnecessary because we 'know' it will // eventually be dropped and committed. // // If A and C happened and not B, then during redo, this stubbify // routine will be called again and the file will be deleted again // // The reason why A has to be sync'ed out is that we don't want B to // happen but A did not and the system crashed. Then we are left // with neither the file nor the stub and maybe even no log record. // Then the system is not recoverable. actionIdentity = (ContainerKey)getIdentity(); actionInstant = instant; actionCode = STUBBIFY_ACTION; try { AccessController.doPrivileged( this); } catch( PrivilegedActionException pae){ throw (StandardException) pae.getException();} finally { actionIdentity = null; actionInstant = null; } } // PrivilegedExceptionAction method public Object run() throws StandardException { switch( actionCode) { case GET_FILE_NAME_ACTION: return privGetFileName( actionIdentity, actionStub, actionErrorOK, actionTryAlternatePath); case CREATE_CONTAINER_ACTION: { StorageFile file = privGetFileName( actionIdentity, false, false, false); try { if (file.exists()) { // note I'm left in the no-identity state as fillInIdentity() // hasn't been called. throw StandardException.newException( SQLState.FILE_EXISTS, file); } } catch (SecurityException se) { throw StandardException.newException( SQLState.FILE_CREATE, se, file); } try { // OK not to force WAL here, in fact, this operation preceeds the // creation of the log record to ensure sufficient space. dataFactory.writeInProgress(); try { fileData = file.getRandomAccessFile( "rw"); } finally { dataFactory.writeFinished(); } // This container format specifies that the first page is an // allocation page and the container information is stored within // it. The allocation page needs to be somewhat formatted // because if the system crashed after the create container log // operation is written, it needs to be well formed enough to get // the container information back out of it. // // Don't try to go thru the page cache here because the container // object cannot be found in the container cache at this point // yet. However, if we use the page cache to store the first // allocation page, then in order to write itself out, it needs to // ask the container to do so, which is going to create a // deadlock. The allocation page cannot write itself out without // going thru the container because it doesn't know where its // offset is. Here we effectively hardwired page 0 at offset 0 of // the container file to be the first allocation page. // create an embryonic page - if this is not a temporary container, // synchronously write out the file header. writeRAFHeader(fileData, true, (actionIdentity.getSegmentId() != ContainerHandle.TEMPORARY_SEGMENT)); } catch (SecurityException se) { // only thrown by the RandomeAccessFile constructor, // so the file won't exist throw StandardException.newException( SQLState.FILE_CREATE, se, file); } catch (IOException ioe) { boolean fileDeleted; try { fileDeleted = privRemoveFile(file); } catch (SecurityException se) { throw StandardException.newException( SQLState.FILE_CREATE_NO_CLEANUP, ioe, file, se); } if (!fileDeleted) { throw StandardException.newException( SQLState.FILE_CREATE_NO_CLEANUP, ioe, file, null); } throw StandardException.newException( SQLState.FILE_CREATE, ioe, file); } canUpdate = true; return null; } // end of case CREATE_CONTAINER_ACTION case REMOVE_FILE_ACTION: return privRemoveFile( actionFile) ? this : null; case OPEN_CONTAINER_ACTION: { boolean isStub = false; // is this a stub? StorageFile file = privGetFileName( actionIdentity, false, true, true); if (file == null) return null; try { if (!file.exists()) { // file does not exist, may be it has been stubbified file = privGetFileName( actionIdentity, true, true, true); if (!file.exists()) return null; isStub = true; } } catch (SecurityException se) { throw StandardException.newException( SQLState.DATA_UNEXPECTED_EXCEPTION, se); } canUpdate = false; try { if (!dataFactory.isReadOnly() && file.canWrite()) canUpdate = true; } catch (SecurityException se) { // just means we can't write to it. } try { fileData = file.getRandomAccessFile(canUpdate ? "rw" : "r"); fileData.seek(FIRST_ALLOC_PAGE_OFFSET); readHeader(fileData); if (SanityManager.DEBUG) { if (isStub) SanityManager.ASSERT(getDroppedState() && getCommittedDropState(), "a stub failed to set drop state"); } } catch (IOException ioe) { if (isStub) { throw dataFactory.markCorrupt( StandardException.newException( SQLState.FILE_CONTAINER_EXCEPTION, ioe, this, ioe)); } // maybe it is being stubbified... try that StorageFile stub = privGetFileName( actionIdentity, true, true, true); if (stub.exists()) { try { if (SanityManager.DEBUG) SanityManager.DEBUG_PRINT("RAFContainer", "removing file because we opened it while it is being stubbified"); privRemoveFile(file); fileData = stub.getRandomAccessFile(canUpdate ? "rw" : "r"); readHeader(fileData); } catch (IOException ioe2) { throw dataFactory.markCorrupt( StandardException.newException( SQLState.FILE_CONTAINER_EXCEPTION, ioe2, this, ioe2)); } // RESOLVE: this is a temporary hack } else throw dataFactory.markCorrupt( StandardException.newException( SQLState.FILE_CONTAINER_EXCEPTION, ioe, this, ioe)); } return this; } // end of case OPEN_CONTAINER_ACTION case STUBBIFY_ACTION: { StorageFile file = privGetFileName( actionIdentity, false, false, true); StorageFile stub = privGetFileName( actionIdentity, true, false, false); StorageRandomAccessFile stubData = null; try { // !!!!! // bumpContainerVersion(); // // do NOT bump the container version. We WANT the stubbify // operation to get redone every time. This is because this // operation first writes out the stub and then remove the // container file. If we bump the version, then the stub will // contain the new version. And if the system crashes right then, // then we will skip the whole operation during redo even though // the container file may not have been removed. Since we don't // want to have the remove happen before the stub is written, we // cannot sync it and therefore cannot be sure the remove // happened before the system crashed. if (!stub.exists()) { // write the header to the stub stubData = stub.getRandomAccessFile( "rw"); writeRAFHeader(stubData, true, /* create */ true); /* sync */ stubData.close(); stubData = null; } // Force WAL and check for database corruption before removing file. // This is one operation where the container is changed on disk // directly without going thru the container cache, which otherwise // would have force WAL. Take care of it here. dataFactory.flush(actionInstant); // try to remove the container file // fileDate is not null only if we are redoing a removeContainer // (stubbify) operation. Then fileData acutally is opened against // the stub and the original container file does not exist. // Then we need to close it here because this method is called by // cache.remove and nobody will be able to see fileData after this. privRemoveFile(file); } catch (SecurityException se) { throw StandardException.newException( SQLState.FILE_CANNOT_REMOVE_FILE, se, file, se); } catch (IOException ioe) { // exception thrown while in creating the stub. Remove the // (half-baked) stub try { if (stubData != null) { stubData.close(); stub.delete(); stubData = null; } if (fileData != null) { fileData.close(); fileData = null; } } catch (IOException ioe2) { throw StandardException.newException( SQLState.FILE_CANNOT_REMOVE_FILE, ioe2, file, ioe); } catch (SecurityException se) { throw StandardException.newException( SQLState.FILE_CANNOT_REMOVE_FILE, se, file, stub); } } //let the data factory know about this the stub file;It // could remove when next checkpoint occurs if it's not necessary for recovery dataFactory.stubFileToRemoveAfterCheckPoint(stub,actionInstant, getIdentity()); return null; } // end of case STUBBIFY_ACTION } return null; } // end of run}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -