示例#1
0
 /**
  * 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();
   }
 }
示例#2
0
 @Override
 public void close() {
   RuntimeException closeError = null;
   if (transferList != null) {
     synchronized (this) {
       for (Transfer transfer : transferList) {
         try {
           traceOperation("SESSION_CLOSE", 0);
           transfer.writeInt(SessionRemote.SESSION_CLOSE);
           done(transfer);
           transfer.close();
         } catch (RuntimeException e) {
           trace.error(e, "close");
           closeError = e;
         } catch (Exception e) {
           trace.error(e, "close");
         }
       }
     }
     transferList = null;
   }
   traceSystem.close();
   if (embedded != null) {
     embedded.close();
     embedded = null;
   }
   if (closeError != null) {
     throw closeError;
   }
 }
示例#3
0
 /**
  * A table is truncated.
  *
  * @param session the session
  * @param tableId the table id
  */
 void logTruncate(Session session, int tableId) {
   if (trace.isDebugEnabled()) {
     trace.debug("log truncate s: " + session.getId() + " table: " + tableId);
   }
   session.addLogPos(logSectionId, logPos);
   logPos++;
   Data buffer = getBuffer();
   buffer.writeByte((byte) TRUNCATE);
   buffer.writeVarInt(session.getId());
   buffer.writeVarInt(tableId);
   write(buffer);
 }
示例#4
0
 private void freeLogPages(IntArray pages) {
   if (trace.isDebugEnabled()) {
     trace.debug("log frees " + pages.get(0) + ".." + pages.get(pages.size() - 1));
   }
   Data buffer = getBuffer();
   buffer.writeByte((byte) FREE_LOG);
   int size = pages.size();
   buffer.writeVarInt(size);
   for (int i = 0; i < size; i++) {
     buffer.writeVarInt(pages.get(i));
   }
   write(buffer);
 }
示例#5
0
 /**
  * Mark a transaction as committed.
  *
  * @param sessionId the session
  */
 void commit(int sessionId) {
   if (trace.isDebugEnabled()) {
     trace.debug("log commit s: " + sessionId);
   }
   if (store.getDatabase().getPageStore() == null) {
     // database already closed
     return;
   }
   Data buffer = getBuffer();
   buffer.writeByte((byte) COMMIT);
   buffer.writeVarInt(sessionId);
   write(buffer);
   if (store.getDatabase().getFlushOnEachCommit()) {
     flush();
   }
 }
示例#6
0
 /** INTERNAL */
 public JdbcConnection(ConnectionInfo ci, boolean useBaseDir) throws SQLException {
   try {
     if (useBaseDir) {
       String baseDir = SysProperties.getBaseDir();
       if (baseDir != null) {
         ci.setBaseDir(baseDir);
       }
     }
     checkJavaVersion();
     // this will return an embedded or server connection
     session = new SessionRemote().createSession(ci);
     trace = session.getTrace();
     int id = getNextId(TraceObject.CONNECTION);
     setTrace(trace, TraceObject.CONNECTION, id);
     this.user = ci.getUserName();
     if (isInfoEnabled()) {
       trace.infoCode(
           "Connection "
               + getTraceObjectName()
               + " = DriverManager.getConnection("
               + quote(ci.getOriginalURL())
               + ", "
               + quote(user)
               + ", \"\");");
     }
     this.url = ci.getURL();
     openStackTrace = new Exception("Stack Trace");
   } catch (Exception e) {
     throw logAndConvert(e);
   }
 }
示例#7
0
 /**
  * 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);
   }
 }
示例#8
0
 protected void finalize() {
   if (!SysProperties.runFinalize) {
     return;
   }
   if (isInternal) {
     return;
   }
   if (session != null && openStackTrace != null) {
     trace.error("Connection not closed", openStackTrace);
     try {
       close();
     } catch (SQLException e) {
       trace.debug("finalize", e);
     }
   }
 }
示例#9
0
 /** Close without further writing. */
 void close() {
   trace.debug("log close");
   if (pageOut != null) {
     pageOut.close();
     pageOut = null;
   }
   writeBuffer = null;
 }
