use of com.mysql.cj.xdevapi.Collection in project aws-mysql-jdbc by awslabs.
the class DevApiSample method documentWalkthrough.
public static void documentWalkthrough(Schema schema) {
// document walthrough
Collection coll = schema.createCollection("myBooks", /* reuseExisting? */
true);
DbDoc newDoc = new DbDocImpl().add("isbn", new JsonString().setValue("12345"));
newDoc.add("title", new JsonString().setValue("Effi Briest"));
newDoc.add("author", new JsonString().setValue("Theodor Fontane"));
newDoc.add("currentlyReadingPage", new JsonNumber().setValue(String.valueOf(42)));
coll.add(newDoc).execute();
// note: "$" prefix for document paths is optional. "$.title.somethingElse[0]" is the same as "title.somethingElse[0]" in document expressions
DocResult docs = coll.find("$.title = 'Effi Briest' and $.currentlyReadingPage > 10").execute();
DbDoc book = docs.next();
System.err.println("Currently reading " + ((JsonString) book.get("title")).getString() + " on page " + ((JsonNumber) book.get("currentlyReadingPage")).getInteger());
// increment the page number and fetch it again
coll.modify("$.isbn = 12345").set("$.currentlyReadingPage", ((JsonNumber) book.get("currentlyReadingPage")).getInteger() + 1).execute();
docs = coll.find("$.title = 'Effi Briest' and $.currentlyReadingPage > 10").execute();
book = docs.next();
System.err.println("Currently reading " + ((JsonString) book.get("title")).getString() + " on page " + ((JsonNumber) book.get("currentlyReadingPage")).getInteger());
// remove the doc
coll.remove("true").execute();
System.err.println("Number of books in collection: " + coll.count());
schema.dropCollection(coll.getName());
}
use of com.mysql.cj.xdevapi.Collection in project aws-mysql-jdbc by awslabs.
the class SchemaTest method testCreateCollectionWithOptions.
@Test
public void testCreateCollectionWithOptions() {
String collName1 = "testCreateCollection1";
String collName2 = "testCreateCollection2";
dropCollection(collName1);
dropCollection(collName2);
String sch1 = "{" + "\"id\":\"http://json-schema.org/geo\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + "\"description\":\"A geographical coordinate\",\"type\":\"object\",\"properties\":{\"latitude\":{\"type\":\"number\"}," + "\"longitude\":{\"type\":\"number\"}},\"required\":[\"latitude\",\"longitude\"]}";
String sch2 = "{\"id\":\"http://json-schema.org/geo\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + "\"description\":\"The geographical coordinate\",\"type\":\"object\",\"properties\":{\"latitude\":{\"type\":\"number\"}," + "\"longitude\":{\"type\":\"number\"}},\"required\":[\"latitude\",\"longitude\"]}";
String sch3 = "{\"id\":\"http://json-schema.org/idx\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + "\"type\":\"object\",\"properties\":{\"index\":{\"type\":\"number\"}},\"required\":[\"index\"]}";
try {
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.19"))) {
// TSFR2b.1: Call createCollection with both level and schema options are set. Ensure that given values are set on server.
Collection coll = //
this.schema.createCollection(//
collName1, new CreateCollectionOptions().setReuseExisting(false).setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema(sch1)));
SqlResult res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
String def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertTrue(def.contains(sch1));
coll.add("{\"latitude\": 20, \"longitude\": 30}").execute();
Collection coll1 = //
this.schema.createCollection(//
collName1, new CreateCollectionOptions().setReuseExisting(true).setValidation(new Validation().setLevel(ValidationLevel.OFF).setSchema(sch1)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertTrue(def.contains(sch1));
coll1 = //
this.schema.createCollection(//
collName1, new CreateCollectionOptions().setReuseExisting(true).setValidation(new Validation().setSchema(sch2)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertFalse(def.contains(sch2));
assertTrue(def.contains(sch1));
coll1 = //
this.schema.createCollection(//
collName1, new CreateCollectionOptions().setReuseExisting(true).setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema(sch1)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertFalse(def.contains(sch2));
assertTrue(def.contains(sch1));
coll1.add("{\"latitude\": 30, \"longitude\": 40}").execute();
// TSFR6d: Call createCollection(String collectionName) and createCollection(String collectionName, boolean reuseExisting) methods against server implementing WL#12965 and ensure they work as before.
this.schema.createCollection(collName2);
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
def = res.next().getString(1);
assertTrue(def.contains("NOT ENFORCED"));
dropCollection(collName2);
this.schema.createCollection(collName2, new CreateCollectionOptions().setReuseExisting(false));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
def = res.next().getString(1);
assertTrue(def.contains("NOT ENFORCED"));
dropCollection(collName2);
assertEquals(MysqlErrorNumbers.ER_TABLE_EXISTS_ERROR, assertThrows(XProtocolError.class, new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.createCollection(collName1);
return null;
}
}).getErrorCode());
assertEquals(MysqlErrorNumbers.ER_TABLE_EXISTS_ERROR, assertThrows(XProtocolError.class, new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.createCollection(collName1, false);
return null;
}
}).getErrorCode());
assertEquals(MysqlErrorNumbers.ER_TABLE_EXISTS_ERROR, assertThrows(XProtocolError.class, new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.createCollection(collName1, new CreateCollectionOptions().setReuseExisting(false));
return null;
}
}).getErrorCode());
Collection coll2 = this.schema.createCollection(collName1, true);
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertTrue(def.contains(sch1));
coll2 = this.schema.createCollection(collName1, new CreateCollectionOptions().setReuseExisting(true));
assertEquals(coll, coll2);
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertTrue(def.contains(sch1));
// TSFR2b.2: Call createCollection with only schema option. Ensure the default level value is set on server.
dropCollection(collName2);
this.schema.createCollection(collName2, new CreateCollectionOptions().setValidation(new Validation().setSchema(sch1)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
def = res.next().getString(1);
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.20"))) {
// After the Bug#30830962 fix when schema is set and level is omitted xplugin sets it to "strict"
assertFalse(def.contains("NOT ENFORCED"));
} else {
assertTrue(def.contains("NOT ENFORCED"));
}
assertTrue(def.contains(sch1));
// TSFR2b.3: Call createCollection with only level option. Ensure the default schema and the given level are set on server.
dropCollection(collName2);
this.schema.createCollection(collName2, new CreateCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertTrue(def.contains("{\"type\":\"object\"}"));
// TSFR5: Create collection with json schema and level `strict`. Try to insert document which doesn't match this schema, ensure that a server error being raised.
assertThrows(XProtocolError.class, "ERROR 5180 \\(HY000\\) Document is not valid according to the schema assigned to collection.*", new Callable<Void>() {
public Void call() throws Exception {
coll.add("{\"_id\": 1}").execute();
return null;
}
});
// TSFR2a.1: Call modifyCollection with only level option. Ensure it's changed on server.
this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.OFF)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertTrue(def.contains("NOT ENFORCED"));
assertTrue(def.contains(sch1));
this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertTrue(def.contains(sch1));
// TSFR2a.2: Call modifyCollection with only schema option. Ensure it's changed on server.
// sch2 is compatible with sch1
this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setSchema(sch2)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertFalse(def.contains(sch1));
assertTrue(def.contains(sch2));
assertThrows(XProtocolError.class, "ERROR 5180 \\(HY000\\) Document is not valid according to the schema assigned to collection.*", new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.modifyCollection(collName1, // sch3 is incompatible with sch1
new ModifyCollectionOptions().setValidation(new Validation().setSchema(sch3)));
return null;
}
});
// TSFR2a.3: Call modifyCollection with both level and schema options. Ensure they are changed on server.
this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.OFF).setSchema(sch3)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertTrue(def.contains("NOT ENFORCED"));
assertFalse(def.contains(sch2));
assertTrue(def.contains(sch3));
this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema(sch1)));
res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
def = res.next().getString(1);
assertFalse(def.contains("NOT ENFORCED"));
assertFalse(def.contains(sch3));
assertTrue(def.contains(sch1));
// TSFR2a.4: Call modifyCollection with neither level nor schema options are set. Ensure Connector/J throws the XProtocolError
assertThrows(XProtocolError.class, "ERROR 5020 \\(HY000\\) Arguments value used under \"validation\" must be an object with at least one field", new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.modifyCollection(collName1, null);
return null;
}
});
assertThrows(XProtocolError.class, "ERROR 5020 \\(HY000\\) Arguments value used under \"validation\" must be an object with at least one field", new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.modifyCollection(collName1, new ModifyCollectionOptions());
return null;
}
});
assertThrows(XProtocolError.class, "ERROR 5020 \\(HY000\\) Arguments value used under \"validation\" must be an object with at least one field", new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation()));
return null;
}
});
// TSFR4: Try to create collection with an invalid json schema. Ensure that a server error being raised.
assertThrows(XProtocolError.class, "ERROR 5182 \\(HY000\\) JSON validation schema .*", new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.createCollection("wrongSchema", new CreateCollectionOptions().setValidation(new Validation().setSchema("{\"id\": \"http://json-schema.org/geo\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + //
"\"description\":\"The geographical coordinate\",\"type\":\"object\",\"properties\":{\"latitude\":{" + // wrong type
"\"type\":\"blablabla\"" + "}},\"required\":[\"latitude\",\"foo\"]}")));
return null;
}
});
} else {
// for old servers
// TSFR6b: Call createCollection(collectionName, createCollectionOptions) method against server which doesn't support validation parameter for `create_collection` X Protocol command,
// eg. MySQL 5.7. Ensure that server responds with error code 5015 and that Connector/J wraps it to WrongArgumentException with message
// "The server doesn't support the requested operation. Please update the MySQL Server and or Client library".
assertThrows(WrongArgumentException.class, Messages.getString("Schema.CreateCollection"), new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.createCollection(collName1, new CreateCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema("{\"id\": \"http://json-schema.org/geo\",\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + "\"description\": \"A geographical coordinate\",\"type\": \"object\",\"properties\":" + "{\"latitude\": {\"type\": \"number\"},\"longitude\": {\"type\": \"number\"}}," + "\"required\": [\"latitude\", \"longitude\"]}")));
return null;
}
});
// TSFR6c: Call modifyCollection(String collectionName, ModifyCollectionOptions options) method against server which doesn't implement `modify_collection_options` X Protocol command,
// eg. MySQL 5.7. Ensure that server responds with error code 5157 and that Connector/J wraps it to WrongArgumentException with message
// "The server doesn't support the requested operation. Please update the MySQL Server and or Client library".
assertThrows(WrongArgumentException.class, Messages.getString("Schema.CreateCollection"), new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.OFF)));
return null;
}
});
// TSFR6a: Call createCollection(String collectionName) and createCollection(String collectionName, boolean reuseExisting) methods against servers not implementing WL#12965 and ensure they work as before.
// It's covered by testCreateCollection() test case.
}
} finally {
dropCollection(collName1);
dropCollection(collName2);
}
}
use of com.mysql.cj.xdevapi.Collection in project aws-mysql-jdbc by awslabs.
the class SchemaTest method testDropCollection.
@Test
public void testDropCollection() {
String collName = "testDropCollection";
dropCollection(collName);
Collection coll = this.schema.getCollection(collName);
assertEquals(DbObjectStatus.NOT_EXISTS, coll.existsInDatabase());
// dropping non-existing collection should not fail
this.schema.dropCollection(collName);
coll = this.schema.createCollection(collName);
assertEquals(DbObjectStatus.EXISTS, coll.existsInDatabase());
this.schema.dropCollection(collName);
// ensure that collection is dropped
coll = this.schema.getCollection(collName);
assertEquals(DbObjectStatus.NOT_EXISTS, coll.existsInDatabase());
assertThrows(XProtocolError.class, "Parameter 'collectionName' must not be null.", new Callable<Void>() {
public Void call() throws Exception {
SchemaTest.this.schema.dropCollection(null);
return null;
}
});
}
use of com.mysql.cj.xdevapi.Collection in project aws-mysql-jdbc by awslabs.
the class SessionTest method testBug97269.
/**
* Test fix for Bug#97269 (30438500), POSSIBLE BUG IN COM.MYSQL.CJ.XDEVAPI.STREAMINGDOCRESULTBUILDER.
*
* @throws Exception
*/
@Test
public void testBug97269() throws Exception {
Session sess = null;
try {
String message1 = "W1";
String message2 = "W2";
// create notice message buffers
Frame.Builder notice1 = Frame.newBuilder().setScope(Frame.Scope.LOCAL).setType(Frame.Type.WARNING_VALUE).setPayload(com.mysql.cj.x.protobuf.MysqlxNotice.Warning.newBuilder().setCode(MysqlErrorNumbers.ER_BAD_DB_ERROR).setMsg(message1).build().toByteString());
Frame.Builder notice2 = Frame.newBuilder().setScope(Frame.Scope.GLOBAL).setType(Frame.Type.WARNING_VALUE).setPayload(com.mysql.cj.x.protobuf.MysqlxNotice.Warning.newBuilder().setCode(MysqlErrorNumbers.ER_BAD_DB_ERROR).setMsg(message2).build().toByteString());
byte[] notice1Bytes = makeNoticeBytes(notice1.build());
byte[] notice2Bytes = makeNoticeBytes(notice2.build());
int size = notice1Bytes.length + notice2Bytes.length;
byte[] noticesBytes = new byte[size];
System.arraycopy(notice1Bytes, 0, noticesBytes, 0, notice1Bytes.length);
System.arraycopy(notice2Bytes, 0, noticesBytes, notice1Bytes.length, notice2Bytes.length);
InjectedSocketFactory.flushAllStaticData();
String url = this.baseUrl + (this.baseUrl.contains("?") ? "" : "?") + makeParam(PropertyKey.socketFactory, InjectedSocketFactory.class.getName(), !this.baseUrl.contains("?") || this.baseUrl.endsWith("?")) + makeParam(PropertyKey.xdevapiSslMode, XdevapiSslMode.DISABLED.toString()) + makeParam(PropertyKey.xdevapiCompression, Compression.DISABLED.toString()) + // to allow injection between result rows
makeParam(PropertyKey.useReadAheadInput, "false");
sess = this.fact.getSession(url);
SocketFactory sf = ((SessionImpl) sess).getSession().getProtocol().getSocketConnection().getSocketFactory();
assertTrue(InjectedSocketFactory.class.isAssignableFrom(sf.getClass()));
Collection collection = sess.getDefaultSchema().createCollection("testBug97269");
collection.add("{\"_id\":\"the_id\",\"g\":1}").execute();
// StreamingDocResultBuilder
InjectedSocketFactory.injectedBuffer = noticesBytes;
DocResult docs = collection.find().fields("$._id as _id, $.g as g, 1 + 1 as q").execute();
DbDoc doc = docs.next();
assertEquals("the_id", ((JsonString) doc.get("_id")).getString());
assertEquals(new Integer(1), ((JsonNumber) doc.get("g")).getInteger());
assertEquals(new Integer(2), ((JsonNumber) doc.get("q")).getInteger());
int cnt = 0;
for (Iterator<Warning> warn = docs.getWarnings(); warn.hasNext(); ) {
Warning w = warn.next();
if (w.getMessage().equals(message1) || w.getMessage().equals(message2)) {
cnt++;
}
}
assertEquals(2, cnt);
InjectedSocketFactory.flushAllStaticData();
InjectedSocketFactory.injectedBuffer = noticesBytes;
SqlResult rs1 = sess.sql("select 1").execute();
assertEquals(1, rs1.fetchOne().getInt(0));
cnt = 0;
for (Iterator<Warning> warn = rs1.getWarnings(); warn.hasNext(); ) {
Warning w = warn.next();
if (w.getMessage().equals(message1) || w.getMessage().equals(message2)) {
cnt++;
}
}
assertEquals(2, cnt);
} finally {
InjectedSocketFactory.flushAllStaticData();
dropCollection("testBug97269");
if (sess != null) {
sess.close();
}
}
}
use of com.mysql.cj.xdevapi.Collection in project aws-mysql-jdbc by awslabs.
the class CollectionFindTest method testCollectionRowLockOptions.
@Test
public void testCollectionRowLockOptions() throws Exception {
assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.5")), "MySQL 8.0.5+ is required to run this test.");
Function<DocResult, List<String>> asStringList = rr -> rr.fetchAll().stream().map(d -> ((JsonString) d.get("_id")).getString()).collect(Collectors.toList());
this.collection.add("{\"_id\":\"1\", \"a\":1}").add("{\"_id\":\"2\", \"a\":1}").add("{\"_id\":\"3\", \"a\":1}").execute();
Session session1 = null;
Session session2 = null;
try {
session1 = new SessionFactory().getSession(this.testProperties);
Collection col1 = session1.getDefaultSchema().getCollection(this.collectionName);
session2 = new SessionFactory().getSession(this.testProperties);
Collection col2 = session2.getDefaultSchema().getCollection(this.collectionName);
DocResult res;
CompletableFuture<DocResult> futRes;
/*
* 1. Shared Lock in both sessions.
*/
// session2.lockShared() returns data immediately.
session1.startTransaction();
col1.find("_id = '1'").lockShared().execute();
session2.startTransaction();
res = col2.find("_id < '3'").lockShared().execute();
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), hasItems("1", "2"));
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockShared().executeAsync();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
session1.rollback();
// session2.lockShared(NOWAIT) returns data immediately.
session1.startTransaction();
col1.find("_id = '1'").lockShared().execute();
session2.startTransaction();
res = col2.find("_id < '3'").lockShared(Statement.LockContention.NOWAIT).execute();
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockShared(Statement.LockContention.NOWAIT).executeAsync();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
session1.rollback();
// session2.lockShared(SKIP_LOCK) returns data immediately.
session1.startTransaction();
col1.find("_id = '1'").lockShared().execute();
session2.startTransaction();
res = col2.find("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).execute();
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).executeAsync();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
session1.rollback();
/*
* 2. Shared Lock in first session and exclusive lock in second.
*/
// session2.lockExclusive() blocks until session1 ends.
session1.startTransaction();
col1.find("_id = '1'").lockShared().execute();
// session2.startTransaction();
// res = col2.find("_id < '3'").lockExclusive().execute(); (Can't test)
// session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockExclusive().executeAsync();
final CompletableFuture<DocResult> fr1 = futRes;
assertThrows(TimeoutException.class, () -> fr1.get(3, TimeUnit.SECONDS));
// Unlocks session2.
session1.rollback();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
// session2.lockExclusive(NOWAIT) should return locking error.
session1.startTransaction();
col1.find("_id = '1'").lockShared().execute();
session2.startTransaction();
assertThrows(XProtocolError.class, "ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).execute());
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).executeAsync();
final CompletableFuture<DocResult> fr2 = futRes;
assertThrows(ExecutionException.class, ".*XProtocolError: ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> fr2.get(3, TimeUnit.SECONDS));
session2.rollback();
session1.rollback();
// session2.lockExclusive(SKIP_LOCK) should return (unlocked) data immediately.
session1.startTransaction();
col1.find("_id = '1'").lockShared().execute();
session2.startTransaction();
res = col2.find("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).execute();
assertEquals(1, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).executeAsync();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(1, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
session2.rollback();
session1.rollback();
/*
* 3. Exclusive Lock in first session and shared lock in second.
*/
// session2.lockShared() blocks until session1 ends.
session1.startTransaction();
col1.find("_id = '1'").lockExclusive().execute();
// session2.startTransaction();
// res = col2.find("_id < '3'").lockShared().execute(); (Can't test)
// session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockShared().executeAsync();
final CompletableFuture<DocResult> fr3 = futRes;
assertThrows(TimeoutException.class, () -> fr3.get(3, TimeUnit.SECONDS));
// Unlocks session2.
session1.rollback();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
// session2.lockShared(NOWAIT) should return locking error.
session1.startTransaction();
col1.find("_id = '1'").lockExclusive().execute();
session2.startTransaction();
assertThrows(XProtocolError.class, "ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> col2.find("_id < '3'").lockShared(Statement.LockContention.NOWAIT).execute());
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockShared(Statement.LockContention.NOWAIT).executeAsync();
final CompletableFuture<DocResult> fr4 = futRes;
assertThrows(ExecutionException.class, ".*XProtocolError: ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> fr4.get(3, TimeUnit.SECONDS));
session2.rollback();
session1.rollback();
// session2.lockShared(SKIP_LOCK) should return (unlocked) data immediately.
session1.startTransaction();
col1.find("_id = '1'").lockExclusive().execute();
session2.startTransaction();
res = col2.find("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).execute();
assertEquals(1, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).executeAsync();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(1, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
session2.rollback();
session1.rollback();
/*
* 4. Exclusive Lock in both sessions.
*/
// session2.lockExclusive() blocks until session1 ends.
session1.startTransaction();
col1.find("_id = '1'").lockExclusive().execute();
// session2.startTransaction();
// res = col2.find("_id < '3'").lockExclusive().execute(); (Can't test)
// session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockExclusive().executeAsync();
final CompletableFuture<DocResult> fr5 = futRes;
assertThrows(TimeoutException.class, () -> fr5.get(3, TimeUnit.SECONDS));
// Unlocks session2.
session1.rollback();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(2, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
session2.rollback();
// session2.lockExclusive(NOWAIT) should return locking error.
session1.startTransaction();
col1.find("_id = '1'").lockExclusive().execute();
session2.startTransaction();
assertThrows(XProtocolError.class, "ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).execute());
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).executeAsync();
final CompletableFuture<DocResult> fr6 = futRes;
assertThrows(ExecutionException.class, ".*XProtocolError: ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> fr6.get(3, TimeUnit.SECONDS));
session2.rollback();
session1.rollback();
// session2.lockExclusive(SKIP_LOCK) should return (unlocked) data immediately.
session1.startTransaction();
col1.find("_id = '1'").lockExclusive().execute();
session2.startTransaction();
res = col2.find("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).execute();
assertEquals(1, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
session2.rollback();
session2.startTransaction();
futRes = col2.find("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).executeAsync();
res = futRes.get(3, TimeUnit.SECONDS);
assertTrue(futRes.isDone());
assertEquals(1, asStringList.apply(res).size());
assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
session2.rollback();
session1.rollback();
} finally {
if (session1 != null) {
session1.close();
}
if (session2 != null) {
session2.close();
}
}
}
Aggregations