From 9d0cd9907f4a65729c922e8fabbfceba9cdb194c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Fl=C3=ADdr?= Date: Sun, 8 Oct 2017 14:55:54 +0200 Subject: [PATCH] full locks --- Connection/Closing.vb | 190 ++++++++++++++++-------------------------- Connection/Opening.vb | 67 ++------------- MetaDescriptor.vb | 164 ++++++++++++++++-------------------- 3 files changed, 155 insertions(+), 266 deletions(-) diff --git a/Connection/Closing.vb b/Connection/Closing.vb index e421097..bfd984a 100644 --- a/Connection/Closing.vb +++ b/Connection/Closing.vb @@ -6,12 +6,7 @@ Partial Public MustInherit Class Connection ''' ''' Threads semahore to read/write first level records from/into managed connections store. ''' - Private Shared _registerLock As New ReaderWriterLockSlim() - - ''' - ''' Threads semahores to read/write second level records from/into managed connections store. - ''' - Private Shared _registerLocks As New Dictionary(Of String, ReaderWriterLockSlim) + Private Shared _registerLock As Object = New Object ''' ''' Close and drop all connections for current process and thread. @@ -22,39 +17,30 @@ Partial Public MustInherit Class Connection Dim processAndThreadConnections As Dictionary(Of Int32, Connection) Dim processAndThreadConnectionsKeys As Int32() Dim provider As DbConnection - ' A. read check begin - if register contains any connection records under process and thread key - Connection._registerLock.EnterUpgradeableReadLock() - ' check if register contains any connection records under process and thread key - If Connection._connectionsRegister.ContainsKey(processAndThreadKey) Then - ' B. write lock begin - to change register records under process and thread key - Connection._registerLock.EnterWriteLock() - ' A. read check end - if register contains any connection records under process and thread key - Connection._registerLock.ExitUpgradeableReadLock() - Try - ' store all connections for current process id and thread in local variable to close them - processAndThreadConnections = Connection._connectionsRegister(processAndThreadKey) - ' lets change the register - remove records under thread and process key - Connection._connectionsRegister.Remove(processAndThreadKey) - Connection._registerLocks.Remove(processAndThreadKey) - ' close all connections for current process na thread only through local variable - processAndThreadConnectionsKeys = DirectCast(processAndThreadConnections.Keys.ToArray().Clone(), Int32()) - For Each key As Int32 In processAndThreadConnectionsKeys - provider = processAndThreadConnections(key).Provider - processAndThreadConnections.Remove(key) - If provider.State = ConnectionState.Open Then - provider.Close() - provider.Dispose() - End If - Next - Catch ex As Exception - Databasic.Events.RaiseError(ex) - End Try - ' B. write lock end - to change register records under process and thread key - Connection._registerLock.ExitWriteLock() - Else - ' A. read check end - if register contains any connection records under process and thread key - Connection._registerLock.ExitUpgradeableReadLock() - End If + + SyncLock Connection._registerLock + If Connection._connectionsRegister.ContainsKey(processAndThreadKey) Then + Try + ' store all connections for current process id and thread in local variable to close them + processAndThreadConnections = Connection._connectionsRegister(processAndThreadKey) + ' lets change the register - remove records under thread and process key + Connection._connectionsRegister.Remove(processAndThreadKey) + ' close all connections for current process na thread only through local variable + processAndThreadConnectionsKeys = DirectCast(processAndThreadConnections.Keys.ToArray().Clone(), Int32()) + For Each key As Int32 In processAndThreadConnectionsKeys + provider = processAndThreadConnections(key).Provider + processAndThreadConnections.Remove(key) + If provider.State = ConnectionState.Open Then + provider.Close() + provider.Dispose() + End If + Next + Catch ex As Exception + Databasic.Events.RaiseError(ex) + End Try + End If + End SyncLock + End Sub ''' @@ -92,66 +78,38 @@ Partial Public MustInherit Class Connection Public Shared Sub Close(connectionIndex As Int32, processId As Int32, threadId As Int32) Dim processAndThreadKey = $"{processId}_{threadId}" Dim processAndThreadConnections As Dictionary(Of Int32, Connection) - Dim processAndThreadLock As ReaderWriterLockSlim Dim provider As DbConnection - ' A. read check begin - if register contains any connection records under process and thread key - Connection._registerLock.EnterUpgradeableReadLock() - If Connection._connectionsRegister.ContainsKey(processAndThreadKey) Then - ' store connections and lock for process and thread in local variables - processAndThreadConnections = Connection._connectionsRegister(processAndThreadKey) - processAndThreadLock = Connection._registerLocks(processAndThreadKey) - ' B. read check begin - if connection record under process and thread key contains connection under called index - processAndThreadLock.EnterUpgradeableReadLock() - ' check if connection record under process and thread key contains connection under called index - If processAndThreadConnections.ContainsKey(connectionIndex) Then - ' connection record under process and thread key contains connection under called index - If processAndThreadConnections.Count = 1 Then - ' connection is only one - remove whole process and thread record from registry - ' D. write lock begin - remove connection records with one connection under thread and process key - Connection._registerLock.EnterWriteLock() - ' B. read check end - if connection record under process and thread key contains connection under called index - processAndThreadLock.ExitUpgradeableReadLock() - ' A. read check end - if register contains any connection records under process and thread key - Connection._registerLock.ExitUpgradeableReadLock() - ' remove and close connection under called index - provider = processAndThreadConnections(connectionIndex).Provider - processAndThreadConnections.Remove(connectionIndex) - If provider.State = ConnectionState.Open Then - provider.Close() - provider.Dispose() - End If - ' remove connection records with one connection under thread and process key - Connection._connectionsRegister.Remove(processAndThreadKey) - Connection._registerLocks.Remove(processAndThreadKey) - ' D. write lock end - remove connection records with one connection under thread and process key - Connection._registerLock.ExitWriteLock() - Else - ' there are still more connections - remove only one connection from process and thread id record - ' C. write lock begin - remove connection under called index in connections record under thread and process key - processAndThreadLock.EnterWriteLock() - ' B. read check end - if connection record under process and thread key contains connection under called index - processAndThreadLock.ExitUpgradeableReadLock() - ' remove and close connection under called index - provider = processAndThreadConnections(connectionIndex).Provider - processAndThreadConnections.Remove(connectionIndex) - If provider.State = ConnectionState.Open Then - provider.Close() - provider.Dispose() + + SyncLock Connection._registerLock + If Connection._connectionsRegister.ContainsKey(processAndThreadKey) Then + processAndThreadConnections = Connection._connectionsRegister(processAndThreadKey) + If processAndThreadConnections.ContainsKey(connectionIndex) Then + ' connection record under process and thread key contains connection under called index + If processAndThreadConnections.Count = 1 Then + ' connection is only one - remove whole process and thread record from registry + ' remove and close connection under called index + provider = processAndThreadConnections(connectionIndex).Provider + processAndThreadConnections.Remove(connectionIndex) + If provider.State = ConnectionState.Open Then + provider.Close() + provider.Dispose() + End If + ' remove connection records with one connection under thread and process key + Connection._connectionsRegister.Remove(processAndThreadKey) + Else + ' there are still more connections - remove only one connection from process and thread id record + ' B. read check end - if connection record under process and thread key contains connection under called index + ' remove and close connection under called index + provider = processAndThreadConnections(connectionIndex).Provider + processAndThreadConnections.Remove(connectionIndex) + If provider.State = ConnectionState.Open Then + provider.Close() + provider.Dispose() + End If End If - ' C. write lock begin - remove connection under called index in connections record under thread and process key - processAndThreadLock.ExitWriteLock() End If - Else - ' process and thread record doesn't contain any connection under called index - no change - ' B. read check end - if connection record under process and thread key contains connection under called index - processAndThreadLock.ExitUpgradeableReadLock() - ' A. read check end - if register contains any connection records under process and thread key - Connection._registerLock.ExitUpgradeableReadLock() End If - Else - ' A. read check end - if register contains any connection records under process and thread key - Connection._registerLock.ExitUpgradeableReadLock() - End If + End SyncLock End Sub ''' @@ -162,27 +120,27 @@ Partial Public MustInherit Class Connection Dim key As String Dim conns As Dictionary(Of Int32, Connection) Dim provider As DbConnection - Connection._registerLock.EnterWriteLock() - For i As Int32 = Connection._connectionsRegister.Keys.Count - 1 To 0 Step -1 - If Connection._connectionsRegister.Keys.Contains(i) Then - key = Connection._connectionsRegister.Keys(i) - Else - Continue For - End If - If key.IndexOf(keyBegin) = 0 Then - conns = Connection._connectionsRegister(key) - For Each item In conns - provider = item.Value.Provider - If provider.State = ConnectionState.Open Then - provider.Close() - provider.Dispose() - End If - Next - Connection._connectionsRegister.Remove(key) - Connection._registerLocks.Remove(key) - End If - Next - Connection._registerLock.ExitWriteLock() + + SyncLock Connection._registerLock + For i As Int32 = Connection._connectionsRegister.Keys.Count - 1 To 0 Step -1 + If Connection._connectionsRegister.Keys.Contains(i) Then + key = Connection._connectionsRegister.Keys(i) + Else + Continue For + End If + If key.IndexOf(keyBegin) = 0 Then + conns = Connection._connectionsRegister(key) + For Each item In conns + provider = item.Value.Provider + If provider.State = ConnectionState.Open Then + provider.Close() + provider.Dispose() + End If + Next + Connection._connectionsRegister.Remove(key) + End If + Next + End SyncLock End Sub End Class diff --git a/Connection/Opening.vb b/Connection/Opening.vb index 8ad1382..ba053e1 100644 --- a/Connection/Opening.vb +++ b/Connection/Opening.vb @@ -28,74 +28,23 @@ Partial Public MustInherit Class Connection End If Dim connection As Databasic.Connection = Nothing Dim processAndThreadKey As String = Databasic.Connection._getProcessAndThreadKey() - Dim processAndThreadLock As ReaderWriterLockSlim Dim processAndThreadConnections As Dictionary(Of Int32, Connection) - ' A. read check begin - if register contains any connection records under process and thread key - Databasic.Connection._registerLock.EnterUpgradeableReadLock() - ' check if register contains any connection records under process and thread key - If Databasic.Connection._connectionsRegister.ContainsKey(processAndThreadKey) Then - ' register contains any connection records under process and thread key - fill local variables to use them later - processAndThreadLock = Databasic.Connection._registerLocks(processAndThreadKey) - processAndThreadConnections = Databasic.Connection._connectionsRegister(processAndThreadKey) - ' C. read check begin - if process and thread record contains connection under called index - processAndThreadLock.EnterUpgradeableReadLock() - ' check if process and thread record contains connection under called index - If processAndThreadConnections.ContainsKey(connectionIndex.Value) Then - ' process and thread record contains connection under called index - let's read connection record - connection = processAndThreadConnections(connectionIndex.Value) - ' C. read check end - if process and thread record contains connection under called index - processAndThreadLock.ExitUpgradeableReadLock() + SyncLock Databasic.Connection._registerLock + If Databasic.Connection._connectionsRegister.ContainsKey(processAndThreadKey) Then + processAndThreadConnections = Databasic.Connection._connectionsRegister(processAndThreadKey) Else - ' process and thread record doesn't contain connection under called index - let's create new connection record - ' D. write lock begin - to change process and thread record under called index - processAndThreadLock.EnterWriteLock() - ' C. read check end - if process and thread record contains connection under called index - processAndThreadLock.ExitUpgradeableReadLock() - ' create new connection record - connection = Databasic.Connection._createAndOpen(connectionIndex.Value) - ' D. write lock end - to change process and thread record under called index - processAndThreadLock.ExitWriteLock() + processAndThreadConnections = New Dictionary(Of Int32, Connection)() + Databasic.Connection._connectionsRegister.Add(processAndThreadKey, processAndThreadConnections) End If - - ' A. read check end - if register contains any connection records under process and thread key - Databasic.Connection._registerLock.ExitUpgradeableReadLock() - Else - ' register doesn't contain any connection records under process and thread key - ' B. write lock begin - to change register records under process and thread key - Databasic.Connection._registerLock.EnterWriteLock() - ' A. read check end - if register contains any connection records under process and thread key - Databasic.Connection._registerLock.ExitUpgradeableReadLock() - processAndThreadLock = New ReaderWriterLockSlim() - - ' lets change the register - add connection records under thread and process key - processAndThreadConnections = New Dictionary(Of Int32, Connection)() - Databasic.Connection._registerLocks.Add(processAndThreadKey, processAndThreadLock) - Databasic.Connection._connectionsRegister.Add(processAndThreadKey, processAndThreadConnections) - - ' B. write lock end - to change register records under process and thread key - Databasic.Connection._registerLock.ExitWriteLock() - - ' C. read check begin - if process and thread record contains connection under called index - processAndThreadLock.EnterUpgradeableReadLock() - ' check if process and thread record contains connection under called index If processAndThreadConnections.ContainsKey(connectionIndex.Value) Then - ' process and thread record contains connection under called index - let's read connection record connection = processAndThreadConnections(connectionIndex.Value) - ' C. read check end - if process and thread record contains connection under called index - processAndThreadLock.ExitUpgradeableReadLock() Else - ' process and thread record doesn't contain connection under called index - let's create new connection record - ' D. write lock begin - to change process and thread record under called index - processAndThreadLock.EnterWriteLock() - ' C. read check end - if process and thread record contains connection under called index - processAndThreadLock.ExitUpgradeableReadLock() - ' create new connection record connection = Databasic.Connection._createAndOpen(connectionIndex.Value) - ' D. write lock end - to change process and thread record under called index - processAndThreadLock.ExitWriteLock() + processAndThreadConnections.Add(connectionIndex.Value, connection) End If - End If + End SyncLock + Return connection End Function diff --git a/MetaDescriptor.vb b/MetaDescriptor.vb index 3206ffe..6f6af89 100644 --- a/MetaDescriptor.vb +++ b/MetaDescriptor.vb @@ -5,7 +5,7 @@ Imports Databasic Public Class MetaDescriptor - Private Shared _lock As ReaderWriterLockSlim = New ReaderWriterLockSlim() + Private Shared _lock As Object = New Object() Private Shared _register As New Dictionary(Of String, MetaDescription) Friend Shared Function GetIndexerPropertyName(Type As Type) As String @@ -22,17 +22,14 @@ Public Class MetaDescriptor Friend Shared Function GetClassDescription(type As Type) As MetaDescription Dim result As MetaDescription = Nothing Dim key As String = type.Assembly.GetName().Name + ":" + type.FullName - MetaDescriptor._lock.EnterUpgradeableReadLock() - If MetaDescriptor._register.ContainsKey(key) Then - result = MetaDescriptor._register(key) - MetaDescriptor._lock.ExitUpgradeableReadLock() - Else - MetaDescriptor._lock.EnterWriteLock() - MetaDescriptor._lock.ExitUpgradeableReadLock() - result = MetaDescriptor._completeMetaDescription(type) - MetaDescriptor._register.Add(key, result) - MetaDescriptor._lock.ExitWriteLock() - End If + SyncLock MetaDescriptor._lock + If MetaDescriptor._register.ContainsKey(key) Then + result = MetaDescriptor._register(key) + Else + result = MetaDescriptor._completeMetaDescription(type) + MetaDescriptor._register.Add(key, result) + End If + End SyncLock Return result End Function @@ -41,24 +38,21 @@ Public Class MetaDescriptor Dim members As Dictionary(Of String, Databasic.MemberInfo) Dim meta As MetaDescription Dim key As String = type.Assembly.GetName().Name + ":" + type.FullName - MetaDescriptor._lock.EnterUpgradeableReadLock() - If MetaDescriptor._register.ContainsKey(key) Then - members = MetaDescriptor._register(key).ColumnsByCodeNames - If members.ContainsKey(codeColumnName) Then - result = members(codeColumnName) - End If - MetaDescriptor._lock.ExitUpgradeableReadLock() - Else - MetaDescriptor._lock.EnterWriteLock() - MetaDescriptor._lock.ExitUpgradeableReadLock() - meta = MetaDescriptor._completeMetaDescription(type) - MetaDescriptor._register.Add(key, meta) - members = meta.ColumnsByCodeNames - If members.ContainsKey(codeColumnName) Then - result = members(codeColumnName) + SyncLock MetaDescriptor._lock + If MetaDescriptor._register.ContainsKey(key) Then + members = MetaDescriptor._register(key).ColumnsByCodeNames + If members.ContainsKey(codeColumnName) Then + result = members(codeColumnName) + End If + Else + meta = MetaDescriptor._completeMetaDescription(type) + MetaDescriptor._register.Add(key, meta) + members = meta.ColumnsByCodeNames + If members.ContainsKey(codeColumnName) Then + result = members(codeColumnName) + End If End If - MetaDescriptor._lock.ExitWriteLock() - End If + End SyncLock Return result End Function @@ -66,18 +60,15 @@ Public Class MetaDescriptor Dim result As Dictionary(Of String, Databasic.MemberInfo) Dim meta As MetaDescription Dim key As String = type.Assembly.GetName().Name + ":" + type.FullName - MetaDescriptor._lock.EnterUpgradeableReadLock() - If MetaDescriptor._register.ContainsKey(key) Then - result = MetaDescriptor._register(key).ColumnsByDatabaseNames - MetaDescriptor._lock.ExitUpgradeableReadLock() - Else - MetaDescriptor._lock.EnterWriteLock() - MetaDescriptor._lock.ExitUpgradeableReadLock() - meta = MetaDescriptor._completeMetaDescription(type) - MetaDescriptor._register.Add(key, meta) - result = meta.ColumnsByDatabaseNames - MetaDescriptor._lock.ExitWriteLock() - End If + SyncLock MetaDescriptor._lock + If MetaDescriptor._register.ContainsKey(key) Then + result = MetaDescriptor._register(key).ColumnsByDatabaseNames + Else + meta = MetaDescriptor._completeMetaDescription(type) + MetaDescriptor._register.Add(key, meta) + result = meta.ColumnsByDatabaseNames + End If + End SyncLock Return result End Function @@ -85,18 +76,15 @@ Public Class MetaDescriptor Dim result As Dictionary(Of String, Databasic.MemberInfo) Dim meta As MetaDescription Dim key As String = type.Assembly.GetName().Name + ":" + type.FullName - MetaDescriptor._lock.EnterUpgradeableReadLock() - If MetaDescriptor._register.ContainsKey(key) Then - result = MetaDescriptor._register(key).ColumnsByCodeNames - MetaDescriptor._lock.ExitUpgradeableReadLock() - Else - MetaDescriptor._lock.EnterWriteLock() - MetaDescriptor._lock.ExitUpgradeableReadLock() - meta = MetaDescriptor._completeMetaDescription(type) - MetaDescriptor._register.Add(key, meta) - result = meta.ColumnsByCodeNames - MetaDescriptor._lock.ExitWriteLock() - End If + SyncLock MetaDescriptor._lock + If MetaDescriptor._register.ContainsKey(key) Then + result = MetaDescriptor._register(key).ColumnsByCodeNames + Else + meta = MetaDescriptor._completeMetaDescription(type) + MetaDescriptor._register.Add(key, meta) + result = meta.ColumnsByCodeNames + End If + End SyncLock Return result End Function @@ -104,23 +92,20 @@ Public Class MetaDescriptor Dim result As AllKeyColumns = New AllKeyColumns Dim meta As MetaDescription Dim key As String = type.Assembly.GetName().Name + ":" + type.FullName - MetaDescriptor._lock.EnterUpgradeableReadLock() - If MetaDescriptor._register.ContainsKey(key) Then - meta = MetaDescriptor._register(key) - result.PrimaryColumns = meta.PrimaryColumns - result.UniqueColumns = meta.UniqueColumns - result.AutoIncrementColumn = meta.AutoIncrementColumn - MetaDescriptor._lock.ExitUpgradeableReadLock() - Else - MetaDescriptor._lock.EnterWriteLock() - MetaDescriptor._lock.ExitUpgradeableReadLock() - meta = MetaDescriptor._completeMetaDescription(type) - MetaDescriptor._register.Add(key, meta) - result.PrimaryColumns = meta.PrimaryColumns - result.UniqueColumns = meta.UniqueColumns - result.AutoIncrementColumn = meta.AutoIncrementColumn - MetaDescriptor._lock.ExitWriteLock() - End If + SyncLock MetaDescriptor._lock + If MetaDescriptor._register.ContainsKey(key) Then + meta = MetaDescriptor._register(key) + result.PrimaryColumns = meta.PrimaryColumns + result.UniqueColumns = meta.UniqueColumns + result.AutoIncrementColumn = meta.AutoIncrementColumn + Else + meta = MetaDescriptor._completeMetaDescription(type) + MetaDescriptor._register.Add(key, meta) + result.PrimaryColumns = meta.PrimaryColumns + result.UniqueColumns = meta.UniqueColumns + result.AutoIncrementColumn = meta.AutoIncrementColumn + End If + End SyncLock Return result End Function @@ -128,29 +113,26 @@ Public Class MetaDescriptor Dim result As AllKeyColumns = New AllKeyColumns Dim meta As MetaDescription Dim key As String = type.Assembly.GetName().Name + ":" + type.FullName - MetaDescriptor._lock.EnterUpgradeableReadLock() - If MetaDescriptor._register.ContainsKey(key) Then - meta = MetaDescriptor._register(key) - If keyType = KeyType.Primary Then - result.PrimaryColumns = meta.PrimaryColumns - Else - result.UniqueColumns = meta.UniqueColumns - End If - result.AutoIncrementColumn = meta.AutoIncrementColumn - MetaDescriptor._lock.ExitUpgradeableReadLock() - Else - MetaDescriptor._lock.EnterWriteLock() - MetaDescriptor._lock.ExitUpgradeableReadLock() - meta = MetaDescriptor._completeMetaDescription(type) - MetaDescriptor._register.Add(key, meta) - If keyType = KeyType.Primary Then - result.PrimaryColumns = meta.PrimaryColumns + SyncLock MetaDescriptor._lock + If MetaDescriptor._register.ContainsKey(key) Then + meta = MetaDescriptor._register(key) + If keyType = KeyType.Primary Then + result.PrimaryColumns = meta.PrimaryColumns + Else + result.UniqueColumns = meta.UniqueColumns + End If + result.AutoIncrementColumn = meta.AutoIncrementColumn Else - result.UniqueColumns = meta.UniqueColumns + meta = MetaDescriptor._completeMetaDescription(type) + MetaDescriptor._register.Add(key, meta) + If keyType = KeyType.Primary Then + result.PrimaryColumns = meta.PrimaryColumns + Else + result.UniqueColumns = meta.UniqueColumns + End If + result.AutoIncrementColumn = meta.AutoIncrementColumn End If - result.AutoIncrementColumn = meta.AutoIncrementColumn - MetaDescriptor._lock.ExitWriteLock() - End If + End SyncLock Return result End Function