示例#10
0
 /**
  * A record is added to a table, or removed from a table.
  *
  * @param session the session
  * @param tableId the table id
  * @param row the row to add
  * @param add true if the row is added, false if it is removed
  */
 void logAddOrRemoveRow(Session session, int tableId, Row row, boolean add) {
   if (trace.isDebugEnabled()) {
     trace.debug(
         "log "
             + (add ? "+" : "-")
             + " s: "
             + session.getId()
             + " table: "
             + tableId
             + " row: "
             + row);
   }
   session.addLogPos(logSectionId, logPos);
   logPos++;
   Data data = dataBuffer;
   data.reset();
   int columns = row.getColumnCount();
   data.writeVarInt(columns);
   data.checkCapacity(row.getByteCount(data));
   if (session.isRedoLogBinaryEnabled()) {
     for (int i = 0; i < columns; i++) {
       data.writeValue(row.getValue(i));
     }
   } else {
     for (int i = 0; i < columns; i++) {
       Value v = row.getValue(i);
       if (v.getType() == Value.BYTES) {
         data.writeValue(ValueNull.INSTANCE);
       } else {
         data.writeValue(v);
       }
     }
   }
   Data buffer = getBuffer();
   buffer.writeByte((byte) (add ? ADD : REMOVE));
   buffer.writeVarInt(session.getId());
   buffer.writeVarInt(tableId);
   buffer.writeVarLong(row.getKey());
   if (add) {
     buffer.writeVarInt(data.length());
     buffer.checkCapacity(data.length());
     buffer.write(data.getBytes(), 0, data.length());
   }
   write(buffer);
 }
示例#11
0
 /**
  * Remove a server from the list of cluster nodes and disables the cluster mode.
  *
  * @param e the exception (used for debugging)
  * @param i the index of the server to remove
  * @param count the retry count index
  */
 public void removeServer(IOException e, int i, int count) {
   trace.debug(e, "removing server because of exception");
   transferList.remove(i);
   if (transferList.size() == 0 && autoReconnect(count)) {
     return;
   }
   checkClosed();
   switchOffCluster();
 }
示例#12
0
 /**
  * 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();
 }
示例#13
0
 /**
  * Add an undo entry to the log. The page data is only written once until the next checkpoint.
  *
  * @param pageId the page id
  * @param page the old page data
  */
 void addUndo(int pageId, Data page) {
   if (undo.get(pageId) || freeing) {
     return;
   }
   if (trace.isDebugEnabled()) {
     trace.debug("log undo " + pageId);
   }
   if (SysProperties.CHECK) {
     if (page == null) {
       DbException.throwInternalError("Undo entry not written");
     }
   }
   undo.set(pageId);
   undoAll.set(pageId);
   Data buffer = getBuffer();
   buffer.writeByte((byte) UNDO);
   buffer.writeVarInt(pageId);
   if (page.getBytes()[0] == 0) {
     buffer.writeVarInt(1);
   } else {
     int pageSize = store.getPageSize();
     if (COMPRESS_UNDO) {
       int size = compress.compress(page.getBytes(), pageSize, compressBuffer, 0);
       if (size < pageSize) {
         buffer.writeVarInt(size);
         buffer.checkCapacity(size);
         buffer.write(compressBuffer, 0, size);
       } else {
         buffer.writeVarInt(0);
         buffer.checkCapacity(pageSize);
         buffer.write(page.getBytes(), 0, pageSize);
       }
     } else {
       buffer.writeVarInt(0);
       buffer.checkCapacity(pageSize);
       buffer.write(page.getBytes(), 0, pageSize);
     }
   }
   write(buffer);
 }
