1
16 package com.zaxxer.hikari.pool;
17
18 import com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry;
19 import com.zaxxer.hikari.util.FastList;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import java.sql.Connection;
24 import java.sql.SQLException;
25 import java.sql.Statement;
26 import java.util.concurrent.ScheduledFuture;
27 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
28
29 import static com.zaxxer.hikari.util.ClockSource.*;
30
31
36 final class PoolEntry implements IConcurrentBagEntry
37 {
38 private static final Logger LOGGER = LoggerFactory.getLogger(PoolEntry.class);
39 private static final AtomicIntegerFieldUpdater<PoolEntry> stateUpdater;
40
41 Connection connection;
42 long lastAccessed;
43 long lastBorrowed;
44
45 @SuppressWarnings("FieldCanBeLocal")
46 private volatile int state = 0;
47 private volatile boolean evict;
48
49 private volatile ScheduledFuture<?> endOfLife;
50
51 private final FastList<Statement> openStatements;
52 private final HikariPool hikariPool;
53
54 private final boolean isReadOnly;
55 private final boolean isAutoCommit;
56
57 static
58 {
59 stateUpdater = AtomicIntegerFieldUpdater.newUpdater(PoolEntry.class, "state");
60 }
61
62 PoolEntry(final Connection connection, final PoolBase pool, final boolean isReadOnly, final boolean isAutoCommit)
63 {
64 this.connection = connection;
65 this.hikariPool = (HikariPool) pool;
66 this.isReadOnly = isReadOnly;
67 this.isAutoCommit = isAutoCommit;
68 this.lastAccessed = currentTime();
69 this.openStatements = new FastList<>(Statement.class, 16);
70 }
71
72
77 void recycle(final long lastAccessed)
78 {
79 if (connection != null) {
80 this.lastAccessed = lastAccessed;
81 hikariPool.recycle(this);
82 }
83 }
84
85
90 void setFutureEol(final ScheduledFuture<?> endOfLife)
91 {
92 this.endOfLife = endOfLife;
93 }
94
95 Connection createProxyConnection(final ProxyLeakTask leakTask, final long now)
96 {
97 return ProxyFactory.getProxyConnection(this, connection, openStatements, leakTask, now, isReadOnly, isAutoCommit);
98 }
99
100 void resetConnectionState(final ProxyConnection proxyConnection, final int dirtyBits) throws SQLException
101 {
102 hikariPool.resetConnectionState(connection, proxyConnection, dirtyBits);
103 }
104
105 String getPoolName()
106 {
107 return hikariPool.toString();
108 }
109
110 boolean isMarkedEvicted()
111 {
112 return evict;
113 }
114
115 void markEvicted()
116 {
117 this.evict = true;
118 }
119
120 void evict(final String closureReason)
121 {
122 hikariPool.closeConnection(this, closureReason);
123 }
124
125
126 long getMillisSinceBorrowed()
127 {
128 return elapsedMillis(lastBorrowed);
129 }
130
131 PoolBase getPoolBase()
132 {
133 return hikariPool;
134 }
135
136
137 @Override
138 public String toString()
139 {
140 final long now = currentTime();
141 return connection
142 + ", accessed " + elapsedDisplayString(lastAccessed, now) + " ago, "
143 + stateToString();
144 }
145
146
147
148
149
150
151 @Override
152 public int getState()
153 {
154 return stateUpdater.get(this);
155 }
156
157
158 @Override
159 public boolean compareAndSet(int expect, int update)
160 {
161 return stateUpdater.compareAndSet(this, expect, update);
162 }
163
164
165 @Override
166 public void setState(int update)
167 {
168 stateUpdater.set(this, update);
169 }
170
171 Connection close()
172 {
173 ScheduledFuture<?> eol = endOfLife;
174 if (eol != null && !eol.isDone() && !eol.cancel(false)) {
175 LOGGER.warn("{} - maxLifeTime expiration task cancellation unexpectedly returned false for connection {}", getPoolName(), connection);
176 }
177
178 Connection con = connection;
179 connection = null;
180 endOfLife = null;
181 return con;
182 }
183
184 private String stateToString()
185 {
186 switch (state) {
187 case STATE_IN_USE:
188 return "IN_USE";
189 case STATE_NOT_IN_USE:
190 return "NOT_IN_USE";
191 case STATE_REMOVED:
192 return "REMOVED";
193 case STATE_RESERVED:
194 return "RESERVED";
195 default:
196 return "Invalid";
197 }
198 }
199 }
200