public void VerifyWrapperIsCollectedWhenCallbackIsCollected()
        {
            JET_CALLBACK callback    = CreateCallback();
            var          callbackRef = new WeakReference(callback);

            var callbackWrappers = new CallbackWrappers();
            var wrapperRef       = new WeakReference(callbackWrappers.Add(callback));

            callback = null;

            RunFullGarbageCollection();
            callbackWrappers.Collect();
            RunFullGarbageCollection();

            // In DEBUG test code, the objects remain alive for an indeterminate amount of time, for some reason.
            // Note that they do get collected if a RETAIL test code is used, even if the product code is DEBUG
            // so it must be something to do with assigning the local variable 'callback' to null and the effect that
            // it has on garbage collecting weak references to it.
#if !DEBUG
            Assert.IsFalse(callbackRef.IsAlive);
            Assert.IsFalse(wrapperRef.IsAlive);
#endif

            // Avoid premature collection of these objects
            GC.KeepAlive(callbackWrappers);
        }
        public void VerifyIsWrappingReturnsFalseForNoMatch()
        {
            JET_CALLBACK callback = CreateCallback();
            var          wrapper  = new JetCallbackWrapper(callback);

            Assert.IsFalse(wrapper.IsWrapping(CreateCallback()));
            GC.KeepAlive(callback);
        }
        public void VerifyAddingSameCallbackReturnsSameWrapper()
        {
            JET_CALLBACK callback = CreateCallback();

            var callbackWrappers = new CallbackWrappers();
            var wrapper          = callbackWrappers.Add(callback);

            Assert.AreEqual(wrapper, callbackWrappers.Add(callback));
        }
        public void VerifyAddingCallbackReturnsWrapper()
        {
            JET_CALLBACK callback = CreateCallback();

            var callbackWrappers = new CallbackWrappers();
            var wrapper          = callbackWrappers.Add(callback);

            Assert.IsNotNull(callbackWrappers.Add(callback));
        }
        public void VerifyNativeCallbackIsNotGarbageCollected()
        {
            JET_CALLBACK callback = CreateCallback();

            var callbackWrappers       = new CallbackWrappers();
            JetCallbackWrapper wrapper = callbackWrappers.Add(callback);
            WeakReference      weakRef = new WeakReference(wrapper.NativeCallback);

            RunFullGarbageCollection();
            Assert.IsTrue(weakRef.IsAlive);
            GC.KeepAlive(wrapper);
        }
        /// <summary>
        /// Look in the list of callback wrappers to see if there is already an entry for
        /// this callback.
        /// </summary>
        /// <param name="callback">The callback to look for.</param>
        /// <param name="wrapper">Returns the wrapper, if found.</param>
        /// <returns>True if a wrapper was found, false otherwise.</returns>
        private bool TryFindWrapperFor(JET_CALLBACK callback, out JetCallbackWrapper wrapper)
        {
            foreach (JetCallbackWrapper w in this.callbackWrappers)
            {
                if (w.IsWrapping(callback))
                {
                    wrapper = w;
                    return(true);
                }
            }

            wrapper = null;
            return(false);
        }
