📄 storageimpl.cs
字号:
namespace Perst.Impl
{
using System;
using System.Collections;
using System.Reflection;
using System.Threading;
using System.Diagnostics;
using System.Text;
using System.IO;
using Perst;
#if USE_GENERICS
using System.Collections.Generic;
#endif
public class StorageImpl:Storage
{
public const int DEFAULT_PAGE_POOL_SIZE = 4*1024*1024;
#if COMPACT_NET_FRAMEWORK
static StorageImpl()
{
assemblies = new System.Collections.ArrayList();
}
public StorageImpl(Assembly callingAssembly)
{
if (!assemblies.Contains(callingAssembly))
{
assemblies.Add(callingAssembly);
}
if (!assemblies.Contains(Assembly.GetExecutingAssembly()))
{
assemblies.Add(Assembly.GetExecutingAssembly());
}
#if FRAMEWORK_2
Assembly mscorlib = Assembly.GetAssembly(typeof(System.String));
if (!assemblies.Contains(mscorlib))
{
assemblies.Add(mscorlib);
}
#endif
}
#endif
public IPersistent Root
{
get
{
lock(this)
{
if (!opened)
{
throw new StorageError(StorageError.ErrorCode.STORAGE_NOT_OPENED);
}
int rootOid = header.root[1 - currIndex].rootObject;
return (rootOid == 0) ? null : lookupObject(rootOid, null);
}
}
set
{
lock(this)
{
if (!opened)
{
throw new StorageError(StorageError.ErrorCode.STORAGE_NOT_OPENED);
}
if (value == null)
{
header.root[1 - currIndex].rootObject = 0;
}
else
{
if (!value.IsPersistent())
{
storeObject0(value, false);
}
header.root[1 - currIndex].rootObject = value.Oid;
}
modified = true;
}
}
}
/// <summary> Initialial database index size - increasing it reduce number of inde reallocation but increase
/// initial database size. Should be set before openning connection.
/// </summary>
const int dbDefaultInitIndexSize = 1024;
/// <summary> Initial capacity of object hash
/// </summary>
const int dbDefaultObjectCacheInitSize = 1319;
/// <summary> 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
/// </summary>
static long dbDefaultExtensionQuantum = 1024 * 1024;
const long dbDefaultPagePoolLruLimit = 1L << 60;
const int dbDatabaseOffsetBits = 32; // up to 4 gigabyte
const int dbLargeDatabaseOffsetBits = 40; // up to 1 terabyte
internal const int dbAllocationQuantumBits = 5;
internal const int dbAllocationQuantum = 1 << dbAllocationQuantumBits;
const int dbBitmapSegmentBits = Page.pageSizeLog + 3 + dbAllocationQuantumBits;
const int dbBitmapSegmentSize = 1 << dbBitmapSegmentBits;
const int dbBitmapPages = 1 << (dbDatabaseOffsetBits - dbBitmapSegmentBits);
const int dbLargeBitmapPages = 1 << (dbLargeDatabaseOffsetBits - dbBitmapSegmentBits);
const int dbHandlesPerPageBits = Page.pageSizeLog - 3;
const int dbHandlesPerPage = 1 << dbHandlesPerPageBits;
const int dbDirtyPageBitmapSize = 1 << (32 - dbHandlesPerPageBits - 3);
const int dbInvalidId = 0;
const int dbBitmapId = 1;
const int dbFirstUserId = dbBitmapId + dbBitmapPages;
internal const int dbPageObjectFlag = 1;
internal const int dbModifiedFlag = 2;
internal const int dbFreeHandleFlag = 4;
internal const int dbFlagsMask = 7;
internal const int dbFlagsBits = 3;
int getBitmapPageId(int i)
{
return i < dbBitmapPages ? dbBitmapId + i : header.root[1-currIndex].bitmapExtent + i;
}
internal long getPos(int oid)
{
lock (objectCache)
{
if (oid == 0 || oid >= currIndexSize)
{
throw new StorageError(StorageError.ErrorCode.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;
}
}
internal void setPos(int oid, long pos)
{
lock (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);
}
}
internal byte[] get(int oid)
{
long pos = getPos(oid);
if ((pos & (dbFreeHandleFlag | dbPageObjectFlag)) != 0)
{
throw new StorageError(StorageError.ErrorCode.INVALID_OID);
}
return pool.get(pos & ~ dbFlagsMask);
}
internal Page getPage(int oid)
{
long pos = getPos(oid);
if ((pos & (dbFreeHandleFlag | dbPageObjectFlag)) != dbPageObjectFlag)
{
throw new StorageError(StorageError.ErrorCode.DELETED_OBJECT);
}
return pool.getPage(pos & ~ dbFlagsMask);
}
internal Page putPage(int oid)
{
lock (objectCache)
{
long pos = getPos(oid);
if ((pos & (dbFreeHandleFlag | dbPageObjectFlag)) != dbPageObjectFlag)
{
throw new StorageError(StorageError.ErrorCode.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);
}
}
internal int allocatePage()
{
int oid = allocateId();
setPos(oid, allocate(Page.pageSize, 0) | dbPageObjectFlag | dbModifiedFlag);
return oid;
}
public void deallocateObject(IPersistent obj)
{
lock(this)
{
lock (objectCache)
{
if ( obj.Oid == 0)
{
return;
}
if (useSerializableTransactions)
{
ThreadTransactionContext ctx = TransactionContext;
if (ctx.nested != 0)
{ // serializable transaction
ctx.deleted.Add(obj);
return;
}
}
deallocateObject0(obj);
}
}
}
private void deallocateObject0(IPersistent obj)
{
int oid = obj.Oid;
long pos = getPos(oid);
objectCache.remove(oid);
int offs = (int) pos & (Page.pageSize - 1);
if ((offs & (dbFreeHandleFlag | dbPageObjectFlag)) != 0)
{
throw new StorageError(StorageError.ErrorCode.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.GetType()) : 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);
}
internal void freePage(int oid)
{
long pos = getPos(oid);
Debug.Assert((pos & (dbFreeHandleFlag | dbPageObjectFlag)) == dbPageObjectFlag);
if ((pos & dbModifiedFlag) != 0)
{
free(pos & ~ dbFlagsMask, Page.pageSize);
}
else
{
cloneBitmap(pos & ~ dbFlagsMask, Page.pageSize);
}
freeId(oid);
}
virtual protected bool isDirty()
{
return header.dirty;
}
internal void setDirty()
{
modified = true;
if (!header.dirty)
{
header.dirty = true;
Page pg = pool.putPage(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -