@Override public void run() { List<Transaction> records = new ArrayList<Transaction>(); if (archivingEnabled == false) { log.info("Archiving has not been enabled"); return; } while (isExit() == false) { records.clear(); buffer.drainTo(records); PrintWriter wf = null; try { FileWriter ff = new FileWriter(filename, true); wf = new PrintWriter(ff); } catch (FileNotFoundException e) { log.error("Should not have happened for [" + filename + "]"); continue; } catch (IOException e) { log.error("Cannot write to [" + filename + "]"); setExit(true); continue; } TransactionLogRecord tlr = new TransactionLogRecord(); for (Transaction t : records) { log.debug("Logging " + t); if (t instanceof ExitTransaction) { setExit(true); continue; } if (t.getDirection().equals(DirectionType.NONE)) { log.error("Transaction [" + t + "] is empty"); continue; } wf.print(tlr.toString(t)); } wf.close(); } log.info("Archiving is ending"); }
/** * 写入事务日志 * * @param tlog * @return * @throws BKException * @throws InterruptedException */ public SyncCounter writeLog(TransactionLogRecord tlog) throws InterruptedException { int recordSize = tlog.calculateTotalRecordSize(); long futureFilePosition = handle.getLength() + recordSize; if (futureFilePosition >= conf.getBtmConf().getMaxLogSizeInMb() * 1024 * 1024) { if (log.isDebugEnabled()) log.debug( "log file is full (size would be: " + futureFilePosition + ", max allowed: " + conf.getBtmConf().getMaxLogSizeInMb() + "Mbs"); return null; } ByteBuffer buf = ByteBuffer.allocate(recordSize); buf.putInt(tlog.getStatus()); buf.putInt(tlog.getRecordLength()); buf.putInt(tlog.getHeaderLength()); buf.putLong(tlog.getTime()); buf.putInt(tlog.getSequenceNumber()); buf.putInt(tlog.getCrc32()); buf.put((byte) tlog.getGtrid().getArray().length); buf.put(tlog.getGtrid().getArray()); Set<String> uniqueNames = tlog.getUniqueNames(); buf.putInt(uniqueNames.size()); for (String uniqueName : uniqueNames) { buf.putShort((short) uniqueName.length()); buf.put(uniqueName.getBytes()); } buf.putInt(tlog.getEndRecord()); byte[] data = buf.array(); SyncCounter counter = new SyncCounter(); counter.inc(); handle.asyncAddEntry(data, new SyncAddCallback(), counter); lastCounter.set(counter); return counter; }
/** * Fetch the next TransactionLogRecord from log. * * @param skipCrcCheck if set to false, the method will thow an InvalidChecksumException if the * CRC on disk does not match the recalculated one. Otherwise, the CRC is not recalculated nor * checked agains the stored one. * @return the TransactionLogRecord or null if the end of the log file has been reached * @throws IOException if an I/O error occurs. */ public TransactionLogRecord readLog(boolean skipCrcCheck) throws IOException { if (currentPosition >= endPosition) { if (log.isDebugEnabled()) log.debug("end of transaction log file reached at " + currentPosition); return null; } final int status = page.getInt(); // currentPosition += 4; final int recordLength = page.getInt(); // currentPosition += 4; currentPosition += 8; if (page.position() + recordLength + 8 > page.limit()) { page.compact(); fileChannel.read(page); page.rewind(); } final int endOfRecordPosition = page.position() + recordLength; if (currentPosition + recordLength > endPosition) { page.position(page.position() + recordLength); currentPosition += recordLength; throw new CorruptedTransactionLogException( "corrupted log found at position " + currentPosition + " (record terminator outside of file bounds: " + currentPosition + recordLength + " of " + endPosition + ", recordLength: " + recordLength + ")"); } final int headerLength = page.getInt(); // currentPosition += 4; final long time = page.getLong(); // currentPosition += 8; final int sequenceNumber = page.getInt(); // currentPosition += 4; final int crc32 = page.getInt(); // currentPosition += 4; final byte gtridSize = page.get(); // currentPosition += 1; currentPosition += 21; // check for log terminator page.mark(); page.position(endOfRecordPosition - 4); int endCode = page.getInt(); page.reset(); if (endCode != TransactionLogAppender.END_RECORD) throw new CorruptedTransactionLogException( "corrupted log found at position " + currentPosition + " (no record terminator found)"); // check that GTRID is not too long if (4 + 8 + 4 + 4 + 1 + gtridSize > recordLength) { page.position(endOfRecordPosition); throw new CorruptedTransactionLogException( "corrupted log found at position " + currentPosition + " (GTRID size too long)"); } final byte[] gtridArray = new byte[gtridSize]; page.get(gtridArray); currentPosition += gtridSize; Uid gtrid = new Uid(gtridArray); final int uniqueNamesCount = page.getInt(); currentPosition += 4; Set<String> uniqueNames = new HashSet<String>(); int currentReadCount = 4 + 8 + 4 + 4 + 1 + gtridSize + 4; for (int i = 0; i < uniqueNamesCount; i++) { int length = page.getShort(); currentPosition += 2; // check that names aren't too long currentReadCount += 2 + length; if (currentReadCount > recordLength) { page.position(endOfRecordPosition); throw new CorruptedTransactionLogException( "corrupted log found at position " + currentPosition + " (unique names too long, " + (i + 1) + " out of " + uniqueNamesCount + ", length: " + length + ", currentReadCount: " + currentReadCount + ", recordLength: " + recordLength + ")"); } byte[] nameBytes = new byte[length]; page.get(nameBytes); currentPosition += length; uniqueNames.add(new String(nameBytes, "US-ASCII")); } final int cEndRecord = page.getInt(); currentPosition += 4; TransactionLogRecord tlog = new TransactionLogRecord( status, recordLength, headerLength, time, sequenceNumber, crc32, gtrid, uniqueNames, cEndRecord); // check that CRC is okay if (!skipCrcCheck && !tlog.isCrc32Correct()) { page.position(endOfRecordPosition); throw new CorruptedTransactionLogException( "corrupted log found at position " + currentPosition + "(invalid CRC, recorded: " + tlog.getCrc32() + ", calculated: " + tlog.calculateCrc32() + ")"); } return tlog; }