Session locks
Session locks are a way to ensure that only one session at a time can access a particular resource. For example, you can use a session lock to ensure that only one session is allowed to update a certain topic.
Session locks are a mechanism managed by the Diffusion™ server to coordinate access to shared resources among multiple sessions.
A session can acquire a lock, identified by a lock name (chosen by you to suit your application). Once a session acquires a lock, no other session can acquire the same lock.
Acquiring a lock does not automatically change anything else about a session. Locks are not linked to topics or permissions, except through your application's logic. It is up to you to design a suitable locking scheme and ensure your application implements it. For example, if you want to implement exclusive updating of a topic using a session lock, you must make sure that each session always acquires the lock and uses a lock constraint created from the lock when updating the topic.
By default, a lock is released when the session owning it closes. Alternatively, when acquiring a lock, a session can specify that the lock will be released if connection to the server is lost. This is done using a scope parameter.
A session can also explicitly release a lock.
/** * Copyright © 2021 Push Technology Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using PushTechnology.ClientInterface.Client.Callbacks; using PushTechnology.ClientInterface.Client.Factories; using PushTechnology.ClientInterface.Client.Features; using PushTechnology.ClientInterface.Client.Features.Topics; using PushTechnology.ClientInterface.Client.Session; using PushTechnology.ClientInterface.Client.Topics; using PushTechnology.ClientInterface.Client.Topics.Details; using static System.Console; namespace PushTechnology.ClientInterface.Example { /// <summary> /// Client implementation that demonstrates session locks. /// </summary> public sealed class SessionLocks { private ISession session1, session2; private ISessionLock sessionLock1, sessionLock2; private static string LOCK_NAME = "lockA"; public SessionLocks(string serverUrl) { session1 = Diffusion.Sessions.Principal("control").Password("password") .CertificateValidation((cert, chain, errors) => CertificateValidationResult.ACCEPT) .Open(serverUrl); session2 = Diffusion.Sessions.Principal("control").Password("password") .CertificateValidation((cert, chain, errors) => CertificateValidationResult.ACCEPT) .Open(serverUrl); WriteLine("Sessions 1 and 2 have been created."); AcquireLockSession1(); } private async void AcquireLockSession1() { try { WriteLine("Requesting lock 1..."); sessionLock1 = await session1.LockAsync(LOCK_NAME, SessionLockScope.UNLOCK_ON_CONNECTION_LOSS); WriteLine("Lock 1 has been acquired."); AcquireLockSession2(); Thread.Sleep(1000); ReleaseLock1(); } catch (Exception ex) { WriteLine($"Failed to get lock 1 : {ex}."); session1.Close(); session2.Close(); } } private async void AcquireLockSession2() { try { WriteLine("Requesting lock 2..."); sessionLock2 = await session2.LockAsync(LOCK_NAME, SessionLockScope.UNLOCK_ON_CONNECTION_LOSS); WriteLine("Lock 2 has been acquired."); Thread.Sleep(1000); ReleaseLock2(); } catch (Exception ex) { WriteLine($"Failed to get lock 2 : {ex}."); session1.Close(); session2.Close(); } } private async void ReleaseLock1() { try { WriteLine("Requesting lock 1 release..."); await sessionLock1.UnlockAsync(); WriteLine("Lock 1 has been released."); } catch (Exception ex) { WriteLine($"Failed to release lock 1 : {ex}."); session1.Close(); session2.Close(); } } private async void ReleaseLock2() { try { WriteLine("Requesting lock 2 release..."); await sessionLock2.UnlockAsync(); WriteLine("Lock 2 has been released."); } catch (Exception ex) { WriteLine($"Failed to release lock 2 : {ex}."); } finally { session1.Close(); session2.Close(); } } } }
Acquiring a lock
Required permissions:
Session locks are established on demand. There is no separate operation to create or destroy a named lock.
If a session attempts to acquire a lock that is not assigned, the server assigns it immediately to the session.
If a session attempts to acquire a lock that is already assigned, the server will record that the session is waiting to acquire it. When a lock is released and multiple sessions are waiting to acquire it, the server will arbitrarily assign it to one of the waiting sessions.
- Lock name
- A name for the lock.
- Lock scope (optional)
The scope of the lock.
By default, the scope is UNLOCK_ON_SESSION_LOSS, meaning that the lock will be released when the session is closed.
If the scope is set to UNLOCK_ON_CONNECTION_LOSS, the lock will be released when the session loses its current connection to the server.