Esempio n. 7
0
        /// <summary>
        /// Wrap a callback and returns its wrapper. If the callback is
        /// already wrapped then the existing wrapper is returned.
        /// </summary>
        /// <param name="callback">The callback to add.</param>
        /// <returns>The callback wrapper for the callback.</returns>
        public JetCallbackWrapper Add(JET_CALLBACK callback)
        {
            lock (this.lockObject)
            {
                JetCallbackWrapper wrapper;
                if (!this.TryFindWrapperFor(callback, out wrapper))
                {
                    wrapper = new JetCallbackWrapper(callback);
                    this.callbackWrappers.Add(wrapper);
                }

                return wrapper;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Look in the list of callback wrappers to see if there is already an entry for 
        /// this callback.
        /// </summary>
        /// <param name="callback">The callback to look for.</param>
        /// <param name="wrapper">Returns the wrapper, if found.</param>
        /// <returns>True if a wrapper was found, false otherwise.</returns>
        private bool TryFindWrapperFor(JET_CALLBACK callback, out JetCallbackWrapper wrapper)
        {
            foreach (JetCallbackWrapper w in this.callbackWrappers)
            {
                if (w.IsWrapping(callback))
                {
                    wrapper = w;
                    return true;
                }
            }

            wrapper = null;
            return false;
        }
        /// <summary>
        /// Wrap a callback and returns its wrapper. If the callback is
        /// already wrapped then the existing wrapper is returned.
        /// </summary>
        /// <param name="callback">The callback to add.</param>
        /// <returns>The callback wrapper for the callback.</returns>
        public JetCallbackWrapper Add(JET_CALLBACK callback)
        {
            lock (this.lockObject)
            {
                JetCallbackWrapper wrapper;
                if (!this.TryFindWrapperFor(callback, out wrapper))
                {
                    wrapper = new JetCallbackWrapper(callback);
                    this.callbackWrappers.Add(wrapper);
                }

                return(wrapper);
            }
        }
        public void VerifyWrapperIsAliveWhenCallbackIsAlive()
        {
            JET_CALLBACK callback = CreateCallback();

            var callbackWrappers = new CallbackWrappers();
            var wrapperRef       = new WeakReference(callbackWrappers.Add(callback));

            RunFullGarbageCollection();
            callbackWrappers.Collect();
            RunFullGarbageCollection();

            Assert.IsTrue(wrapperRef.IsAlive);

            // Avoid premature collection of these objects
            GC.KeepAlive(callback);
            GC.KeepAlive(callbackWrappers);
        }
Esempio n. 11
0
        /// <summary>
        /// Callback function for native code. We don't want to throw an exception through
        /// unmanaged ESENT because that will corrupt ESENT's internal state. Instead we
        /// catch all exceptions and return an error instead. We use a CER to make catching
        /// the exceptions as reliable as possible.
        /// </summary>
        /// <param name="nativeSesid">The session for which the callback is being made.</param>
        /// <param name="nativeDbid">The database for which the callback is being made.</param>
        /// <param name="nativeTableid">The cursor for which the callback is being made.</param>
        /// <param name="nativeCbtyp">The operation for which the callback is being made.</param>
        /// <param name="arg1">First callback-specific argument.</param>
        /// <param name="arg2">Second callback-specific argument.</param>
        /// <param name="nativeContext">Callback context.</param>
        /// <param name="unused">This parameter is not used.</param>
        /// <returns>An ESENT error code.</returns>
        private JET_err CallbackImpl(
            IntPtr nativeSesid,
            uint nativeDbid,
            IntPtr nativeTableid,
            uint nativeCbtyp,
            IntPtr arg1,
            IntPtr arg2,
            IntPtr nativeContext,
            IntPtr unused)
        {
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                var sesid = new JET_SESID {
                    Value = nativeSesid
                };
                var dbid = new JET_DBID {
                    Value = nativeDbid
                };
                var tableid = new JET_TABLEID {
                    Value = nativeTableid
                };
                JET_cbtyp cbtyp = (JET_cbtyp)nativeCbtyp;

                Debug.Assert(this.wrappedCallback.IsAlive, "Wrapped callback has been garbage collected");

                // This will throw an exception if the wrapped callback has been collected. The exception
                // will be handled below.
                JET_CALLBACK callback = (JET_CALLBACK)this.wrappedCallback.Target;
                return(callback(sesid, dbid, tableid, cbtyp, null, null, nativeContext, IntPtr.Zero));
            }
            catch (Exception ex)
            {
                // Thread aborts aren't handled here. ESENT callbacks can execute on client threads or
                // internal ESENT threads so it isn't clear what should be done on an abort.
                Trace.WriteLineIf(
                    traceSwitch.TraceWarning,
                    String.Format(CultureInfo.InvariantCulture, "Caught Exception {0}", ex));
                return(JET_err.CallbackFailed);
            }
        }
Esempio n. 12
0
        public void TestJetDefragment2Callback()
        {
            ManualResetEvent oldFinishedEvent = new ManualResetEvent(false);
            JET_CALLBACK     callback         = (sesid, dbid, tableid, cbtyp, arg1, arg2, context, unused) =>
            {
                oldFinishedEvent.Set();
                return(JET_err.Success);
            };

            int passes  = 1;
            int seconds = 1;

            Api.JetDefragment2(this.sesid, this.dbid, null, ref passes, ref seconds, callback, DefragGrbit.BatchStart);
            Assert.IsTrue(
                oldFinishedEvent.WaitOne(TimeSpan.FromSeconds(10)),
                "Online Defragmentation Callback not called");
            Api.JetDefragment2(this.sesid, this.dbid, null, ref passes, ref seconds, null, DefragGrbit.BatchStop);

            // Don't let the callback be collected before OLD finishes.
            GC.KeepAlive(callback);
        }
Esempio n. 13
0
        public void VerifyRegisteredCallbackIsCalled()
        {
            bool         callbackWasCalled = false;
            JET_CALLBACK callback          = (s, d, t, cbtyp, arg1, arg2, context, unused) =>
            {
                callbackWasCalled = true;
                return(JET_err.Success);
            };

            JET_HANDLE callbackId;

            Api.JetRegisterCallback(this.sesid, this.tableid, JET_cbtyp.BeforeInsert, callback, IntPtr.Zero, out callbackId);

            using (var transaction = new Transaction(this.sesid))
                using (var update = new Update(this.sesid, this.tableid, JET_prep.Insert))
                {
                    Api.SetColumn(this.sesid, this.tableid, this.columnidLongText, Any.String, Encoding.Unicode);
                    update.Save();
                    transaction.Commit(CommitTransactionGrbit.None);
                }

            Assert.IsTrue(callbackWasCalled, "callback was not called");
        }
Esempio n. 14
0
 /// <summary>
 /// Initializes a new instance of the JetCallbackWrapper class.
 /// </summary>
 /// <param name="callback">
 /// The managed callback to use.
 /// </param>
 public JetCallbackWrapper(JET_CALLBACK callback)
 {
     this.wrappedCallback = new WeakReference(callback);
     Debug.Assert(this.wrappedCallback.IsAlive, "Callback isn't alive");
 }
Esempio n. 15
0
 /// <summary>
 /// Determine if the callback is wrapping the specified JET_CALLBACK.
 /// </summary>
 /// <param name="callback">The callback.</param>
 /// <returns>True if this wrapper is wrapping the callback.</returns>
 public bool IsWrapping(JET_CALLBACK callback)
 {
     return(callback.Equals(this.wrappedCallback.Target));
 }
Esempio n. 16
0
 /// <summary>
 /// Initializes a new instance of the <see cref="JetSetGetLs"/> class.
 /// </summary>
 public JetSetGetLs()
 {
     this.runtimeCallback = new JET_CALLBACK(this.RuntimeCallback);
 }
Esempio n. 17
0
 /// <summary>
 /// Sets database configuration options.
 /// </summary>
 /// <param name="instance">
 /// The instance to set the option on or <see cref="JET_INSTANCE.Nil"/>
 /// to set the option on all instances.
 /// </param>
 /// <param name="sesid">The session to use.</param>
 /// <param name="paramid">The parameter to set.</param>
 /// <param name="paramValue">The value of the parameter to set, if the parameter is a JET_CALLBACK.</param>
 /// <param name="paramString">The value of the parameter to set, if the parameter is a string type.</param>
 /// <returns>An ESENT warning code.</returns>
 public static JET_wrn JetSetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, JET_param paramid, JET_CALLBACK paramValue, string paramString)
 {
     return Api.Check(Impl.JetSetSystemParameter(instance, sesid, paramid, paramValue, paramString));
 }
