public virtual void Backup(System.IO.Stream streamOut) { lock (this) { if (!opened) throw new StorageError(StorageError.STORAGE_NOT_OPENED); objectCache.Flush(); int curr = 1 - currIndex; int nObjects = header.root[curr].indexUsed; long indexOffs = header.root[curr].index; int i, j, k; int nUsedIndexPages = (nObjects + dbHandlesPerPage - 1) / dbHandlesPerPage; int nIndexPages = (int) ((header.root[curr].indexSize + dbHandlesPerPage - 1) / dbHandlesPerPage); long totalRecordsSize = 0; long nPagedObjects = 0; int bitmapExtent = header.root[curr].bitmapExtent; long[] index = new long[nObjects]; int[] oids = new int[nObjects]; if (bitmapExtent == 0) bitmapExtent = Int32.MaxValue; for (i = 0, j = 0; i < nUsedIndexPages; i++) { Page pg = pool.GetPage(indexOffs + (long) i * Page.pageSize); for (k = 0; k < dbHandlesPerPage && j < nObjects; k++, j++) { long pos = Bytes.Unpack8(pg.data, k * 8); index[j] = pos; oids[j] = j; if ((pos & dbFreeHandleFlag) == 0) { if ((pos & dbPageObjectFlag) != 0) { nPagedObjects += 1; } else if (pos != 0) { int offs = (int) pos & (Page.pageSize - 1); Page op = pool.GetPage(pos - offs); int size = ObjectHeader.GetSize(op.data, offs & ~dbFlagsMask); size = (size + dbAllocationQuantum - 1) & ~ (dbAllocationQuantum - 1); totalRecordsSize += size; pool.Unfix(op); } } } pool.Unfix(pg); } Header newHeader = new Header(); newHeader.curr = 0; newHeader.dirty = false; newHeader.initialized = true; long newFileSize = (long) (nPagedObjects + nIndexPages * 2 + 1) * Page.pageSize + totalRecordsSize; newFileSize = (newFileSize + Page.pageSize - 1) & ~ (Page.pageSize - 1); newHeader.root = new RootPage[2]; newHeader.root[0] = new RootPage(); newHeader.root[1] = new RootPage(); newHeader.root[0].size = newHeader.root[1].size = newFileSize; newHeader.root[0].index = newHeader.root[1].shadowIndex = Page.pageSize; newHeader.root[0].shadowIndex = newHeader.root[1].index = Page.pageSize + (long) nIndexPages * Page.pageSize; newHeader.root[0].shadowIndexSize = newHeader.root[0].indexSize = newHeader.root[1].shadowIndexSize = newHeader.root[1].indexSize = nIndexPages * dbHandlesPerPage; newHeader.root[0].indexUsed = newHeader.root[1].indexUsed = nObjects; newHeader.root[0].freeList = newHeader.root[1].freeList = header.root[curr].freeList; newHeader.root[0].bitmapEnd = newHeader.root[1].bitmapEnd = header.root[curr].bitmapEnd; newHeader.root[0].rootObject = newHeader.root[1].rootObject = header.root[curr].rootObject; newHeader.root[0].classDescList = newHeader.root[1].classDescList = header.root[curr].classDescList; newHeader.root[0].bitmapExtent = newHeader.root[1].bitmapExtent = header.root[curr].bitmapExtent; byte[] page = new byte[Page.pageSize]; newHeader.Pack(page); streamOut.Write(page, 0, page.Length); long pageOffs = (long) (nIndexPages * 2 + 1) * Page.pageSize; long recOffs = (long) (nPagedObjects + nIndexPages * 2 + 1) * Page.pageSize; GenericSort.Sort(new AnonymousClassGenericSortArray(nObjects, index, oids, this)); byte[] newIndex = new byte[nIndexPages * dbHandlesPerPage * 8]; for (i = 0; i < nObjects; i++) { long pos = index[i]; int oid = oids[i]; if ((pos & dbFreeHandleFlag) == 0) { if ((pos & dbPageObjectFlag) != 0) { Bytes.Pack8(newIndex, oid * 8, pageOffs | dbPageObjectFlag); pageOffs += Page.pageSize; } else if (pos != 0) { Bytes.Pack8(newIndex, oid * 8, recOffs); int offs = (int) pos & (Page.pageSize - 1); Page op = pool.GetPage(pos - offs); int size = ObjectHeader.GetSize(op.data, offs & ~dbFlagsMask); size = (size + dbAllocationQuantum - 1) & ~ (dbAllocationQuantum - 1); recOffs += size; pool.Unfix(op); } } else { Bytes.Pack8(newIndex, oid * 8, pos); } } streamOut.Write(newIndex, 0, newIndex.Length); streamOut.Write(newIndex, 0, newIndex.Length); for (i = 0; i < nObjects; i++) { long pos = index[i]; if (((int) pos & (dbFreeHandleFlag | dbPageObjectFlag)) == dbPageObjectFlag) { if (oids[i] < dbBitmapId + dbBitmapPages || (oids[i] >= bitmapExtent && oids[i] < bitmapExtent + dbLargeBitmapPages - dbBitmapPages)) { int pageId = oids[i] < dbBitmapId + dbBitmapPages ? oids[i] - dbBitmapId : oids[i] - bitmapExtent; long mappedSpace = (long) pageId * Page.pageSize * 8 * dbAllocationQuantum; if (mappedSpace >= newFileSize) { SupportClass.ArraySupport.Fill(page, 0); } else if (mappedSpace + Page.pageSize * 8 * dbAllocationQuantum <= newFileSize) { SupportClass.ArraySupport.Fill(page, 0xff); } else { int nBits = (int) ((newFileSize - mappedSpace) >> dbAllocationQuantumBits); SupportClass.ArraySupport.Fill(page, 0, nBits >> 3, 0xff); page[nBits >> 3] = (byte) ((1 << (nBits & 7)) - 1); SupportClass.ArraySupport.Fill(page, (nBits >> 3) + 1, Page.pageSize, 0); }; streamOut.Write(page, 0, page.Length); } else { Page pg = pool.GetPage(pos & ~ dbFlagsMask); streamOut.Write(pg.data, 0, pg.data.Length); pool.Unfix(pg); } } } for (i = 0; i < nObjects; i++) { long pos = index[i]; if (pos != 0 && ((int) pos & (dbFreeHandleFlag | dbPageObjectFlag)) == 0) { pos &= ~ dbFlagsMask; int offs = (int) pos & (Page.pageSize - 1); Page pg = pool.GetPage(pos - offs); int size = ObjectHeader.GetSize(pg.data, offs); size = (size + dbAllocationQuantum - 1) & ~ (dbAllocationQuantum - 1); while (true) { if (Page.pageSize - offs >= size) { streamOut.Write(pg.data, offs, size); break; } streamOut.Write(pg.data, offs, Page.pageSize - offs); size -= (Page.pageSize - offs); pos += Page.pageSize - offs; offs = 0; pool.Unfix(pg); pg = pool.GetPage(pos); } pool.Unfix(pg); } } if (recOffs != newFileSize) { Assert.That(newFileSize - recOffs < Page.pageSize); int align = (int) (newFileSize - recOffs); SupportClass.ArraySupport.Fill(page, 0, align, (byte) 0); streamOut.Write(page, 0, align); } } }
public virtual void Open(IFile file, int pagePoolSize) { lock (this) { if (opened) { throw new StorageError(StorageError.STORAGE_ALREADY_OPENED); } if (lockFile) { if (!file.Lock()) { throw new StorageError(StorageError.STORAGE_IS_USED); } } Page pg; int i; int indexSize = initIndexSize; if (indexSize < dbFirstUserId) { indexSize = dbFirstUserId; } indexSize = (indexSize + dbHandlesPerPage - 1) & ~ (dbHandlesPerPage - 1); dirtyPagesMap = new int[dbDirtyPageBitmapSize / 4 + 1]; gcThreshold = Int64.MaxValue; backgroundGcMonitor = new object(); backgroundGcStartMonitor = new object(); gcThread = null; gcActive = false; gcDone = false; allocatedDelta = 0; nNestedTransactions = 0; nBlockedTransactions = 0; nCommittedTransactions = 0; scheduledCommitTime = Int64.MaxValue; transactionMonitor = new object(); transactionLock = new PersistentResource(); modified = false; objectCache = CreateObjectCache(cacheKind, pagePoolSize, objectCacheInitSize); //UPGRADE_TODO: Class 'java.util.HashMap' was converted to 'System.Collections.Hashtable' which has a different behavior. classDescMap = new Hashtable(); descList = null; header = new Header(); byte[] buf = new byte[Header.Sizeof]; int rc = file.Read(0, buf); if (rc > 0 && rc < Header.Sizeof) { throw new StorageError(StorageError.DATABASE_CORRUPTED); } header.Unpack(buf); if (header.curr < 0 || header.curr > 1) { throw new StorageError(StorageError.DATABASE_CORRUPTED); } if (pool == null) { pool = new PagePool(pagePoolSize / Page.pageSize); pool.Open(file); } if (!header.initialized) { header.curr = currIndex = 0; long used = Page.pageSize; header.root[0].index = used; header.root[0].indexSize = indexSize; header.root[0].indexUsed = dbFirstUserId; header.root[0].freeList = 0; used += indexSize * 8L; header.root[1].index = used; header.root[1].indexSize = indexSize; header.root[1].indexUsed = dbFirstUserId; header.root[1].freeList = 0; used += indexSize * 8L; header.root[0].shadowIndex = header.root[1].index; header.root[1].shadowIndex = header.root[0].index; header.root[0].shadowIndexSize = indexSize; header.root[1].shadowIndexSize = indexSize; int bitmapPages = (int) ((used + Page.pageSize * (dbAllocationQuantum * 8 - 1) - 1) / (Page.pageSize * (dbAllocationQuantum * 8 - 1))); long bitmapSize = (long) bitmapPages * Page.pageSize; int usedBitmapSize = (int) (SupportClass.URShift((used + bitmapSize), (dbAllocationQuantumBits + 3))); for (i = 0; i < bitmapPages; i++) { pg = pool.PutPage(used + (long) i * Page.pageSize); byte[] bitmap = pg.data; int n = usedBitmapSize > Page.pageSize ? Page.pageSize : usedBitmapSize; for (int j = 0; j < n; j++) { bitmap[j] = (byte) 0xFF; } usedBitmapSize -= Page.pageSize; pool.Unfix(pg); } int bitmapIndexSize = ((dbBitmapId + dbBitmapPages) * 8 + Page.pageSize - 1) & ~ (Page.pageSize - 1); byte[] index = new byte[bitmapIndexSize]; Bytes.Pack8(index, dbInvalidId * 8, dbFreeHandleFlag); for (i = 0; i < bitmapPages; i++) { Bytes.Pack8(index, (dbBitmapId + i) * 8, used | dbPageObjectFlag); used += Page.pageSize; } header.root[0].bitmapEnd = dbBitmapId + i; header.root[1].bitmapEnd = dbBitmapId + i; while (i < dbBitmapPages) { Bytes.Pack8(index, (dbBitmapId + i) * 8, dbFreeHandleFlag); i += 1; } header.root[0].size = used; header.root[1].size = used; usedSize = used; committedIndexSize = currIndexSize = dbFirstUserId; pool.Write(header.root[1].index, index); pool.Write(header.root[0].index, index); header.dirty = true; header.root[0].size = header.root[1].size; pg = pool.PutPage(0); header.Pack(pg.data); pool.Flush(); pool.Modify(pg); header.initialized = true; header.Pack(pg.data); pool.Unfix(pg); pool.Flush(); } else { int curr = header.curr; currIndex = curr; if (header.root[curr].indexSize != header.root[curr].shadowIndexSize) { throw new StorageError(StorageError.DATABASE_CORRUPTED); } if (IsDirty()) { if (listener != null) { listener.DatabaseCorrupted(); } Console.Error.WriteLine("Database was not normally closed: start recovery"); header.root[1 - curr].size = header.root[curr].size; header.root[1 - curr].indexUsed = header.root[curr].indexUsed; header.root[1 - curr].freeList = header.root[curr].freeList; header.root[1 - curr].index = header.root[curr].shadowIndex; header.root[1 - curr].indexSize = header.root[curr].shadowIndexSize; header.root[1 - curr].shadowIndex = header.root[curr].index; header.root[1 - curr].shadowIndexSize = header.root[curr].indexSize; header.root[1 - curr].bitmapEnd = header.root[curr].bitmapEnd; header.root[1 - curr].rootObject = header.root[curr].rootObject; header.root[1 - curr].classDescList = header.root[curr].classDescList; header.root[1 - curr].bitmapExtent = header.root[curr].bitmapExtent; pg = pool.PutPage(0); header.Pack(pg.data); pool.Unfix(pg); pool.Copy(header.root[1 - curr].index, header.root[curr].index, (header.root[curr].indexUsed * 8L + Page.pageSize - 1) & ~(Page.pageSize - 1)); if (listener != null) { listener.RecoveryCompleted(); } Console.Error.WriteLine("Recovery completed"); } currIndexSize = header.root[1 - curr].indexUsed; committedIndexSize = currIndexSize; usedSize = header.root[curr].size; } int bitmapSize2 = header.root[1 - currIndex].bitmapExtent == 0 ? dbBitmapPages : dbLargeBitmapPages; bitmapPageAvailableSpace = new int[bitmapSize2]; for (i = 0; i < bitmapPageAvailableSpace.Length; i++) { bitmapPageAvailableSpace[i] = Int32.MaxValue; } currRBitmapPage = currPBitmapPage = 0; currRBitmapOffs = currPBitmapOffs = 0; opened = true; ReloadScheme(); } }