示例#14
0
 /**
  * INTERNAL. Check if this connection is closed.
  *
  * @param write if the next operation is possibly writing
  * @throws SQLException if the connection or session is closed
  */
 protected void checkClosed(boolean write) throws SQLException {
   if (session == null) {
     throw DbException.get(ErrorCode.OBJECT_CLOSED);
   }
   if (session.isClosed()) {
     throw DbException.get(ErrorCode.DATABASE_CALLED_AT_SHUTDOWN);
   }
   if (session.isReconnectNeeded(write)) {
     trace.debug("reconnect");
     closePreparedCommands();
     session = session.reconnect(write);
     setTrace(session.getTrace());
   }
 }
示例#15
0
 /** 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;
   }
 }
示例#16
0
 /**
  * Cancel the statement with the given id.
  *
  * @param id the statement id
  */
 public void cancelStatement(int id) {
   for (Transfer transfer : transferList) {
     try {
       Transfer trans = transfer.openNewConnection();
       trans.init();
       trans.writeInt(clientVersion);
       trans.writeInt(clientVersion);
       trans.writeString(null);
       trans.writeString(null);
       trans.writeString(sessionId);
       trans.writeInt(SessionRemote.SESSION_CANCEL_STATEMENT);
       trans.writeInt(id);
       trans.close();
     } catch (IOException e) {
       trace.debug(e, "could not cancel statement");
     }
   }
 }
示例#17
0
 /** INTERNAL */
 public void setTraceLevel(int level) {
   trace.setLevel(level);
 }
示例#18
0
 /**
  * Write the operation to the trace system if debug trace is enabled.
  *
  * @param operation the operation performed
  * @param id the id of the operation
  */
 public void traceOperation(String operation, int id) {
   if (trace.isDebugEnabled()) {
     trace.debug("{0} {1}", operation, id);
   }
 }
