25
25
import io .netty .channel .pool .ChannelPoolHandler ;
26
26
import io .netty .util .concurrent .EventExecutor ;
27
27
28
+ import java .util .HashMap ;
28
29
import java .util .Map ;
29
- import java .util .concurrent .ConcurrentHashMap ;
30
- import java .util .concurrent .atomic .AtomicInteger ;
30
+ import java .util .concurrent .locks .Lock ;
31
+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
32
+ import java .util .function .Supplier ;
31
33
32
34
import org .neo4j .driver .internal .BoltServerAddress ;
33
35
import org .neo4j .driver .internal .messaging .BoltProtocol ;
40
42
41
43
public class NettyChannelTracker implements ChannelPoolHandler
42
44
{
43
- private final Map <BoltServerAddress ,AtomicInteger > addressToInUseChannelCount = new ConcurrentHashMap <>();
44
- private final Map <BoltServerAddress ,AtomicInteger > addressToIdleChannelCount = new ConcurrentHashMap <>();
45
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock ();
46
+ private final Lock read = lock .readLock ();
47
+ private final Lock write = lock .writeLock ();
48
+ private final Map <BoltServerAddress ,Integer > addressToInUseChannelCount = new HashMap <>();
49
+ private final Map <BoltServerAddress ,Integer > addressToIdleChannelCount = new HashMap <>();
45
50
private final Logger log ;
46
51
private final MetricsListener metricsListener ;
47
52
private final ChannelFutureListener closeListener = future -> channelClosed ( future .channel () );
@@ -62,21 +67,28 @@ public NettyChannelTracker( MetricsListener metricsListener, ChannelGroup channe
62
67
@ Override
63
68
public void channelReleased ( Channel channel )
64
69
{
65
- log .debug ( "Channel [0x%s] released back to the pool" , channel .id () );
66
- decrementInUse ( channel );
67
- incrementIdle ( channel );
70
+ doInWriteLock ( () ->
71
+ {
72
+ decrementInUse ( channel );
73
+ incrementIdle ( channel );
74
+ } );
75
+
68
76
channel .closeFuture ().addListener ( closeListener );
77
+ log .debug ( "Channel [0x%s] released back to the pool" , channel .id () );
69
78
}
70
79
71
80
@ Override
72
81
public void channelAcquired ( Channel channel )
73
82
{
74
- log .debug ( "Channel [%s] acquired from the pool. Local address: %s, remote address: %s" ,
75
- channel .id (), channel .localAddress (), channel .remoteAddress () );
83
+ doInWriteLock ( () ->
84
+ {
85
+ incrementInUse ( channel );
86
+ decrementIdle ( channel );
87
+ } );
76
88
77
- incrementInUse ( channel );
78
- decrementIdle ( channel );
79
89
channel .closeFuture ().removeListener ( closeListener );
90
+ log .debug ( "Channel [0x%s] acquired from the pool. Local address: %s, remote address: %s" , channel .id (), channel .localAddress (),
91
+ channel .remoteAddress () );
80
92
}
81
93
82
94
@ Override
@@ -87,13 +99,12 @@ public void channelCreated( Channel channel )
87
99
88
100
public void channelCreated ( Channel channel , ListenerEvent creatingEvent )
89
101
{
90
- log .debug ( "Channel [%s] created. Local address: %s, remote address: %s" ,
91
- channel .id (), channel .localAddress (), channel .remoteAddress () );
102
+ doInWriteLock ( () -> incrementInUse ( channel ) );
92
103
93
- incrementInUse ( channel );
94
104
metricsListener .afterCreated ( serverAddress ( channel ), creatingEvent );
95
105
96
106
allChannels .add ( channel );
107
+ log .debug ( "Channel [0x%s] created. Local address: %s, remote address: %s" , channel .id (), channel .localAddress (), channel .remoteAddress () );
97
108
}
98
109
99
110
public ListenerEvent channelCreating ( BoltServerAddress address )
@@ -110,20 +121,18 @@ public void channelFailedToCreate( BoltServerAddress address )
110
121
111
122
public void channelClosed ( Channel channel )
112
123
{
113
- decrementIdle ( channel );
124
+ doInWriteLock ( () -> decrementIdle ( channel ) );
114
125
metricsListener .afterClosed ( serverAddress ( channel ) );
115
126
}
116
127
117
128
public int inUseChannelCount ( BoltServerAddress address )
118
129
{
119
- AtomicInteger count = addressToInUseChannelCount .get ( address );
120
- return count == null ? 0 : count .get ();
130
+ return retrieveInReadLock ( () -> addressToInUseChannelCount .getOrDefault ( address , 0 ) );
121
131
}
122
132
123
133
public int idleChannelCount ( BoltServerAddress address )
124
134
{
125
- AtomicInteger count = addressToIdleChannelCount .get ( address );
126
- return count == null ? 0 : count .get ();
135
+ return retrieveInReadLock ( () -> addressToIdleChannelCount .getOrDefault ( address , 0 ) );
127
136
}
128
137
129
138
public void prepareToCloseChannels ()
@@ -139,7 +148,8 @@ public void prepareToCloseChannels()
139
148
{
140
149
// only logging it
141
150
log .debug ( "Failed to prepare to close Channel %s due to error %s. " +
142
- "It is safe to ignore this error as the channel will be closed despite if it is successfully prepared to close or not." , channel , e .getMessage () );
151
+ "It is safe to ignore this error as the channel will be closed despite if it is successfully prepared to close or not." , channel ,
152
+ e .getMessage () );
143
153
}
144
154
}
145
155
}
@@ -164,22 +174,47 @@ private void decrementIdle( Channel channel )
164
174
decrement ( channel , addressToIdleChannelCount );
165
175
}
166
176
167
- private void increment ( Channel channel , Map <BoltServerAddress ,AtomicInteger > countMap )
177
+ private void increment ( Channel channel , Map <BoltServerAddress ,Integer > countMap )
168
178
{
169
179
BoltServerAddress address = serverAddress ( channel );
170
- AtomicInteger count = countMap .computeIfAbsent ( address , k -> new AtomicInteger () );
171
- count . incrementAndGet ( );
180
+ Integer count = countMap .computeIfAbsent ( address , k -> 0 );
181
+ countMap . put ( address , count + 1 );
172
182
}
173
183
174
- private void decrement ( Channel channel , Map <BoltServerAddress ,AtomicInteger > countMap )
184
+ private void decrement ( Channel channel , Map <BoltServerAddress ,Integer > countMap )
175
185
{
176
186
BoltServerAddress address = serverAddress ( channel );
177
- AtomicInteger count = countMap .get ( address );
178
- if ( count == null )
187
+ if ( !countMap .containsKey ( address ) )
179
188
{
180
- System .out .println ( countMap );
181
189
throw new IllegalStateException ( "No count exist for address '" + address + "'" );
182
190
}
183
- count .decrementAndGet ();
191
+ Integer count = countMap .get ( address );
192
+ countMap .put ( address , count - 1 );
193
+ }
194
+
195
+ private void doInWriteLock ( Runnable work )
196
+ {
197
+ try
198
+ {
199
+ write .lock ();
200
+ work .run ();
201
+ }
202
+ finally
203
+ {
204
+ write .unlock ();
205
+ }
206
+ }
207
+
208
+ private <T > T retrieveInReadLock ( Supplier <T > work )
209
+ {
210
+ try
211
+ {
212
+ read .lock ();
213
+ return work .get ();
214
+ }
215
+ finally
216
+ {
217
+ read .unlock ();
218
+ }
184
219
}
185
220
}
0 commit comments