Finally, we compare AspectJ and IIIA on a concrete feature from Berkeley DB. First we directly compare the original AspectJ implementation (left column) with an IIIA implementation (right column). Additionally, we show how we had to prepare the source code for the IIIA solution below. The main differences are highlighted.
The complete IIIA implementation can be downloaded here. The AspectJ implementation is available as part of the refactored Berkeley DB project here.
Checksum-Feature in AspectJ |
Checksum-Feature in IIIA |
---|---|
public privileged aspect ChecksumValidatorAspect { |
aspect Checksum advises LogManagerInitializationJP, ValidateHeaderJP, ValidateBodyJP, LogManagerStaticInitJP, FileReaderInitializationJP, FileReaderValidateChecksumJP, FileReaderDeterminIsCollectDataJP, FileReaderReadHeaderJP, FileReaderStartChecksumJP { |
after(LogManager logManager, EnvironmentImpl env) throws DatabaseException : execution(LogManager.new(EnvironmentImpl, boolean)) && this(logManager) && args(env,boolean) { /* See if we're configured to do a checksum when reading in objects. */ DbConfigManager configManager = env.getConfigManager(); logManager.doChecksumOnRead = configManager .getBoolean(EnvironmentParams.LOG_CHECKSUM_READ); } private ChecksumValidator validator = null; after(LogManager lm, ByteBuffer entryBuffer, EntryHeader entryHeader) throws DatabaseException : call(void EntryHeader.readHeader(ByteBuffer, boolean)) && this(lm) && args(entryBuffer,boolean) && target(entryHeader) { if (lm.doChecksumOnRead) { validator = new ChecksumValidator(); int oldpos = entryBuffer.position(); entryBuffer.position(oldpos - LogManager.HEADER_CONTENT_BYTES); validator.update(lm.envImpl, entryBuffer, LogManager.HEADER_CONTENT_BYTES, false); entryBuffer.position(oldpos); } } private pointcut getLogEntryFromLogSource(long lsn) : execution(LogEntry LogManager.getLogEntryFromLogSource(long,LogSource)) && args(lsn,LogSource); after(LogManager lm, ByteBuffer entryBuffer, EntryHeader entryHeader, long lsn) throws DatabaseException : call(ByteBuffer LogManager.getRemainingBuffer(ByteBuffer, LogSource, long, EntryHeader)) && target(lm) && args(entryBuffer, LogSource, long, entryHeader) && cflow(getLogEntryFromLogSource(lsn)) { if (lm.doChecksumOnRead) { /* Check the checksum first. */ validator.update(lm.envImpl, entryBuffer, entryHeader .getEntrySize(), false); validator.validate(lm.envImpl, entryHeader.getChecksum(), lsn); } } public boolean LogManager.doChecksumOnRead; public boolean LogManager.getChecksumOnRead() { return doChecksumOnRead; } | after(LogManagerInitializationJP l) { /* See if we're configured to do a checksum when reading in objects. */ DbConfigManager configManager = l.env.getConfigManager(); l._this.doChecksumOnRead = configManager .getBoolean(EnvironmentParams.LOG_CHECKSUM_READ); } private ChecksumValidator validator; private long storedChecksum; after(ValidateHeaderJP l) throws DatabaseException { validator = null; storedChecksum = LogUtils.getUnsignedInt(l.entryBuffer); if (l._this.doChecksumOnRead) { validator = new ChecksumValidator(); validator.update(l._this.envImpl, l.entryBuffer, LogManager.HEADER_CONTENT_BYTES, false); } } after(ValidateBodyJP l) throws DatabaseException { if (l._this.doChecksumOnRead) { /* Check the checksum first. */ validator.update(l._this.envImpl, l.entryBuffer, l.itemSize, false); validator.validate(l._this.envImpl, storedChecksum, l.lsn); } } public boolean LogManager.doChecksumOnRead; public boolean LogManager.getChecksumOnRead() { return doChecksumOnRead; } |
static final int LogManager.CHECKSUM_BYTES = 4; // size of checksum field static final int LogManager.HEADER_CHECKSUM_OFFSET = 0; // size of checksum // field after(): staticinitialization(LogManager) { LogManager.HEADER_BYTES += LogManager.CHECKSUM_BYTES; // size of entry // header LogManager.PREV_BYTES = 4; // size of previous field LogManager.HEADER_CONTENT_BYTES = LogManager.HEADER_BYTES - LogManager.CHECKSUM_BYTES; LogManager.HEADER_ENTRY_TYPE_OFFSET += 4; LogManager.HEADER_VERSION_OFFSET += 4; LogManager.HEADER_PREV_OFFSET += 4; LogManager.HEADER_SIZE_OFFSET += 4; } | static final int LogManager.CHECKSUM_BYTES = 4; // size of checksum field static final int LogManager.HEADER_CHECKSUM_OFFSET = 0; // size of checksum // field after(LogManagerStaticInitJP j) { LogManager.HEADER_BYTES += LogManager.CHECKSUM_BYTES; // size of entry // header LogManager.PREV_BYTES = 4; // size of previous field LogManager.HEADER_CONTENT_BYTES = LogManager.HEADER_BYTES - LogManager.CHECKSUM_BYTES; LogManager.HEADER_ENTRY_TYPE_OFFSET += 4; LogManager.HEADER_VERSION_OFFSET += 4; LogManager.HEADER_PREV_OFFSET += 4; LogManager.HEADER_SIZE_OFFSET += 4; } |
Object around(FileReader fileReader, EnvironmentImpl env) throws DatabaseException : execution(FileReader.new(EnvironmentImpl, int, boolean, long, Long, long,long)) && args(env,int, boolean, long, Long, long,long) && this(fileReader) && within(FileReader) { fileReader.doValidateChecksum = env.getLogManager(). getChecksumOnRead(); Object r = proceed(fileReader, env); if (fileReader.doValidateChecksum) { fileReader.cksumValidator = new ChecksumValidator(); } fileReader.anticipateChecksumErrors = false; return r; } after(FileReader fileReader, ByteBuffer dataBuffer) throws DatabaseException : call(void FileReader.hook_startChecksumValidation(ByteBuffer)) && target(fileReader) && args(dataBuffer){ boolean doValidate = fileReader.doValidateChecksum && (fileReader.alwaysValidateChecksum || fileReader .isTargetEntry(fileReader.currentEntryTypeNum, fileReader.currentEntryTypeVersion)); if (doValidate) { fileReader.startChecksum(dataBuffer); } if (doValidate) fileReader.currentEntryCollectData = true; } after(FileReader fileReader, ByteBuffer dataBuffer) throws DatabaseException : call(void FileReader.hook_checksumValidation(ByteBuffer)) && target(fileReader) && args(dataBuffer){ boolean doValidate = fileReader.doValidateChecksum && (fileReader.alwaysValidateChecksum || fileReader .isTargetEntry(fileReader.currentEntryTypeNum, fileReader.currentEntryTypeVersion)); if (doValidate) { fileReader.validateChecksum(dataBuffer); } } before(ByteBuffer dataBuffer, FileReader fileReader): execution(void FileReader.readHeader(ByteBuffer)) && args(dataBuffer) && target(fileReader) { /* Get the checksum for this log entry. */ fileReader.currentEntryChecksum = LogUtils.getUnsignedInt (dataBuffer); } | before(FileReaderInitializationJP j) throws DatabaseException { j._this.doValidateChecksum = j.env.getLogManager(). getChecksumOnRead(); } after(FileReaderInitializationJP j) { if (j._this.doValidateChecksum) { j._this.cksumValidator = new ChecksumValidator(); } j._this.anticipateChecksumErrors = false; } boolean around(FileReaderDeterminIsCollectDataJP j) { return proceed() || j._this.doValidateChecksum && j._this.alwaysValidateChecksum; } before(FileReaderStartChecksumJP j) throws DatabaseException { boolean doValidate = j._this.doValidateChecksum && (j.isTargetEntry || j._this.alwaysValidateChecksum); if (doValidate) { j._this.startChecksum(j.dataBuffer); } } before(FileReaderValidateChecksumJP j) throws DatabaseException { boolean doValidate = j._this.doValidateChecksum && (j.isTargetEntry || j._this.alwaysValidateChecksum); if (doValidate) { j._this.validateChecksum(j.dataBuffer); } } before(FileReaderReadHead&&erJP j){ j._this.currentEntryChecksum = LogUtils.getUnsignedInt (j.dataBuffer); } |
public ChecksumValidator FileReader.cksumValidator; public boolean FileReader.doValidateChecksum; public boolean FileReader.alwaysValidateChecksum; public boolean FileReader.anticipateChecksumErrors; public void FileReader.startChecksum(ByteBuffer dataBuffer) throws DatabaseException { cksumValidator.reset(); int entryStart = threadSafeBufferPosition(dataBuffer); System.out.println(dataBuffer); dataBuffer.reset(); cksumValidator.update(env, dataBuffer, LogManager.HEADER_CONTENT_BYTES, anticipateChecksumErrors); threadSafeBufferPosition(dataBuffer, entryStart); } public long FileReader.currentEntryChecksum; public void FileReader.validateChecksum(ByteBuffer entryBuffer) throws DatabaseException { cksumValidator.update(env, entryBuffer, currentEntrySize, anticipateChecksumErrors); cksumValidator.validate(env, currentEntryChecksum, readBufferFileNum, currentEntryOffset, anticipateChecksumErrors); } }//end of aspect | public ChecksumValidator FileReader.cksumValidator; public boolean FileReader.doValidateChecksum; public boolean FileReader.alwaysValidateChecksum; public boolean FileReader.anticipateChecksumErrors; public void FileReader.startChecksum(ByteBuffer dataBuffer) throws DatabaseException { cksumValidator.reset(); int entryStart = threadSafeBufferPosition(dataBuffer); System.out.println(dataBuffer); dataBuffer.reset(); cksumValidator.update(env, dataBuffer, LogManager.HEADER_CONTENT_BYTES, anticipateChecksumErrors); threadSafeBufferPosition(dataBuffer, entryStart); } public long FileReader.currentEntryChecksum; public void FileReader.validateChecksum(ByteBuffer entryBuffer) throws DatabaseException { cksumValidator.update(env, entryBuffer, currentEntrySize, anticipateChecksumErrors); cksumValidator.validate(env, currentEntryChecksum, readBufferFileNum, currentEntryOffset, anticipateChecksumErrors); } }//end of aspect |
Join Point Types in IIIA | |
abstract public joinpointtype ChecksumJP { } abstract public joinpointtype FileReaderChecksumJP extends ChecksumJP { FileReader _this; } public joinpointtype FileReaderDeterminIsCollectDataJP extends FileReaderChecksumJP { } public joinpointtype FileReaderInitializationJP extends FileReaderChecksumJP { EnvironmentImpl env; } public joinpointtype FileReaderReadHeaderJP extends FileReaderChecksumJP { ByteBuffer dataBuffer; } public joinpointtype FileReaderStartChecksumJP extends FileReaderChecksumJP { boolean isTargetEntry; ByteBuffer dataBuffer; } public joinpointtype FileReaderValidateChecksumJP extends FileReaderChecksumJP { boolean isTargetEntry; ByteBuffer dataBuffer; } abstract public joinpointtype LogManagerChecksumJP extends ChecksumJP { LogManager _this; } public joinpointtype LogManagerInitializationJP extends LogManagerChecksumJP { EnvironmentImpl env; } public joinpointtype LogManagerStaticInitJP extends ChecksumJP { } public joinpointtype ValidateBodyJP extends LogManagerChecksumJP { ByteBuffer entryBuffer; int itemSize; long lsn; } public joinpointtype ValidateHeaderJP extends LogManagerChecksumJP { ByteBuffer entryBuffer; } | |
LogManager in AspectJ (excerpt) | LogManager in IIIA (excerpt) |
public class FileReader { public FileReader(EnvironmentImpl env, int readBufferSize, boolean forward, long startLsn, Long singleFileNumber, long endOfFileLsn, long finishLsn) throws IOException, DatabaseException { this.env = env; this.fileManager = env.getFileManager(); //... } public boolean readNextEntry() throws DatabaseException, IOException { boolean foundEntry = false; try { while ((!eof) && (!foundEntry)) { ByteBuffer dataBuffer = readData(LogManager.HEADER_BYTES, true); readHeader(dataBuffer); boolean isTargetEntry = isTargetEntry(currentEntryTypeNum, currentEntryTypeVersion); currentEntryCollectData = isTargetEntry; hook_startChecksumValidation(dataBuffer); dataBuffer = readData(currentEntrySize, currentEntryCollectData); dataBuffer.mark(); if (forward) { currentEntryOffset = nextEntryOffset; nextEntryOffset += LogManager.HEADER_BYTES + currentEntrySize; } hook_checksumValidation(dataBuffer); if (isTargetEntry) { if (processEntry(dataBuffer)) { foundEntry = true; nRead++; } } else if (currentEntryCollectData) { threadSafeBufferPosition(dataBuffer, threadSafeBufferPosition(dataBuffer) + currentEntrySize); } } } catch (EOFException e) { eof = true; } catch (DatabaseException e) { eof = true; /* Report on error. */ throw e; } return foundEntry; } private void hook_startChecksumValidation(ByteBuffer dataBuffer) throws DatabaseException { } private void hook_checksumValidation(ByteBuffer dataBuffer) throws DatabaseException { } private void readHeader(ByteBuffer dataBuffer) throws DatabaseException { dataBuffer.mark(); currentEntryTypeNum = dataBuffer.get(); currentEntryTypeVersion = dataBuffer.get(); currentEntryPrevOffset = LogUtils.getUnsignedInt(dataBuffer); currentEntrySize = LogUtils.readInt(dataBuffer); } | public class FileReader exhibits FileReaderInitializationJP, FileReaderValidateChecksumJP, FileReaderDeterminIsCollectDataJP, FileReaderReadHeaderJP, FileReaderStartChecksumJP { pointcut FileReaderInitializationJP : execution(new(..)) && this(_this) && args(env,..); public FileReader(EnvironmentImpl env, int readBufferSize, boolean forward, long startLsn, Long singleFileNumber, long endOfFileLsn, long finishLsn) throws IOException, DatabaseException { this.env = env; this.fileManager = env.getFileManager(); //... } public boolean readNextEntry() throws DatabaseException, IOException { boolean foundEntry = false; try { while ((!eof) && (!foundEntry)) { ByteBuffer dataBuffer = readData(LogManager.HEADER_BYTES, true); readHeader(dataBuffer); boolean isTargetEntry = isTargetEntry(currentEntryTypeNum, currentEntryTypeVersion); boolean collectData = hook_isCollectData(isTargetEntry); exhibit new FileReaderStartChecksumJP(this,isTargetEntry,dataBuffer){}; dataBuffer = readData(currentEntrySize, collectData); if (forward) { currentEntryOffset = nextEntryOffset; nextEntryOffset += LogManager.HEADER_BYTES + currentEntrySize; } exhibit new FileReaderValidateChecksumJP(this,isTargetEntry,dataBuffer){}; if (isTargetEntry) { if (processEntry(dataBuffer)) { foundEntry = true; nRead++; } } else if (collectData) { threadSafeBufferPosition(dataBuffer, threadSafeBufferPosition(dataBuffer) + currentEntrySize); } } } catch (EOFException e) { eof = true; } catch (DatabaseException e) { eof = true; /* Report on error. */ throw e; } return foundEntry; } pointcut FileReaderDeterminIsCollectDataJP : execution(boolean hook_isCollectData(..)) && this(_this); public boolean hook_isCollectData(boolean isTargetEntry) { return isTargetEntry; } pointcut FileReaderReadHeaderJP : execution(void readHeader(ByteBuffer)) && args(dataBuffer) && this(_this); private void readHeader(ByteBuffer dataBuffer) throws DatabaseException { dataBuffer.mark(); currentEntryTypeNum = dataBuffer.get(); currentEntryTypeVersion = dataBuffer.get(); currentEntryPrevOffset = LogUtils.getUnsignedInt(dataBuffer); currentEntrySize = dataBuffer.getInt(); } //... } |
Back to main page