1 c# clr garbage-collection esent ravendb
帮帮我理解 我读过这个
"终结者的执行时间和顺序无法预测或预先确定"
正确?
但是看看RavenDB源代码TransactionStorage.cs,我看到了这一点
~TransactionalStorage()
{
try
{
Trace.WriteLine(
"Disposing esent resources from finalizer! You should call TransactionalStorage.Dispose() instead!");
Api.JetTerm2(instance, TermGrbit.Abrupt);
}
catch (Exception exception)
{
try
{
Trace.WriteLine("Failed to dispose esent instance from finalizer because: " + exception);
}
catch
{
}
}
}
Run Code Online (Sandbox Code Playgroud)
API类(属于Managed Esent)可能会使用SafeHandle对本机资源进行处理?
因此,如果我理解正确,可以在TransactionStorage之前完成本机句柄SafeHandle,这可能会产生不良影响,也许为什么Ayende在此处添加了catch all子句?
实际上潜入Esent代码,它不使用SafeHandles.
根据CLR通过C#这是危险的吗?
internal static class SomeType {
[DllImport("Kernel32", CharSet=CharSet.Unicode, EntryPoint="CreateEvent")]
// This prototype is not robust
private static extern IntPtr CreateEventBad(
IntPtr pSecurityAttributes, Boolean manualReset, Boolean initialState, String name);
// This prototype is robust
[DllImport("Kernel32", CharSet=CharSet.Unicode, EntryPoint="CreateEvent")]
private static extern SafeWaitHandle CreateEventGood(
IntPtr pSecurityAttributes, Boolean manualReset, Boolean initialState, String name)
public static void SomeMethod() {
IntPtr handle = CreateEventBad(IntPtr.Zero, false, false, null);
SafeWaitHandle swh = CreateEventGood(IntPtr.Zero, false, false, null);
}
}
Run Code Online (Sandbox Code Playgroud)
Managed Esent(NativeMEthods.cs)看起来像这样(使用Ints vs IntPtrs?):
[DllImport(EsentDll, CharSet = EsentCharSet, ExactSpelling = true)]
public static extern int JetCreateDatabase(IntPtr sesid, string szFilename, string szConnect, out uint dbid, uint grbit);
Run Code Online (Sandbox Code Playgroud)
Managed Esent正在处理finalization/dispoal正确的方法,其次是RavenDB处理终结器的纠正方式还是补偿Managed Esent?
使用带有ESENT资源的SafeHandles是非常复杂和危险的,所以我决定不这样做.有两个主要问题:
首先,有几个案例需要考虑:
现在JET_SESID或JET_TABLEID实际上是一个指向内部结构的指针(我们尝试通过一个句柄表进行间接,但发现它太慢了,特别是当被多个线程使用时).这意味着一旦资源关闭,就可以重用内存.再次释放资源可能会释放另一个线程的资源; 就像双重释放指针一样.
这使得这个代码在最终确定方面具有惊人的挑战性:
void Foo(JET_SESID sesid, JET_DBID dbid)
{
JET_TABLEID tableid;
Api.JetBeginTransaction(sesid);
Api.JetOpenTable(sesid, dbid, "table", null, 0, OpenTableGrbit.None, out tableid);
// do something...
if (somethingFailed)
{
Api.JetRollback(sesid, RollbackTransactionGrbit.None);
}
else
{
Api.JetCommitTransaction(sesid, CommitTransactionGrbit.None);
}
}
Run Code Online (Sandbox Code Playgroud)
如果JET_TABLEID包装在SafeHandle中,我们必须知道JetRollback()调用(甚至不将tableid作为参数)关闭了表,因此终结器无法关闭表.另一方面,如果我们采用提交路径,那么终结器应该关闭表.
如果JET_SESID也是一个SafeHandle,那么我们必须跟踪终结器的执行顺序.如果JET_SESID已经完成,那么我们就无法关闭JET_TABLEID.
跟踪实例,会话,表和事务之间的关系,然后在终结器中做正确的事情将是非常困难的,并且最好使用比ManagedEsent提供的更复杂的对象模型.
但是,我们可以使用带有JET_INSTANCE的SafeHandle,因为没有可以隐式关闭实例的API.Instance()包装器就是这样做的.为什么不让JET_INSTANCE成为SafeHandle?在某些情况下,应用程序想要退出而不终止ESENT - 终止可能很慢,如果您只是退出程序,使用持久事务您实际上不会丢失任何信息 - 数据库恢复将自动在JetInit上运行.
至于终结器订单,我相信关键终结器(例如SafeHandles)总是在所有正常终结器运行后运行.
| 归档时间: |
|
| 查看次数: |
1147 次 |
| 最近记录: |