Skip to content

Commit 004b33e

Browse files
committed
use copy on write
1 parent 15eff92 commit 004b33e

2 files changed

Lines changed: 54 additions & 62 deletions

File tree

java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import java.sql.Statement;
6767
import java.time.Duration;
6868
import java.util.ArrayList;
69+
import java.util.Collections;
6970
import java.util.ConcurrentModificationException;
7071
import java.util.List;
7172
import java.util.Map;
@@ -76,7 +77,6 @@
7677
import java.util.concurrent.Executor;
7778
import java.util.concurrent.ExecutorService;
7879
import java.util.concurrent.TimeUnit;
79-
import java.util.concurrent.locks.ReentrantLock;
8080

8181
/**
8282
* An implementation of {@link java.sql.Connection} for establishing a connection with BigQuery and
@@ -87,7 +87,6 @@
8787
public class BigQueryConnection extends BigQueryNoOpsConnection {
8888

8989
private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString());
90-
private final ReentrantLock queryPropertiesLock = new ReentrantLock();
9190
String connectionClassName = this.toString();
9291
private final String connectionId;
9392
private static final String DEFAULT_JDBC_TOKEN_VALUE = "Google-BigQuery-JDBC-Driver";
@@ -179,7 +178,7 @@ public class BigQueryConnection extends BigQueryNoOpsConnection {
179178
// transactionStarted is false by default.
180179
// when autocommit is false transaction starts and session is initialized.
181180
boolean transactionStarted;
182-
ConnectionProperty sessionInfoConnectionProperty;
181+
volatile ConnectionProperty sessionInfoConnectionProperty;
183182
boolean isClosed;
184183
DatasetId defaultDataset;
185184
String location;
@@ -199,7 +198,7 @@ public class BigQueryConnection extends BigQueryNoOpsConnection {
199198
long destinationDatasetExpirationTime;
200199
String kmsKeyName;
201200
String universeDomain;
202-
List<ConnectionProperty> queryProperties;
201+
private volatile List<ConnectionProperty> queryProperties;
203202
Map<String, String> authProperties;
204203
Map<String, String> overrideProperties;
205204
Map<String, String> proxyProperties;
@@ -615,12 +614,7 @@ String getKmsKeyName() {
615614
}
616615

617616
List<ConnectionProperty> getQueryProperties() {
618-
queryPropertiesLock.lock();
619-
try {
620-
return this.queryProperties;
621-
} finally {
622-
queryPropertiesLock.unlock();
623-
}
617+
return this.queryProperties;
624618
}
625619

626620
public String getLocation() {
@@ -705,30 +699,29 @@ private void beginTransaction() {
705699
}
706700
}
707701

708-
void updateSessionInfo(String sessionId) {
702+
synchronized void updateSessionInfo(String sessionId) {
709703
if (sessionId != null && !sessionId.isEmpty()) {
710-
queryPropertiesLock.lock();
711-
try {
712-
if (this.sessionInfoConnectionProperty == null
713-
|| !sessionId.equals(this.sessionInfoConnectionProperty.getValue())) {
714-
this.sessionInfoConnectionProperty =
715-
ConnectionProperty.newBuilder().setKey("session_id").setValue(sessionId).build();
716-
boolean found = false;
717-
if (this.queryProperties != null) {
718-
for (int i = 0; i < this.queryProperties.size(); i++) {
719-
if ("session_id".equalsIgnoreCase(this.queryProperties.get(i).getKey())) {
720-
this.queryProperties.set(i, this.sessionInfoConnectionProperty);
721-
found = true;
722-
break;
723-
}
724-
}
725-
if (!found) {
726-
this.queryProperties.add(this.sessionInfoConnectionProperty);
727-
}
704+
if (this.sessionInfoConnectionProperty == null
705+
|| !sessionId.equals(this.sessionInfoConnectionProperty.getValue())) {
706+
ConnectionProperty sessionProperty =
707+
ConnectionProperty.newBuilder().setKey("session_id").setValue(sessionId).build();
708+
this.sessionInfoConnectionProperty = sessionProperty;
709+
List<ConnectionProperty> updated =
710+
this.queryProperties != null
711+
? new ArrayList<>(this.queryProperties)
712+
: new ArrayList<>();
713+
boolean found = false;
714+
for (int i = 0; i < updated.size(); i++) {
715+
if ("session_id".equalsIgnoreCase(updated.get(i).getKey())) {
716+
updated.set(i, sessionProperty);
717+
found = true;
718+
break;
728719
}
729720
}
730-
} finally {
731-
queryPropertiesLock.unlock();
721+
if (!found) {
722+
updated.add(sessionProperty);
723+
}
724+
this.queryProperties = Collections.unmodifiableList(updated);
732725
}
733726
}
734727
}
@@ -746,12 +739,7 @@ boolean isUnsupportedHTAPIFallback() {
746739
}
747740

748741
public ConnectionProperty getSessionInfoConnectionProperty() {
749-
queryPropertiesLock.lock();
750-
try {
751-
return this.sessionInfoConnectionProperty;
752-
} finally {
753-
queryPropertiesLock.unlock();
754-
}
742+
return this.sessionInfoConnectionProperty;
755743
}
756744

757745
boolean isEnableHighThroughputAPI() {
@@ -1214,7 +1202,7 @@ private List<ConnectionProperty> convertMapToConnectionPropertiesList(
12141202
.build());
12151203
}
12161204
}
1217-
return connectionProperties;
1205+
return Collections.unmodifiableList(connectionProperties);
12181206
}
12191207

12201208
void removeStatement(Statement statement) {

java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryStatement.java

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ StatementType getStatementType(QueryJobConfiguration queryJobConfiguration) thro
330330
LOG.finer("++enter++");
331331
// BQ Read-only tokens are not recommended to use, they have a lot of known flaws.
332332
// We're supporting them in a limited capacity, for pure SELECT statements.
333-
if (this.connection.isReadOnlyTokenUsed()) {
333+
if (this.connection != null && this.connection.isReadOnlyTokenUsed()) {
334334
LOG.warning(
335335
"Read-only token detected, skipping dry run and assuming StatementType is SELECT.");
336336
return StatementType.SELECT;
@@ -1474,30 +1474,34 @@ QueryJobConfiguration.Builder getJobConfig(String query) {
14741474
queryConfigBuilder.setUseQueryCache(this.querySettings.getUseQueryCache());
14751475
queryConfigBuilder.setMaxResults(this.querySettings.getMaxResultPerPage());
14761476

1477-
ConnectionProperty sessionProperty = this.connection.getSessionInfoConnectionProperty();
1478-
boolean isSessionEnabled = this.connection.isSessionEnabled();
1479-
List<ConnectionProperty> queryProperties = this.connection.getQueryProperties();
1480-
1481-
if (isSessionEnabled) {
1482-
if (sessionProperty != null) {
1483-
List<ConnectionProperty> props =
1484-
queryProperties != null ? new ArrayList<>(queryProperties) : new ArrayList<>();
1485-
boolean hasSessionId =
1486-
props.stream().anyMatch(cp -> "session_id".equalsIgnoreCase(cp.getKey()));
1487-
if (!hasSessionId) {
1488-
props.add(sessionProperty);
1489-
}
1490-
queryConfigBuilder.setConnectionProperties(props);
1491-
} else {
1492-
queryConfigBuilder.setCreateSession(true);
1493-
if (queryProperties != null && !queryProperties.isEmpty()) {
1494-
queryConfigBuilder.setConnectionProperties(queryProperties);
1495-
}
1496-
}
1497-
} else {
1498-
if (queryProperties != null && !queryProperties.isEmpty()) {
1499-
queryConfigBuilder.setConnectionProperties(queryProperties);
1477+
ConnectionProperty sessionProperty =
1478+
this.connection != null
1479+
? this.connection.getSessionInfoConnectionProperty()
1480+
: this.querySettings.getSessionInfoConnectionProperty();
1481+
boolean isSessionEnabled =
1482+
this.connection != null
1483+
? this.connection.isSessionEnabled()
1484+
: this.querySettings.isEnableSession();
1485+
List<ConnectionProperty> queryProperties =
1486+
this.connection != null
1487+
? this.connection.getQueryProperties()
1488+
: this.querySettings.getQueryProperties();
1489+
1490+
List<ConnectionProperty> props =
1491+
queryProperties != null ? new ArrayList<>(queryProperties) : new ArrayList<>();
1492+
1493+
if (sessionProperty != null) {
1494+
boolean hasSessionId =
1495+
props.stream().anyMatch(cp -> "session_id".equalsIgnoreCase(cp.getKey()));
1496+
if (!hasSessionId) {
1497+
props.add(sessionProperty);
15001498
}
1499+
} else if (isSessionEnabled) {
1500+
queryConfigBuilder.setCreateSession(true);
1501+
}
1502+
1503+
if (!props.isEmpty()) {
1504+
queryConfigBuilder.setConnectionProperties(props);
15011505
}
15021506
if (this.querySettings.getKmsKeyName() != null) {
15031507
EncryptionConfiguration encryption =

0 commit comments

Comments
 (0)