Esempio n. 18
0
 /// <summary>
 /// Allows the application to configure the database engine to issue
 /// notifications to the application for specific events. These
 /// notifications are associated with a specific table and remain in
 /// effect only until the instance containing the table is shut down
 /// using <see cref="JetTerm"/>.
 /// </summary>
 /// <param name="sesid">The session to use.</param>
 /// <param name="tableid">
 /// A cursor opened on the table that the callback should be
 /// registered on.
 /// </param>
 /// <param name="cbtyp">
 /// The callback reasons for which the application wishes to receive notifications.
 /// </param>
 /// <param name="callback">The callback function.</param>
 /// <param name="context">A context that will be given to the callback.</param>
 /// <param name="callbackId">
 /// A handle that can later be used to cancel the registration of the given
 /// callback function using <see cref="JetUnregisterCallback"/>.
 /// </param>
 public static void JetRegisterCallback(
     JET_SESID sesid,
     JET_TABLEID tableid,
     JET_cbtyp cbtyp,
     JET_CALLBACK callback,
     IntPtr context,
     out JET_HANDLE callbackId)
 {
     Api.Check(Impl.JetRegisterCallback(sesid, tableid, cbtyp, callback, context, out callbackId));
 }
Esempio n. 19
0
 /// <summary>
 /// Starts and stops database defragmentation tasks that improves data
 /// organization within a database.
 /// </summary>
 /// <remarks>
 /// The callback passed to JetDefragment2 can be executed asynchronously.
 /// The GC doesn't know that the unmanaged code has a reference to the callback
 /// so it is important to make sure the callback isn't collected.
 /// </remarks>
 /// <param name="sesid">The session to use for the call.</param>
 /// <param name="dbid">The database to be defragmented.</param>
 /// <param name="tableName">
 /// Unused parameter. Defragmentation is performed for the entire database described by the given database ID.
 /// </param>
 /// <param name="passes">
 /// When starting an online defragmentation task, this parameter sets the maximum number of defragmentation
 /// passes. When stopping an online defragmentation task, this parameter is set to the number of passes
 /// performed.
 /// </param>
 /// <param name="seconds">
 /// When starting an online defragmentation task, this parameter sets
 /// the maximum time for defragmentation. When stopping an online
 /// defragmentation task, this output buffer is set to the length of
 /// time used for defragmentation.
 /// </param>
 /// <param name="callback">Callback function that defrag uses to report progress.</param>
 /// <param name="grbit">Defragmentation options.</param>
 /// <returns>A warning code.</returns>
 public static JET_wrn JetDefragment2(
     JET_SESID sesid, 
     JET_DBID dbid, 
     string tableName, 
     ref int passes, 
     ref int seconds, 
     JET_CALLBACK callback, 
     DefragGrbit grbit)
 {
     return Api.Check(Impl.JetDefragment2(sesid, dbid, tableName, ref passes, ref seconds, callback, grbit));
 }
Esempio n. 20
0
 /// <summary>
 /// Initializes a new instance of the JetCallbackWrapper class.
 /// </summary>
 /// <param name="callback">
 /// The managed callback to use.
 /// </param>
 public JetCallbackWrapper(JET_CALLBACK callback)
 {
     this.wrappedCallback = new WeakReference(callback);
     this.nativeCallback = this.CallbackImpl;
     Debug.Assert(this.wrappedCallback.IsAlive, "Callback isn't alive");
 }
Esempio n. 21
0
 /// <summary>
 /// Determine if the callback is wrapping the specified JET_CALLBACK.
 /// </summary>
 /// <param name="callback">The callback.</param>
 /// <returns>True if this wrapper is wrapping the callback.</returns>
 public bool IsWrapping(JET_CALLBACK callback)
 {
     return callback.Equals(this.wrappedCallback.Target);
 }