// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. // // // Callback for JET_param JET_paramDurableCommitCallback. // // -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.Isam.Esent.Interop.Windows8 { using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; #if !MANAGEDESENT_ON_CORECLR using System.Runtime.CompilerServices; #endif using Microsoft.Isam.Esent.Interop.Implementation; /// /// A class which wraps the callback dealing with durable commits. /// public class DurableCommitCallback : EsentResource { /// /// API call tracing. /// private static readonly TraceSwitch TraceSwitch = new TraceSwitch("ESENT DurableCommitCallback", "Wrapper around unmanaged ESENT durable commit callback"); /// /// Instance associated with this callback. /// private JET_INSTANCE instance; /// /// Hold a reference to the delegate so that it doesn't get garbage-collected. /// private JET_PFNDURABLECOMMITCALLBACK wrappedCallback; /// /// Hold a reference to the delegate so that it doesn't get garbage-collected. /// [SuppressMessage("Exchange.Performance", "EX0023:DeadVariableDetector", Justification = "Need to hold on to a reference to the callback, so that it does not get garbage collected.")] private NATIVE_JET_PFNDURABLECOMMITCALLBACK wrapperCallback; /// /// Initializes a new instance of the class. /// The constructor. /// /// /// The instance with which to associate the callback. /// /// /// The managed code callback to call. /// public DurableCommitCallback( JET_INSTANCE instance, JET_PFNDURABLECOMMITCALLBACK wrappedCallback) { this.instance = instance; this.wrappedCallback = wrappedCallback; this.wrapperCallback = this.NativeDurableCommitCallback; #if !MANAGEDESENT_ON_WSA // RuntimeHelpers works differently in Windows Store Apps. if (this.wrappedCallback != null) { RuntimeHelpers.PrepareMethod(this.wrappedCallback.Method.MethodHandle); } RuntimeHelpers.PrepareMethod(typeof(DurableCommitCallback).GetMethod("NativeDurableCommitCallback", BindingFlags.NonPublic | BindingFlags.Instance).MethodHandle); #endif InstanceParameters instanceParameters = new InstanceParameters(this.instance); // This might be null. instanceParameters.SetDurableCommitCallback(this.wrapperCallback); this.ResourceWasAllocated(); } /// /// Generate a string representation of the structure. /// /// The structure as a string. public override string ToString() { return string.Format( CultureInfo.InvariantCulture, "DurableCommitCallback({0})", this.instance.ToString()); } /// /// Terminate the durable commit session. /// public void End() { this.CheckObjectIsNotDisposed(); this.ReleaseResource(); } /// /// Free the durable commit session. /// We do not try to set the instance parameter to null, since the callback is disposed after JetTerm and /// the callback cannot be set after JetTerm. /// protected override void ReleaseResource() { this.instance = JET_INSTANCE.Nil; this.wrappedCallback = null; this.wrapperCallback = null; this.ResourceWasReleased(); } /// /// The proxy callback function to call the user-defined managed delegate. /// /// /// The instance. /// /// /// The commit-id flushed. /// /// /// Reserved currently. /// /// /// An error code. /// private JET_err NativeDurableCommitCallback( IntPtr instance, ref NATIVE_COMMIT_ID commitIdSeen, uint grbit) { RuntimeHelpers.PrepareConstrainedRegions(); try { JET_INSTANCE jetInstance = new JET_INSTANCE() { Value = instance }; if (this.instance != jetInstance) { // We assume it's only called on one instance at a time. The only thing // we really care about is serialization of the byte array. // // It would be nice to throw an error, but we're going back to real // code, which doesn't deal with managed exceptions well. return JET_err.CallbackFailed; } JET_COMMIT_ID commitId = new JET_COMMIT_ID(commitIdSeen); return this.wrappedCallback(jetInstance, commitId, (DurableCommitCallbackGrbit)grbit); } catch (Exception ex) { Trace.WriteLineIf( TraceSwitch.TraceWarning, string.Format(CultureInfo.InvariantCulture, "Caught Exception {0}", ex)); JetApi.ReportUnhandledException(ex, "Unhandled exception during NativeDurableCommitCallback"); // This should never be executed, but the compiler doesn't know it. return JET_err.CallbackFailed; } } } }