/** * Prepare a transaction. * * @param session the session * @param transaction the name of the transaction */ void prepareCommit(Session session, String transaction) { if (trace.isDebugEnabled()) { trace.debug("log prepare commit s: " + session.getId() + ", " + transaction); } if (store.getDatabase().getPageStore() == null) { // database already closed return; } // store it on a separate log page int pageSize = store.getPageSize(); pageOut.flush(); pageOut.fillPage(); Data buffer = getBuffer(); buffer.writeByte((byte) PREPARE_COMMIT); buffer.writeVarInt(session.getId()); buffer.writeString(transaction); if (buffer.length() >= PageStreamData.getCapacity(pageSize)) { throw DbException.getInvalidValueException("transaction name (too long)", transaction); } write(buffer); // store it on a separate log page flushOut(); pageOut.fillPage(); if (store.getDatabase().getFlushOnEachCommit()) { flush(); } }
/** * Open the log for writing. For an existing database, the recovery must be run first. * * @param newFirstTrunkPage the first trunk page * @param atEnd whether only pages at the end of the file should be used */ void openForWriting(int newFirstTrunkPage, boolean atEnd) { trace.debug("log openForWriting firstPage: " + newFirstTrunkPage); this.firstTrunkPage = newFirstTrunkPage; logKey++; pageOut = new PageOutputStream(store, newFirstTrunkPage, undoAll, logKey, atEnd); pageOut.reserve(1); // pageBuffer = new BufferedOutputStream(pageOut, 8 * 1024); store.setLogFirstPage(logKey, newFirstTrunkPage, pageOut.getCurrentDataPageId()); writeBuffer = store.createData(); }
/** Switch to a new log section. */ void checkpoint() { Data buffer = getBuffer(); buffer.writeByte((byte) CHECKPOINT); write(buffer); undo = new BitField(); logSectionId++; logPos = 0; pageOut.flush(); pageOut.fillPage(); int currentDataPage = pageOut.getCurrentDataPageId(); logSectionPageMap.put(logSectionId, currentDataPage); }
/** * Remove all pages until the given data page. * * @param trunkPage the first trunk page * @param firstDataPageToKeep the first data page to keep * @return the trunk page of the data page to keep */ private int removeUntil(int trunkPage, int firstDataPageToKeep) { trace.debug("log.removeUntil " + trunkPage + " " + firstDataPageToKeep); int last = trunkPage; while (true) { Page p = store.getPage(trunkPage); PageStreamTrunk t = (PageStreamTrunk) p; if (t == null) { throw DbException.throwInternalError( "log.removeUntil not found: " + firstDataPageToKeep + " last " + last); } logKey = t.getLogKey(); last = t.getPos(); if (t.contains(firstDataPageToKeep)) { return last; } trunkPage = t.getNextTrunk(); IntArray list = new IntArray(); list.add(t.getPos()); for (int i = 0; ; i++) { int next = t.getPageData(i); if (next == -1) { break; } list.add(next); } freeLogPages(list); pageOut.free(t); } }
/** Close without further writing. */ void close() { trace.debug("log close"); if (pageOut != null) { pageOut.close(); pageOut = null; } writeBuffer = null; }
/** Free up all pages allocated by the log. */ void free() { if (trace.isDebugEnabled()) { trace.debug("log free"); } int currentDataPage = 0; if (pageOut != null) { currentDataPage = pageOut.getCurrentDataPageId(); pageOut.freeReserved(); } try { freeing = true; int first = 0; int loopDetect = 1024, loopCount = 0; PageStreamTrunk.Iterator it = new PageStreamTrunk.Iterator(store, firstTrunkPage); while (firstTrunkPage != 0 && firstTrunkPage < store.getPageCount()) { PageStreamTrunk t = it.next(); if (t == null) { if (it.canDelete()) { store.free(firstTrunkPage, false); } break; } if (loopCount++ >= loopDetect) { first = t.getPos(); loopCount = 0; loopDetect *= 2; } else if (first != 0 && first == t.getPos()) { throw DbException.throwInternalError("endless loop at " + t); } t.free(currentDataPage); firstTrunkPage = t.getNextTrunk(); } } finally { freeing = false; } }
/** * Get the smallest possible page id used. This is the trunk page if only appending at the end of * the file, or 0. * * @return the smallest possible page. */ int getMinPageId() { return pageOut == null ? 0 : pageOut.getMinPageId(); }
private void flushOut() { pageOut.flush(); }
long getSize() { return pageOut == null ? 0 : pageOut.getSize(); }
private void write(Data data) { pageOut.write(data.getBytes(), 0, data.length()); data.reset(); }