示例#19
0
 /**
  * Run one recovery stage. There are three recovery stages: 0: only the undo steps are run
  * (restoring the state before the last checkpoint). 1: the pages that are used by the transaction
  * log are allocated. 2: the committed operations are re-applied.
  *
  * @param stage the recovery stage
  * @return whether the transaction log was empty
  */
 boolean recover(int stage) {
   if (trace.isDebugEnabled()) {
     trace.debug("log recover stage: " + stage);
   }
   if (stage == RECOVERY_STAGE_ALLOCATE) {
     PageInputStream in = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
     usedLogPages = in.allocateAllPages();
     in.close();
     return true;
   }
   PageInputStream pageIn = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
   DataReader in = new DataReader(pageIn);
   int logId = 0;
   Data data = store.createData();
   boolean isEmpty = true;
   try {
     int pos = 0;
     while (true) {
       int x = in.readByte();
       if (x < 0) {
         break;
       }
       pos++;
       isEmpty = false;
       if (x == UNDO) {
         int pageId = in.readVarInt();
         int size = in.readVarInt();
         if (size == 0) {
           in.readFully(data.getBytes(), store.getPageSize());
         } else if (size == 1) {
           // empty
           Arrays.fill(data.getBytes(), 0, store.getPageSize(), (byte) 0);
         } else {
           in.readFully(compressBuffer, size);
           try {
             compress.expand(compressBuffer, 0, size, data.getBytes(), 0, store.getPageSize());
           } catch (ArrayIndexOutOfBoundsException e) {
             DbException.convertToIOException(e);
           }
         }
         if (stage == RECOVERY_STAGE_UNDO) {
           if (!undo.get(pageId)) {
             if (trace.isDebugEnabled()) {
               trace.debug("log undo {0}", pageId);
             }
             store.writePage(pageId, data);
             undo.set(pageId);
             undoAll.set(pageId);
           } else {
             if (trace.isDebugEnabled()) {
               trace.debug("log undo skip {0}", pageId);
             }
           }
         }
       } else if (x == ADD) {
         int sessionId = in.readVarInt();
         int tableId = in.readVarInt();
         Row row = readRow(in, data);
         if (stage == RECOVERY_STAGE_UNDO) {
           store.allocateIfIndexRoot(pos, tableId, row);
         } else if (stage == RECOVERY_STAGE_REDO) {
           if (isSessionCommitted(sessionId, logId, pos)) {
             if (trace.isDebugEnabled()) {
               trace.debug("log redo + table: " + tableId + " s: " + sessionId + " " + row);
             }
             store.redo(tableId, row, true);
           } else {
             if (trace.isDebugEnabled()) {
               trace.debug("log ignore s: " + sessionId + " + table: " + tableId + " " + row);
             }
           }
         }
       } else if (x == REMOVE) {
         int sessionId = in.readVarInt();
         int tableId = in.readVarInt();
         long key = in.readVarLong();
         if (stage == RECOVERY_STAGE_REDO) {
           if (isSessionCommitted(sessionId, logId, pos)) {
             if (trace.isDebugEnabled()) {
               trace.debug("log redo - table: " + tableId + " s:" + sessionId + " key: " + key);
             }
             store.redoDelete(tableId, key);
           } else {
             if (trace.isDebugEnabled()) {
               trace.debug("log ignore s: " + sessionId + " - table: " + tableId + " " + key);
             }
           }
         }
       } else if (x == TRUNCATE) {
         int sessionId = in.readVarInt();
         int tableId = in.readVarInt();
         if (stage == RECOVERY_STAGE_REDO) {
           if (isSessionCommitted(sessionId, logId, pos)) {
             if (trace.isDebugEnabled()) {
               trace.debug("log redo truncate table: " + tableId);
             }
             store.redoTruncate(tableId);
           } else {
             if (trace.isDebugEnabled()) {
               trace.debug("log ignore s: " + sessionId + " truncate table: " + tableId);
             }
           }
         }
       } else if (x == PREPARE_COMMIT) {
         int sessionId = in.readVarInt();
         String transaction = in.readString();
         if (trace.isDebugEnabled()) {
           trace.debug("log prepare commit " + sessionId + " " + transaction + " pos: " + pos);
         }
         if (stage == RECOVERY_STAGE_UNDO) {
           int page = pageIn.getDataPage();
           setPrepareCommit(sessionId, page, transaction);
         }
       } else if (x == ROLLBACK) {
         int sessionId = in.readVarInt();
         if (trace.isDebugEnabled()) {
           trace.debug("log rollback " + sessionId + " pos: " + pos);
         }
         // ignore - this entry is just informational
       } else if (x == COMMIT) {
         int sessionId = in.readVarInt();
         if (trace.isDebugEnabled()) {
           trace.debug("log commit " + sessionId + " pos: " + pos);
         }
         if (stage == RECOVERY_STAGE_UNDO) {
           setLastCommitForSession(sessionId, logId, pos);
         }
       } else if (x == NOOP) {
         // nothing to do
       } else if (x == CHECKPOINT) {
         logId++;
       } else if (x == FREE_LOG) {
         int count = in.readVarInt();
         for (int i = 0; i < count; i++) {
           int pageId = in.readVarInt();
           if (stage == RECOVERY_STAGE_REDO) {
             if (!usedLogPages.get(pageId)) {
               store.free(pageId, false);
             }
           }
         }
       } else {
         if (trace.isDebugEnabled()) {
           trace.debug("log end");
           break;
         }
       }
     }
   } catch (DbException e) {
     if (e.getErrorCode() == ErrorCode.FILE_CORRUPTED_1) {
       trace.debug("log recovery stopped");
     } else {
       throw e;
     }
   } catch (IOException e) {
     trace.debug("log recovery completed");
   }
   undo = new BitField();
   if (stage == RECOVERY_STAGE_REDO) {
     usedLogPages = null;
   }
   return isEmpty;
 }