예제 #1
0
 int allocate(BitField exclude, int first) {
   if (this.full) {
     return -1;
   }
   int start = Math.max(0, first - getPos());
   for (; ; ) {
     int free = this.used.nextClearBit(start);
     if (free >= this.pageCount) {
       if (start == 0) {
         this.full = true;
       }
       return -1;
     }
     if ((exclude != null) && (exclude.get(free + getPos()))) {
       start = exclude.nextClearBit(free + getPos()) - getPos();
       if (start >= this.pageCount) {
         return -1;
       }
     } else {
       this.used.set(free);
       this.store.logUndo(this, this.data);
       this.store.update(this);
       return free + getPos();
     }
   }
 }
 /**
  * Allocate a page from the free list.
  *
  * @param exclude the exclude list or null
  * @param first the first page to look for
  * @return the page, or -1 if all pages are used
  */
 int allocate(BitField exclude, int first) {
   if (full) {
     return -1;
   }
   // TODO cache last result
   int start = Math.max(0, first - getPos());
   while (true) {
     int free = used.nextClearBit(start);
     if (free >= pageCount) {
       if (start == 0) {
         full = true;
       }
       return -1;
     }
     if (exclude != null && exclude.get(free + getPos())) {
       start = exclude.nextClearBit(free + getPos()) - getPos();
       if (start >= pageCount) {
         return -1;
       }
     } else {
       // set the bit first, because logUndo can
       // allocate other pages, and we must not
       // return the same page twice
       used.set(free);
       store.logUndo(this, data);
       store.update(this);
       return free + getPos();
     }
   }
 }
 /**
  * Mark a page as used.
  *
  * @param pageId the page id
  * @return the page id, or -1
  */
 int allocate(int pageId) {
   int idx = pageId - getPos();
   if (idx >= 0 && !used.get(idx)) {
     // set the bit first, because logUndo can
     // allocate other pages, and we must not
     // return the same page twice
     used.set(idx);
     store.logUndo(this, data);
     store.update(this);
   }
   return pageId;
 }
 private PageFreeList(PageStore store, int pageId) {
   // kept in cache, and array list in page store
   setPos(pageId);
   this.store = store;
   pageCount = (store.getPageSize() - DATA_START) * 8;
   used = new BitField(pageCount);
   used.set(0);
 }
 @Override
 public void write() {
   data = store.createData();
   data.writeByte((byte) Page.TYPE_FREE_LIST);
   data.writeShortInt(0);
   for (int i = 0; i < pageCount; i += 8) {
     data.writeByte((byte) used.getByte(i));
   }
   store.writePage(getPos(), data);
 }
 /** Read the page from the disk. */
 private void read() {
   data.reset();
   data.readByte();
   data.readShortInt();
   for (int i = 0; i < pageCount; i += 8) {
     int x = data.readByte() & 255;
     used.setByte(i, x);
   }
   full = false;
 }
 private void checkRegistered(int parameterIndex) throws SQLException {
   try {
     checkIndexBounds(parameterIndex);
     if (!outParameters.get(parameterIndex - 1)) {
       throw DbException.getInvalidValueException("parameterIndex", parameterIndex);
     }
   } catch (Exception e) {
     throw logAndConvert(e);
   }
 }
 /**
  * Get the first free page starting at the given offset.
  *
  * @param first the page number to start the search
  * @return the page number, or -1
  */
 int getFirstFree(int first) {
   if (full) {
     return -1;
   }
   int start = Math.max(0, first - getPos());
   int free = used.nextClearBit(start);
   if (free >= pageCount) {
     return -1;
   }
   return free + getPos();
 }
예제 #9
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);
 }
 private void registerOutParameter(int parameterIndex) throws SQLException {
   try {
     checkClosed();
     if (outParameters == null) {
       maxOutParameters =
           Math.min(
               getParameterMetaData().getParameterCount(), getCheckedMetaData().getColumnCount());
       outParameters = new BitField();
     }
     checkIndexBounds(parameterIndex);
     ParameterInterface param = command.getParameters().get(--parameterIndex);
     if (!param.isValueSet()) {
       param.setValue(ValueNull.INSTANCE, false);
     }
     outParameters.set(parameterIndex);
   } catch (Exception e) {
     throw logAndConvert(e);
   }
 }
예제 #11
0
 /**
  * Check if the undo entry was already written for the given page.
  *
  * @param pageId the page
  * @return true if it was written
  */
 boolean getUndo(int pageId) {
   return undo.get(pageId);
 }
예제 #12
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;
 }
 /**
  * Check if a page is already in use.
  *
  * @param pageId the page to check
  * @return true if it is in use
  */
 boolean isUsed(int pageId) {
   return used.get(pageId - getPos());
 }
 /**
  * Add a page to the free list.
  *
  * @param pageId the page id to add
  */
 void free(int pageId) {
   full = false;
   store.logUndo(this, data);
   used.clear(pageId - getPos());
   store.update(this);
 }
 int getLastUsed() {
   int last = used.length() - 1;
   return last <= 0 ? -1 : last + getPos();
 }