231 lines
7.8 KiB
C#
231 lines
7.8 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities.DurableInstancing
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime;
|
|
using System.Runtime.DurableInstancing;
|
|
using System.Threading;
|
|
|
|
class SqlWorkflowInstanceStoreLock
|
|
{
|
|
TimeSpan hostLockRenewalPulseInterval = TimeSpan.Zero;
|
|
bool isBeingModified;
|
|
Guid lockOwnerId;
|
|
SqlWorkflowInstanceStore sqlWorkflowInstanceStore;
|
|
WeakReference lockOwnerInstanceHandle;
|
|
object thisLock;
|
|
|
|
public SqlWorkflowInstanceStoreLock(SqlWorkflowInstanceStore sqlWorkflowInstanceStore)
|
|
{
|
|
this.sqlWorkflowInstanceStore = sqlWorkflowInstanceStore;
|
|
this.thisLock = new object();
|
|
this.SurrogateLockOwnerId = -1;
|
|
}
|
|
|
|
public PersistenceTask InstanceDetectionTask
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public bool IsValid
|
|
{
|
|
get
|
|
{
|
|
return IsLockOwnerValid(this.SurrogateLockOwnerId);
|
|
}
|
|
}
|
|
|
|
public bool IsLockOwnerValid(long surrogateLockOwnerId)
|
|
{
|
|
return (this.SurrogateLockOwnerId != -1)
|
|
&& (surrogateLockOwnerId == this.SurrogateLockOwnerId)
|
|
&& (this.sqlWorkflowInstanceStore.InstanceOwnersExist);
|
|
}
|
|
|
|
public Guid LockOwnerId
|
|
{
|
|
get
|
|
{
|
|
return this.lockOwnerId;
|
|
}
|
|
}
|
|
|
|
public PersistenceTask LockRecoveryTask
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public PersistenceTask LockRenewalTask
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public long SurrogateLockOwnerId
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
object ThisLock
|
|
{
|
|
get
|
|
{
|
|
return this.thisLock;
|
|
}
|
|
}
|
|
|
|
TimeSpan HostLockRenewalPulseInterval
|
|
{
|
|
get
|
|
{
|
|
if (this.hostLockRenewalPulseInterval == TimeSpan.Zero)
|
|
{
|
|
// if user configured HostLockRenewalPeriod is less than constant MaxHostLockRenewalPulseInterval,
|
|
// then HostLockRenewalPeriod is how frequently SWIS will connect to SQL store to renew lock expiration.
|
|
// Otherwise, SWIS will connect to SQL store to renew lock expiration every MaxHostLockRenewalPulseInterval timespan.
|
|
|
|
if (SqlWorkflowInstanceStoreConstants.MaxHostLockRenewalPulseInterval < this.sqlWorkflowInstanceStore.HostLockRenewalPeriod)
|
|
{
|
|
this.hostLockRenewalPulseInterval = SqlWorkflowInstanceStoreConstants.MaxHostLockRenewalPulseInterval;
|
|
}
|
|
else
|
|
{
|
|
this.hostLockRenewalPulseInterval = this.sqlWorkflowInstanceStore.HostLockRenewalPeriod;
|
|
}
|
|
}
|
|
|
|
return this.hostLockRenewalPulseInterval;
|
|
}
|
|
}
|
|
|
|
public void MarkInstanceOwnerCreated(Guid lockOwnerId, long surrogateLockOwnerId, InstanceHandle lockOwnerInstanceHandle, bool detectRunnableInstances, bool detectActivatableInstances)
|
|
{
|
|
Fx.Assert(this.isBeingModified, "Must have modification lock to mark owner as created");
|
|
this.lockOwnerId = lockOwnerId;
|
|
this.SurrogateLockOwnerId = surrogateLockOwnerId;
|
|
this.lockOwnerInstanceHandle = new WeakReference(lockOwnerInstanceHandle);
|
|
|
|
TimeSpan runnableInstancesDetectionPeriod = this.sqlWorkflowInstanceStore.RunnableInstancesDetectionPeriod;
|
|
|
|
if (detectActivatableInstances)
|
|
{
|
|
this.InstanceDetectionTask = new DetectActivatableWorkflowsTask(this.sqlWorkflowInstanceStore, this, runnableInstancesDetectionPeriod);
|
|
}
|
|
else if (detectRunnableInstances)
|
|
{
|
|
this.InstanceDetectionTask = new DetectRunnableInstancesTask(this.sqlWorkflowInstanceStore, this, runnableInstancesDetectionPeriod);
|
|
}
|
|
|
|
// By setting taskTimeout value with BufferedHostLockRenewalPeriod,
|
|
// BufferedHostLockRenewalPeriod becomes max sql retry duration for ExtendLock command and RecoveryIntanceLock command.
|
|
this.LockRenewalTask = new LockRenewalTask(this.sqlWorkflowInstanceStore, this, this.HostLockRenewalPulseInterval, this.sqlWorkflowInstanceStore.BufferedHostLockRenewalPeriod);
|
|
this.LockRecoveryTask = new LockRecoveryTask(this.sqlWorkflowInstanceStore, this, this.HostLockRenewalPulseInterval, this.sqlWorkflowInstanceStore.BufferedHostLockRenewalPeriod);
|
|
|
|
if (this.InstanceDetectionTask != null)
|
|
{
|
|
this.InstanceDetectionTask.ResetTimer(true);
|
|
}
|
|
this.LockRenewalTask.ResetTimer(true);
|
|
this.LockRecoveryTask.ResetTimer(true);
|
|
}
|
|
|
|
public void MarkInstanceOwnerLost(long surrogateLockOwnerId, bool hasModificationLock)
|
|
{
|
|
if (hasModificationLock)
|
|
{
|
|
this.MarkInstanceOwnerLost(surrogateLockOwnerId);
|
|
}
|
|
else
|
|
{
|
|
this.TakeModificationLock();
|
|
this.MarkInstanceOwnerLost(surrogateLockOwnerId);
|
|
this.ReturnModificationLock();
|
|
}
|
|
}
|
|
|
|
public void ReturnModificationLock()
|
|
{
|
|
Fx.Assert(this.isBeingModified, "Must have modification lock to release it!");
|
|
bool lockTaken = false;
|
|
|
|
while (true)
|
|
{
|
|
Monitor.Enter(ThisLock, ref lockTaken);
|
|
|
|
if (lockTaken)
|
|
{
|
|
this.isBeingModified = false;
|
|
Monitor.Pulse(ThisLock);
|
|
Monitor.Exit(ThisLock);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void TakeModificationLock()
|
|
{
|
|
bool lockTaken = false;
|
|
|
|
while (true)
|
|
{
|
|
Monitor.Enter(ThisLock, ref lockTaken);
|
|
|
|
if (lockTaken)
|
|
{
|
|
while (this.isBeingModified)
|
|
{
|
|
Monitor.Wait(ThisLock);
|
|
}
|
|
|
|
this.isBeingModified = true;
|
|
Monitor.Exit(ThisLock);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MarkInstanceOwnerLost(long surrogateLockOwnerId)
|
|
{
|
|
Fx.Assert(this.isBeingModified, "Must have modification lock to mark owner as lost");
|
|
|
|
if (this.SurrogateLockOwnerId == surrogateLockOwnerId)
|
|
{
|
|
this.SurrogateLockOwnerId = -1;
|
|
InstanceHandle instanceHandle = this.lockOwnerInstanceHandle.Target as InstanceHandle;
|
|
if (instanceHandle != null)
|
|
{
|
|
instanceHandle.Free();
|
|
}
|
|
|
|
if (this.sqlWorkflowInstanceStore.IsLockRetryEnabled())
|
|
{
|
|
this.sqlWorkflowInstanceStore.LoadRetryHandler.AbortPendingRetries();
|
|
}
|
|
|
|
if (this.LockRenewalTask != null)
|
|
{
|
|
this.LockRenewalTask.CancelTimer();
|
|
}
|
|
|
|
if (this.LockRecoveryTask != null)
|
|
{
|
|
this.LockRecoveryTask.CancelTimer();
|
|
}
|
|
|
|
if (this.InstanceDetectionTask != null)
|
|
{
|
|
this.InstanceDetectionTask.CancelTimer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|