📄 storageimpl.java
字号:
package org.garret.perst.impl;
import org.garret.perst.*;
import java.lang.reflect.*;
import java.util.*;
import java.io.*;
public class StorageImpl implements Storage {
/**
* Initialial database index size - increasing it reduce number of inde reallocation but increase
* initial database size. Should be set before openning connection.
*/
static final int dbDefaultInitIndexSize = 1024;
/**
* Initial capacity of object hash
*/
static final int dbDefaultObjectCacheInitSize = 1319;
/**
* Database extension quantum. Memory is allocate by scanning bitmap. If there is no
* large enough hole, then database is extended by the value of dbDefaultExtensionQuantum
* This parameter should not be smaller than dbFirstUserId
*/
static final long dbDefaultExtensionQuantum = 1024*1024;
static final long dbDefaultPagePoolLruLimit = 1L << 60;
static final int dbDatabaseOffsetBits = 32; // up to 4 gigabyte
static final int dbLargeDatabaseOffsetBits = 40; // up to 1 terabyte
static final int dbAllocationQuantumBits = 5;
static final int dbAllocationQuantum = 1 << dbAllocationQuantumBits;
static final int dbBitmapSegmentBits = Page.pageSizeLog + 3 + dbAllocationQuantumBits;
static final int dbBitmapSegmentSize = 1 << dbBitmapSegmentBits;
static final int dbBitmapPages = 1 << (dbDatabaseOffsetBits-dbBitmapSegmentBits);
static final int dbLargeBitmapPages = 1 << (dbLargeDatabaseOffsetBits-dbBitmapSegmentBits);
static final int dbHandlesPerPageBits = Page.pageSizeLog - 3;
static final int dbHandlesPerPage = 1 << dbHandlesPerPageBits;
static final int dbDirtyPageBitmapSize = 1 << (32-dbHandlesPerPageBits-3);
static final int dbInvalidId = 0;
static final int dbBitmapId = 1;
static final int dbFirstUserId = dbBitmapId + dbBitmapPages;
static final int dbPageObjectFlag = 1;
static final int dbModifiedFlag = 2;
static final int dbFreeHandleFlag = 4;
static final int dbFlagsMask = 7;
static final int dbFlagsBits = 3;
final int getBitmapPageId(int i) {
return i < dbBitmapPages ? dbBitmapId + i : header.root[1-currIndex].bitmapExtent + i;
}
final long getPos(int oid) {
synchronized (objectCache) {
if (oid == 0 || oid >= currIndexSize) {
throw new StorageError(StorageError.INVALID_OID);
}
Page pg = pool.getPage(header.root[1-currIndex].index
+ ((long)(oid >>> dbHandlesPerPageBits) << Page.pageSizeLog));
long pos = Bytes.unpack8(pg.data, (oid & (dbHandlesPerPage-1)) << 3);
pool.unfix(pg);
return pos;
}
}
final void setPos(int oid, long pos) {
synchronized (objectCache) {
dirtyPagesMap[oid >>> (dbHandlesPerPageBits+5)]
|= 1 << ((oid >>> dbHandlesPerPageBits) & 31);
Page pg = pool.putPage(header.root[1-currIndex].index
+ ((long)(oid >>> dbHandlesPerPageBits) << Page.pageSizeLog));
Bytes.pack8(pg.data, (oid & (dbHandlesPerPage-1)) << 3, pos);
pool.unfix(pg);
}
}
final byte[] get(int oid) {
long pos = getPos(oid);
if ((pos & (dbFreeHandleFlag|dbPageObjectFlag)) != 0) {
throw new StorageError(StorageError.INVALID_OID);
}
return pool.get(pos & ~dbFlagsMask);
}
final Page getPage(int oid) {
long pos = getPos(oid);
if ((pos & (dbFreeHandleFlag|dbPageObjectFlag)) != dbPageObjectFlag) {
throw new StorageError(StorageError.DELETED_OBJECT);
}
return pool.getPage(pos & ~dbFlagsMask);
}
final Page putPage(int oid) {
synchronized (objectCache) {
long pos = getPos(oid);
if ((pos & (dbFreeHandleFlag|dbPageObjectFlag)) != dbPageObjectFlag) {
throw new StorageError(StorageError.DELETED_OBJECT);
}
if ((pos & dbModifiedFlag) == 0) {
dirtyPagesMap[oid >>> (dbHandlesPerPageBits+5)]
|= 1 << ((oid >>> dbHandlesPerPageBits) & 31);
allocate(Page.pageSize, oid);
cloneBitmap(pos & ~dbFlagsMask, Page.pageSize);
pos = getPos(oid);
}
modified = true;
return pool.putPage(pos & ~dbFlagsMask);
}
}
int allocatePage() {
int oid = allocateId();
setPos(oid, allocate(Page.pageSize, 0) | dbPageObjectFlag | dbModifiedFlag);
return oid;
}
public synchronized void deallocateObject(IPersistent obj)
{
synchronized (objectCache) {
if (obj.getOid() == 0) {
return;
}
if (useSerializableTransactions) {
ThreadTransactionContext ctx = getTransactionContext();
if (ctx.nested != 0) { // serializable transaction
ctx.deleted.add(obj);
return;
}
}
deallocateObject0(obj);
}
}
private void deallocateObject0(IPersistent obj)
{
int oid = obj.getOid();
long pos = getPos(oid);
objectCache.remove(oid);
int offs = (int)pos & (Page.pageSize-1);
if ((offs & (dbFreeHandleFlag|dbPageObjectFlag)) != 0) {
throw new StorageError(StorageError.DELETED_OBJECT);
}
Page pg = pool.getPage(pos - offs);
offs &= ~dbFlagsMask;
int size = ObjectHeader.getSize(pg.data, offs);
pool.unfix(pg);
freeId(oid);
CustomAllocator allocator = (customAllocatorMap != null)
? getCustomAllocator(obj.getClass()) : null;
if (allocator != null) {
allocator.free(pos & ~dbFlagsMask, size);
} else {
if ((pos & dbModifiedFlag) != 0) {
free(pos & ~dbFlagsMask, size);
} else {
cloneBitmap(pos, size);
}
}
obj.assignOid(null, 0, false);
}
final void freePage(int oid) {
long pos = getPos(oid);
Assert.that((pos & (dbFreeHandleFlag|dbPageObjectFlag)) == dbPageObjectFlag);
if ((pos & dbModifiedFlag) != 0) {
free(pos & ~dbFlagsMask, Page.pageSize);
} else {
cloneBitmap(pos & ~dbFlagsMask, Page.pageSize);
}
freeId(oid);
}
int allocateId() {
synchronized (objectCache) {
int oid;
int curr = 1-currIndex;
setDirty();
if ((oid = header.root[curr].freeList) != 0) {
header.root[curr].freeList = (int)(getPos(oid) >> dbFlagsBits);
Assert.that(header.root[curr].freeList >= 0);
dirtyPagesMap[oid >>> (dbHandlesPerPageBits+5)]
|= 1 << ((oid >>> dbHandlesPerPageBits) & 31);
return oid;
}
if (currIndexSize >= header.root[curr].indexSize) {
int oldIndexSize = header.root[curr].indexSize;
int newIndexSize = oldIndexSize << 1;
if (newIndexSize < oldIndexSize) {
newIndexSize = Integer.MAX_VALUE & ~(dbHandlesPerPage-1);
if (newIndexSize <= oldIndexSize) {
throw new StorageError(StorageError.NOT_ENOUGH_SPACE);
}
}
long newIndex = allocate(newIndexSize*8L, 0);
if (currIndexSize >= header.root[curr].indexSize) {
long oldIndex = header.root[curr].index;
pool.copy(newIndex, oldIndex, currIndexSize*8L);
header.root[curr].index = newIndex;
header.root[curr].indexSize = newIndexSize;
free(oldIndex, oldIndexSize*8L);
} else {
// index was already reallocated
free(newIndex, newIndexSize*8L);
}
}
oid = currIndexSize;
header.root[curr].indexUsed = ++currIndexSize;
return oid;
}
}
void freeId(int oid)
{
synchronized (objectCache) {
setPos(oid, ((long)(header.root[1-currIndex].freeList) << dbFlagsBits)
| dbFreeHandleFlag);
header.root[1-currIndex].freeList = oid;
}
}
final static byte firstHoleSize [] = {
8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
};
final static byte lastHoleSize [] = {
8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
final static byte maxHoleSize [] = {
8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
5,4,3,3,2,2,2,2,3,2,2,2,2,2,2,2,4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2,
6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
7,6,5,5,4,4,4,4,3,3,3,3,3,3,3,3,4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2,
5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,0
};
final static byte maxHoleOffset [] = {
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,0,1,5,5,5,5,5,5,0,5,5,5,5,5,5,5,
0,1,2,2,0,3,3,3,0,1,6,6,0,6,6,6,0,1,2,2,0,6,6,6,0,1,6,6,0,6,6,6,
0,1,2,2,3,3,3,3,0,1,4,4,0,4,4,4,0,1,2,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,2,2,0,3,3,3,0,1,0,2,0,1,0,4,0,1,2,2,0,1,0,3,0,1,0,2,0,1,0,7,
0,1,2,2,3,3,3,3,0,4,4,4,4,4,4,4,0,1,2,2,0,5,5,5,0,1,5,5,0,5,5,5,
0,1,2,2,0,3,3,3,0,1,0,2,0,1,0,4,0,1,2,2,0,1,0,3,0,1,0,2,0,1,0,6,
0,1,2,2,3,3,3,3,0,1,4,4,0,4,4,4,0,1,2,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,2,2,0,3,3,3,0,1,0,2,0,1,0,4,0,1,2,2,0,1,0,3,0,1,0,2,0,1,0,0
};
static final int pageBits = Page.pageSize*8;
static final int inc = Page.pageSize/dbAllocationQuantum/8;
static final void memset(Page pg, int offs, int pattern, int len) {
byte[] arr = pg.data;
byte pat = (byte)pattern;
while (--len >= 0) {
arr[offs++] = pat;
}
}
final void extend(long size)
{
if (size > header.root[1-currIndex].size) {
header.root[1-currIndex].size = size;
}
}
public long getUsedSize() {
return usedSize;
}
public long getDatabaseSize() {
return header.root[1-currIndex].size;
}
static class Location {
long pos;
long size;
Location next;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -