Skip to content

Commit 3096f5a

Browse files
authored
Spanner stale read (GoogleCloudPlatform#831)
1 parent 606c9b9 commit 3096f5a

File tree

4 files changed

+60
-49
lines changed

4 files changed

+60
-49
lines changed

spanner/cloud-client/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ limitations under the License.
5252
<dependency>
5353
<groupId>com.google.cloud</groupId>
5454
<artifactId>google-cloud-spanner</artifactId>
55-
<version>0.21.1-beta</version>
55+
<version>0.22.0-beta</version>
5656
<exclusions>
5757
<exclusion> <!-- exclude an old version of Guava -->
5858
<groupId>com.google.guava</groupId>

spanner/cloud-client/src/main/java/com/example/spanner/SpannerSample.java

+46-39
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,29 @@
1616

1717
package com.example.spanner;
1818

19-
// [START transaction_import]
2019
import static com.google.cloud.spanner.TransactionRunner.TransactionCallable;
21-
// [END transaction_import]
2220

2321
import com.google.cloud.spanner.Database;
2422
import com.google.cloud.spanner.DatabaseAdminClient;
2523
import com.google.cloud.spanner.DatabaseClient;
2624
import com.google.cloud.spanner.DatabaseId;
27-
// [START transaction_import]
2825
import com.google.cloud.spanner.Key;
29-
// [END transaction_import]
30-
// [START read_import]
3126
import com.google.cloud.spanner.KeySet;
32-
// [END read_import]
33-
// [START write_import]
3427
import com.google.cloud.spanner.Mutation;
35-
// [END write_import]
3628
import com.google.cloud.spanner.Operation;
37-
// [START read_only_transaction_import]
3829
import com.google.cloud.spanner.ReadOnlyTransaction;
39-
// [END read_only_transaction_import]
40-
// [START query_import]
4130
import com.google.cloud.spanner.ResultSet;
42-
// [END query_import]
4331
import com.google.cloud.spanner.Spanner;
4432
import com.google.cloud.spanner.SpannerOptions;
45-
// [START query_import]
4633
import com.google.cloud.spanner.Statement;
47-
// [END query_import]
48-
// [START transaction_import]
4934
import com.google.cloud.spanner.Struct;
35+
import com.google.cloud.spanner.TimestampBound;
5036
import com.google.cloud.spanner.TransactionContext;
51-
// [END transaction_import]
5237
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
53-
54-
// [START write_import]
55-
5638
import java.util.ArrayList;
57-
// [END write_import]
5839
import java.util.Arrays;
5940
import java.util.List;
41+
import java.util.concurrent.TimeUnit;
6042

6143
/**
6244
* Example code for using the Cloud Spanner API. This example demonstrates all the common
@@ -67,11 +49,14 @@
6749
* <li> Writing data using a read-write transaction.
6850
* <li> Using an index to read and execute SQL queries over data.
6951
* </ul>
70-
*
7152
*/
7253
public class SpannerSample {
73-
/** Class to contain singer sample data. */
54+
55+
/**
56+
* Class to contain singer sample data.
57+
*/
7458
static class Singer {
59+
7560
final long singerId;
7661
final String firstName;
7762
final String lastName;
@@ -83,8 +68,11 @@ static class Singer {
8368
}
8469
}
8570

86-
/** Class to contain album sample data. */
71+
/**
72+
* Class to contain album sample data.
73+
*/
8774
static class Album {
75+
8876
final long singerId;
8977
final long albumId;
9078
final String albumTitle;
@@ -116,22 +104,22 @@ static class Album {
116104

117105
static void createDatabase(DatabaseAdminClient dbAdminClient, DatabaseId id) {
118106
Operation<Database, CreateDatabaseMetadata> op = dbAdminClient
119-
.createDatabase(
120-
id.getInstanceId().getInstance(),
121-
id.getDatabase(),
122-
Arrays.asList(
123-
"CREATE TABLE Singers (\n"
124-
+ " SingerId INT64 NOT NULL,\n"
125-
+ " FirstName STRING(1024),\n"
126-
+ " LastName STRING(1024),\n"
127-
+ " SingerInfo BYTES(MAX)\n"
128-
+ ") PRIMARY KEY (SingerId)",
129-
"CREATE TABLE Albums (\n"
130-
+ " SingerId INT64 NOT NULL,\n"
131-
+ " AlbumId INT64 NOT NULL,\n"
132-
+ " AlbumTitle STRING(MAX)\n"
133-
+ ") PRIMARY KEY (SingerId, AlbumId),\n"
134-
+ " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"));
107+
.createDatabase(
108+
id.getInstanceId().getInstance(),
109+
id.getDatabase(),
110+
Arrays.asList(
111+
"CREATE TABLE Singers (\n"
112+
+ " SingerId INT64 NOT NULL,\n"
113+
+ " FirstName STRING(1024),\n"
114+
+ " LastName STRING(1024),\n"
115+
+ " SingerInfo BYTES(MAX)\n"
116+
+ ") PRIMARY KEY (SingerId)",
117+
"CREATE TABLE Albums (\n"
118+
+ " SingerId INT64 NOT NULL,\n"
119+
+ " AlbumId INT64 NOT NULL,\n"
120+
+ " AlbumTitle STRING(MAX)\n"
121+
+ ") PRIMARY KEY (SingerId, AlbumId),\n"
122+
+ " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"));
135123
Database db = op.waitFor().getResult();
136124
System.out.println("Created database [" + db.getId() + "]");
137125
}
@@ -413,6 +401,22 @@ static void readOnlyTransaction(DatabaseClient dbClient) {
413401
}
414402
// [END read_only_transaction]
415403

404+
// [START read_stale_data]
405+
static void readStaleData(DatabaseClient dbClient) {
406+
ResultSet resultSet =
407+
dbClient
408+
.singleUse(TimestampBound.ofExactStaleness(10, TimeUnit.SECONDS))
409+
.read("Albums",
410+
KeySet.all(),
411+
Arrays.asList("SingerId", "AlbumId", "MarketingBudget"));
412+
while (resultSet.next()) {
413+
System.out.printf(
414+
"%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1),
415+
resultSet.isNull(2) ? "NULL" : resultSet.getLong("MarketingBudget"));
416+
}
417+
}
418+
// [END read_stale_data]
419+
416420
static void run(DatabaseClient dbClient, DatabaseAdminClient dbAdminClient, String command,
417421
DatabaseId database) {
418422
switch (command) {
@@ -458,6 +462,9 @@ static void run(DatabaseClient dbClient, DatabaseAdminClient dbAdminClient, Stri
458462
case "readonlytransaction":
459463
readOnlyTransaction(dbClient);
460464
break;
465+
case "readstaledata":
466+
readStaleData(dbClient);
467+
break;
461468
default:
462469
printUsageAndExit();
463470
}

spanner/cloud-client/src/test/java/com/example/spanner/QuickstartSampleIT.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@
1818

1919
import static com.google.common.truth.Truth.assertThat;
2020

21+
import java.io.ByteArrayOutputStream;
22+
import java.io.PrintStream;
2123
import org.junit.After;
2224
import org.junit.Before;
2325
import org.junit.Test;
2426
import org.junit.runner.RunWith;
2527
import org.junit.runners.JUnit4;
2628

27-
import java.io.ByteArrayOutputStream;
28-
import java.io.PrintStream;
29-
3029
/**
3130
* Tests for quickstart sample.
3231
*/

spanner/cloud-client/src/test/java/com/example/spanner/SpannerSampleIT.java

+11-6
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@
2323
import com.google.cloud.spanner.Spanner;
2424
import com.google.cloud.spanner.SpannerOptions;
2525

26+
import java.io.ByteArrayOutputStream;
27+
import java.io.PrintStream;
2628
import org.junit.After;
2729
import org.junit.Before;
2830
import org.junit.Test;
2931
import org.junit.runner.RunWith;
3032
import org.junit.runners.JUnit4;
3133

32-
import java.io.ByteArrayOutputStream;
33-
import java.io.PrintStream;
34-
3534
/**
3635
* Unit tests for {@code SpannerSample}
3736
*/
@@ -43,6 +42,7 @@ public class SpannerSampleIT {
4342
private final String databaseId = System.getProperty("spanner.sample.database");
4443
DatabaseId dbId;
4544
DatabaseAdminClient dbClient;
45+
private long lastUpdateDataTimeInMillis;
4646

4747
private String runSample(String command) throws Exception {
4848
PrintStream stdOut = System.out;
@@ -83,12 +83,17 @@ public void testSample() throws Exception {
8383

8484
out = runSample("query");
8585
assertThat(out).contains("1 1 Total Junk");
86-
8786
runSample("addmarketingbudget");
87+
88+
// wait for 10 seconds to elapse and then run an update, and query for stale data
89+
lastUpdateDataTimeInMillis = System.currentTimeMillis();
90+
while (System.currentTimeMillis() < lastUpdateDataTimeInMillis + 11000) {
91+
Thread.sleep(1000);
92+
}
8893
runSample("update");
89-
94+
out = runSample("readstaledata");
95+
assertThat(out).contains("1 1 NULL");
9096
runSample("writetransaction");
91-
9297
out = runSample("querymarketingbudget");
9398
assertThat(out).contains("1 1 300000");
9499
assertThat(out).contains("2 2 300000");

0 commit comments

Comments
 (0)