예제 #1
0
  private long readHeader(int id) throws IOException {
    long header = p_alloc(MINIMUM_PAGE_SIZE);

    try {
      try {
        mPageArray.readPage(id, header, 0, MINIMUM_PAGE_SIZE);
      } catch (EOFException e) {
        throw new CorruptDatabaseException("File is smaller than expected");
      }

      long magic = p_longGetLE(header, I_MAGIC_NUMBER);
      if (magic != MAGIC_NUMBER) {
        throw new CorruptDatabaseException("Wrong magic number: " + magic);
      }

      int checksum = p_intGetLE(header, I_CHECKSUM);

      int newChecksum = setHeaderChecksum(header);
      if (newChecksum != checksum) {
        throw new CorruptDatabaseException(
            "Header checksum mismatch: " + newChecksum + " != " + checksum);
      }

      return header;
    } catch (Throwable e) {
      p_delete(header);
      throw e;
    }
  }
예제 #2
0
 /** @see _SnapshotPageArray#beginSnapshot */
 Snapshot beginSnapshot(_LocalDatabase db) throws IOException {
   mHeaderLatch.acquireShared();
   try {
     long pageCount, redoPos;
     long header = p_alloc(MINIMUM_PAGE_SIZE);
     try {
       mPageArray.readPage(mCommitNumber & 1, header, 0, MINIMUM_PAGE_SIZE);
       pageCount = _PageManager.readTotalPageCount(header, I_MANAGER_HEADER);
       redoPos = _LocalDatabase.readRedoPosition(header, I_EXTRA_DATA);
     } finally {
       p_delete(header);
     }
     return mPageArray.beginSnapshot(db, pageCount, redoPos);
   } finally {
     mHeaderLatch.releaseShared();
   }
 }
예제 #3
0
 @Override
 public void readPage(long id, long page) throws IOException {
   try {
     mPageArray.readPage(id, page, 0, pageSize());
   } catch (Throwable e) {
     throw closeOnFailure(e);
   }
 }
예제 #4
0
 private void readPartial(long index, int start, byte[] buf, int offset, int length)
     throws IOException {
   long page = p_alloc(start + length);
   try {
     mPageArray.readPage(index, page, 0, start + length);
     p_copyToArray(page, start, buf, offset, length);
   } finally {
     p_delete(page);
   }
 }
예제 #5
0
 @Override
 public void deletePage(long id) throws IOException {
   checkId(id);
   CommitLock.Shared shared = mCommitLock.acquireShared();
   try {
     mPageManager.deletePage(id);
   } catch (IOException e) {
     throw e;
   } catch (Throwable e) {
     throw closeOnFailure(e);
   } finally {
     shared.release();
   }
   mPageArray.uncachePage(id);
 }
예제 #6
0
 @Override
 public void close(Throwable cause) throws IOException {
   if (mPageArray != null) {
     mPageArray.close(cause);
   }
 }
예제 #7
0
 @Override
 public long copyPage(long srcId, long dstId) throws IOException {
   return mPageArray.copyPage(srcId, dstId);
 }
예제 #8
0
 @Override
 public long dirtyPage(long id) throws IOException {
   return mPageArray.dirtyPage(id);
 }
예제 #9
0
 @Override
 public long directPagePointer(long id) throws IOException {
   return mPageArray.directPagePointer(id);
 }
예제 #10
0
 @Override
 public void uncachePage(long id) throws IOException {
   mPageArray.uncachePage(id);
 }
예제 #11
0
 @Override
 public void cachePage(long id, long page) throws IOException {
   mPageArray.cachePage(id, page);
 }
예제 #12
0
 @Override
 public long evictPage(long id, long page) throws IOException {
   checkId(id);
   return mPageArray.evictPage(id, page);
 }
예제 #13
0
 @Override
 public void writePage(long id, long page) throws IOException {
   checkId(id);
   mPageArray.writePage(id, page, 0);
 }
예제 #14
0
 @Override
 public long pageCount() throws IOException {
   return mPageArray.getPageCount();
 }
예제 #15
0
 @Override
 public int pageSize() {
   return mPageArray.pageSize();
 }
예제 #16
0
  private _DurablePageDb(
      final PageArray rawArray, final PageCache cache, final Crypto crypto, final boolean destroy)
      throws IOException, WrongPageSize {
    mCrypto = crypto;

    PageArray array = crypto == null ? rawArray : new CryptoPageArray(rawArray, crypto);

    mPageArray = new _SnapshotPageArray(array, rawArray, cache);
    mHeaderLatch = new Latch();

    try {
      int pageSize = mPageArray.pageSize();
      checkPageSize(pageSize);

      if (destroy || mPageArray.isEmpty()) {
        // Newly created file.
        mPageManager = new _PageManager(mPageArray);
        mCommitNumber = -1;

        // Commit twice to ensure both headers have valid data.
        long header = p_calloc(pageSize);
        try {
          mCommitLock.acquireExclusive();
          try {
            commit(false, header, null);
            commit(false, header, null);
          } finally {
            mCommitLock.releaseExclusive();
          }
        } finally {
          p_delete(header);
        }

        mPageArray.setPageCount(2);
      } else {
        // Opened an existing file.

        // Previous header commit operation might have been interrupted before final
        // header sync completed. Pages cannot be safely recycled without this.
        mPageArray.sync(false);

        long header0 = p_null();
        long header1 = p_null();

        try {
          final long header;
          final int commitNumber;
          findHeader:
          {
            int pageSize0;
            int commitNumber0, commitNumber1;
            CorruptDatabaseException ex0;

            try {
              header0 = readHeader(0);
              commitNumber0 = p_intGetLE(header0, I_COMMIT_NUMBER);
              pageSize0 = p_intGetLE(header0, I_PAGE_SIZE);
              ex0 = null;
            } catch (CorruptDatabaseException e) {
              header0 = p_null();
              commitNumber0 = -1;
              pageSize0 = pageSize;
              ex0 = e;
            }

            if (pageSize0 != pageSize) {
              throw new WrongPageSize(pageSize, pageSize0);
            }

            try {
              header1 = readHeader(1);
              commitNumber1 = p_intGetLE(header1, I_COMMIT_NUMBER);
            } catch (CorruptDatabaseException e) {
              if (ex0 != null) {
                // File is completely unusable.
                throw ex0;
              }
              header = header0;
              commitNumber = commitNumber0;
              break findHeader;
            }

            int pageSize1 = p_intGetLE(header1, I_PAGE_SIZE);
            if (pageSize0 != pageSize1) {
              throw new CorruptDatabaseException(
                  "Mismatched page sizes: " + pageSize0 + " != " + pageSize1);
            }

            if (header0 == p_null()) {
              header = header1;
              commitNumber = commitNumber1;
            } else {
              // Modulo comparison.
              int diff = commitNumber1 - commitNumber0;
              if (diff > 0) {
                header = header1;
                commitNumber = commitNumber1;
              } else if (diff < 0) {
                header = header0;
                commitNumber = commitNumber0;
              } else {
                throw new CorruptDatabaseException(
                    "Both headers have same commit number: " + commitNumber0);
              }
            }
          }

          mHeaderLatch.acquireExclusive();
          mCommitNumber = commitNumber;
          mHeaderLatch.releaseExclusive();

          mPageManager = new _PageManager(mPageArray, header, I_MANAGER_HEADER);
        } finally {
          p_delete(header0);
          p_delete(header1);
        }
      }
    } catch (WrongPageSize e) {
      delete();
      closeQuietly(null, this);
      throw e;
    } catch (Throwable e) {
      delete();
      throw closeOnFailure(e);
    }
  }