lsm-tree-0.1.0.0: Log-structured merge-trees
Safe HaskellSafe-Inferred
LanguageGHC2021

Control.RefCount

Synopsis

Using references

data Ref obj where Source #

A reference to an object of type a. Use references to support prompt finalisation of object resources.

Rules of use:

  • Each Ref must eventually be released exactly once with releaseRef.
  • Use withRef, or DeRef to (temporarily) obtain the underlying object.
  • After calling releaseRef, the operations withRef and pattern DeRef must not be used.
  • After calling releaseRef, an object obtained previously from DeRef must not be used. For this reason, it is advisable to use withRef where possible, and be careful with use of DeRef.
  • A Ref may be duplicated using dupRef to produce an independent reference (which must itself be released with releaseRef).

All of these operations are thread safe. They are not async-exception safe however: the operations that allocate or deallocate must be called with async exceptions masked. This includes newRef, dupRef and releaseRef.

Provided that all these rules are followed, this guarantees that the object's finaliser will be run exactly once, promptly, when the final reference is released.

In debug mode (when using CPP define NO_IGNORE_ASSERTS), adherence to these rules are checked dynamically. These dynamic checks are however not thread safe, so it is not guaranteed that all violations are always detected.

Bundled Patterns

pattern DeRef :: obj -> Ref obj

Get the object in a Ref. Be careful with retaining the object for too long, since the object must not be used after releaseRef is called.

Instances

Instances details
Show obj => Show (Ref obj) Source # 
Instance details

Defined in Control.RefCount

Methods

showsPrec :: Int -> Ref obj -> ShowS #

show :: Ref obj -> String #

showList :: [Ref obj] -> ShowS #

NFData obj => NFData (Ref obj) Source # 
Instance details

Defined in Control.RefCount

Methods

rnf :: Ref obj -> () #

releaseRef :: (RefCounted m obj, PrimMonad m, MonadMask m) => Ref obj -> m () Source #

Release a reference to an object that will no longer be used (via this reference).

withRef :: forall m obj a. (PrimMonad m, MonadThrow m) => Ref obj -> (obj -> m a) -> m a Source #

Use the object in a Ref. Do not retain the object after the scope of the body. If you cannot use scoped "with" style, use pattern DeRef.

dupRef :: forall m obj. (RefCounted m obj, PrimMonad m, MonadThrow m) => Ref obj -> m (Ref obj) Source #

Duplicate an existing reference, to produce a new reference.

data RefException Source #

Constructors

RefUseAfterRelease 

Fields

RefDoubleRelease 

Fields

RefNeverReleased RefId CallStack

Allocation site

Weak references

newtype WeakRef a Source #

A "weak" reference to an object: that is, a reference that does not guarantee to keep the object alive. If however the object is still alive (due to other normal references still existing) then it can be converted back into a normal reference with deRefWeak.

Weak references do not themselves need to be released.

Constructors

WeakRef a 

Instances

Instances details
Show a => Show (WeakRef a) Source # 
Instance details

Defined in Control.RefCount

Methods

showsPrec :: Int -> WeakRef a -> ShowS #

show :: WeakRef a -> String #

showList :: [WeakRef a] -> ShowS #

mkWeakRef :: Ref obj -> WeakRef obj Source #

Given an existing normal reference, create a new weak reference.

mkWeakRefFromRaw :: obj -> WeakRef obj Source #

Given an existing raw reference, create a new weak reference.

deRefWeak :: (RefCounted m obj, PrimMonad m) => WeakRef obj -> m (Maybe (Ref obj)) Source #

If the object is still alive, obtain a new normal reference. The normal rules for Ref apply, including the need to eventually call releaseRef.

Implementing objects with finalisers

class RefCounted m obj | obj -> m where Source #

Class of objects which support Ref.

For objects in this class the guarantee is that (when the Ref rules are followed) the object's finaliser is called exactly once.

Methods

getRefCounter :: obj -> RefCounter m Source #

newRef :: (RefCounted m obj, PrimMonad m) => m () -> (RefCounter m -> obj) -> m (Ref obj) Source #

Make a new reference.

The given finaliser is run when the last reference is released. The finaliser is run with async exceptions masked.

Low level reference counts

data RefCounter m Source #

A reference counter with an optional finaliser action. Once the reference count reaches 0, the finaliser will be run.

Constructors

RefCounter !(PrimVar (PrimState m) Int) !(m ()) 

Instances

Instances details
Show (RefCounter m) Source # 
Instance details

Defined in Control.RefCount

NFData (RefCounter m) Source #

NOTE: Only strict in the variable and not the referenced value.

Instance details

Defined in Control.RefCount

Methods

rnf :: RefCounter m -> () #

newRefCounter :: PrimMonad m => m () -> m (RefCounter m) Source #

Make a reference counter with initial value 1.

The given finaliser is run when the reference counter reaches 0. The finaliser is run with async exceptions masked.

incrementRefCounter :: PrimMonad m => RefCounter m -> m () Source #

Increase the reference counter by one.

The count must be known (from context) to be non-zero already. Typically this will be because the caller has a reference already and is handing out another reference to some other code.

decrementRefCounter :: (PrimMonad m, MonadMask m) => RefCounter m -> m () Source #

Decrease the reference counter by one.

The count must be known (from context) to be non-zero. Typically this will be because the caller has a reference already (that they took out themselves or were given).

tryIncrementRefCounter :: PrimMonad m => RefCounter m -> m Bool Source #

Try to turn a "weak" reference on something into a proper reference. This is by analogy with deRefWeak :: Weak v -> IO (Maybe v), but for reference counts.

This amounts to trying to increase the reference count, but if it is already zero then this will fail. And unlike with addReference where such failure would be a programmer error, this corresponds to the case when the thing the reference count is tracking has been closed already.

The result is True when a strong reference has been obtained and False when upgrading fails.

Test API

checkForgottenRefs :: forall m. (PrimMonad m, MonadThrow m) => m () Source #

Run a GC to try and see if any refs have been forgotten without being released. If so, this will throw a synchronous exception.

Note however that this is not the only place where RefNeverReleased exceptions can be thrown. All Ref operations poll for forgotten refs.

ignoreForgottenRefs :: (PrimMonad m, MonadCatch m) => m () Source #

Ignore and reset the state of forgotten reference tracking. This ensures that any stale fogotten references are not reported later.

This is especillay important in QC tests with shrinking which otherwise leads to confusion.

enableForgottenRefChecks :: IO () Source #

Enable forgotten reference checks.

disableForgottenRefChecks :: IO () Source #

Disable forgotten reference checks. This will error if there are already forgotten references while we are trying to disable the checks.