diff --git a/README.md b/README.md index 06e8d3c4..acc62a0f 100644 --- a/README.md +++ b/README.md @@ -54,12 +54,12 @@ grab via Maven: io.dgraph dgraph4j - 20.03.1 + 20.03.2 ``` or Gradle: ```groovy -compile 'io.dgraph:dgraph4j:20.03.1' +compile 'io.dgraph:dgraph4j:20.03.2' ``` ## Supported Versions @@ -106,7 +106,7 @@ use a different version of this client. | 1.7.0 | 1.15.0 | 2.0.12.Final | | 1.7.3-1.7.5 | 1.15.1 | 2.0.12.Final | | 2.0.0-2.1.0 | 1.22.1 | 2.0.25.Final | - | 20.03.0 | 1.26.0 | 2.0.26.Final | + | 20.03.0-20.03.2 | 1.26.0 | 2.0.26.Final | So, for example, if you were using `dgraph4j v20.03.0`, then you would need to use `2.0.26-Final` as the version for `netty-tcnative-boringssl-static` dependency as suggested by gRPC docs for diff --git a/build.gradle b/build.gradle index 3421fdfd..0016dd27 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ apply plugin: 'signing' group = 'io.dgraph' archivesBaseName = 'dgraph4j' -version = '20.03.1' +version = '20.03.2' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutation.java b/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutation.java index 138383d2..2fc42d7e 100644 --- a/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutation.java +++ b/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutation.java @@ -1,111 +1,140 @@ package io.dgraph.example; -import io.dgraph.DgraphProto.Mutation; -import io.dgraph.DgraphProto.Request; import com.google.gson.Gson; -import io.dgraph.DgraphProto.Response; import com.google.protobuf.ByteString; import io.dgraph.DgraphClient; +import io.dgraph.DgraphProto.Mutation; +import io.dgraph.DgraphProto.Request; +import io.dgraph.DgraphProto.Response; import io.dgraph.Transaction; import io.dgraph.TxnConflictException; import java.util.Collections; import java.util.Map; public class MultiThreadedMutation implements Runnable { - // maximum retries - static final int MAX_RETRY_COUNT = 5; - static Integer globalThreadNumberCount = 1; - int threadNumber = 0; - // - private DgraphClient dgraphClient; - private Transaction txn; - - public MultiThreadedMutation(DgraphClient dgraphClient) { - //assign a thread number - synchronized (globalThreadNumberCount) { - this.threadNumber = globalThreadNumberCount++; - this.dgraphClient = dgraphClient; - } - - } + // maximum retries + static final int MAX_RETRY_COUNT = 5; + static Integer globalThreadNumberCount = 1; + int threadNumber = 0; + // + private DgraphClient dgraphClient; + private Transaction txn; - public void run() { - boolean successFlag = false; - int retryCount = 0; - while (retryCount < MAX_RETRY_COUNT) { - try { - //fire the mutation and check for exceptions - doMutation(); - successFlag = true; - System.out.println(System.currentTimeMillis() + " Thread #" + threadNumber + " succeeded after " - + retryCount + " retries"); - break; - } catch (TxnConflictException txnConflictException) { - try { - System.out.println(System.currentTimeMillis() + " Thread #" + threadNumber - + " found a concurrent modification conflict, sleeping for 1 second..."); - Thread.sleep(1000); - System.out.println(System.currentTimeMillis() + " Thread #" + threadNumber + " resuming"); - } catch (InterruptedException e) { - e.printStackTrace(); - } - retryCount++; - } catch (Exception e) { - // cannot retry - e.printStackTrace(); - break; - } - } - //check if maximum retries has been crossed - if (!successFlag && retryCount >= MAX_RETRY_COUNT) { - System.out.println(System.currentTimeMillis() + " Thread #" + threadNumber + " giving up transaction after " - + (retryCount - 1) + " retries"); - } - } + public MultiThreadedMutation(DgraphClient dgraphClient) { + // assign a thread number + synchronized (globalThreadNumberCount) { + this.threadNumber = globalThreadNumberCount++; + this.dgraphClient = dgraphClient; + } + } - private void doMutation() throws Exception { - txn = dgraphClient.newTransaction(); - Gson gson = new Gson(); - // Query - String query = "query all($a: string){\n" + " all(func: eq(name, $a)) {\n" + " " + "uid\n" + "name\n" - + "clickCount\n" + " }\n" + "}\n"; + public void run() { + boolean successFlag = false; + int retryCount = 0; + while (retryCount < MAX_RETRY_COUNT) { + try { + // fire the mutation and check for exceptions + doMutation(); + successFlag = true; + System.out.println( + System.currentTimeMillis() + + " Thread #" + + threadNumber + + " succeeded after " + + retryCount + + " retries"); + break; + } catch (TxnConflictException txnConflictException) { + try { + System.out.println( + System.currentTimeMillis() + + " Thread #" + + threadNumber + + " found a concurrent modification conflict, sleeping for 1 second..."); + Thread.sleep(1000); + System.out.println(System.currentTimeMillis() + " Thread #" + threadNumber + " resuming"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + retryCount++; + } catch (Exception e) { + // cannot retry + e.printStackTrace(); + break; + } + } + // check if maximum retries has been crossed + if (!successFlag && retryCount >= MAX_RETRY_COUNT) { + System.out.println( + System.currentTimeMillis() + + " Thread #" + + threadNumber + + " giving up transaction after " + + (retryCount - 1) + + " retries"); + } + } - Map vars = Collections.singletonMap("$a", "Alice"); + private void doMutation() throws Exception { + txn = dgraphClient.newTransaction(); + Gson gson = new Gson(); + // Query + String query = + "query all($a: string){\n" + + " all(func: eq(name, $a)) {\n" + + " " + + "uid\n" + + "name\n" + + "clickCount\n" + + " }\n" + + "}\n"; - Response response = dgraphClient.newReadOnlyTransaction().queryWithVars(query, vars); - People ppl = gson.fromJson(response.getJson().toStringUtf8(), People.class); - // - for (Person person : ppl.all) { - System.out.println(System.currentTimeMillis() + " Thread #" + threadNumber - + " increasing clickCount for uid " + person.uid + ", Name: " + person.name); - //increment clickCount - person.clickCount = person.clickCount + 1; + Map vars = Collections.singletonMap("$a", "Alice"); - try { - //find and update alice's clickCount in a transaction - String upsertQuery = "query {\n" + "user as var(func: eq(name, \"" + person.name + "\"))\n" + "}\n"; - Mutation mu2 = Mutation.newBuilder() - .setSetNquads(ByteString.copyFromUtf8("uid(user) \"" + person.clickCount + "\" .")) - .build(); + Response response = dgraphClient.newReadOnlyTransaction().queryWithVars(query, vars); + People ppl = gson.fromJson(response.getJson().toStringUtf8(), People.class); + // + for (Person person : ppl.all) { + System.out.println( + System.currentTimeMillis() + + " Thread #" + + threadNumber + + " increasing clickCount for uid " + + person.uid + + ", Name: " + + person.name); + // increment clickCount + person.clickCount = person.clickCount + 1; - Request request = Request.newBuilder().setQuery(upsertQuery).addMutations(mu2).setCommitNow(true) - .build(); - txn.doRequest(request); - txn.close(); - } catch (Exception ex) { - // if its a conflict exception, we can retry - if (ex.getCause().getCause() instanceof TxnConflictException) { - TxnConflictException txnConflictException = (TxnConflictException) ex.getCause().getCause(); - txn.close(); - throw (txnConflictException); - } else { - throw ex; - } + try { + // find and update alice's clickCount in a transaction + String upsertQuery = + "query {\n" + "user as var(func: eq(name, \"" + person.name + "\"))\n" + "}\n"; + Mutation mu2 = + Mutation.newBuilder() + .setSetNquads( + ByteString.copyFromUtf8( + "uid(user) \"" + person.clickCount + "\" .")) + .build(); - } finally { - txn.discard(); - } + Request request = + Request.newBuilder().setQuery(upsertQuery).addMutations(mu2).setCommitNow(true).build(); + txn.doRequest(request); + txn.close(); + } catch (Exception ex) { + // if its a conflict exception, we can retry + if (ex.getCause().getCause() instanceof TxnConflictException) { + TxnConflictException txnConflictException = + (TxnConflictException) ex.getCause().getCause(); + txn.close(); + throw (txnConflictException); + } else { + throw ex; + } - } - } + } finally { + txn.discard(); + } + } + } } diff --git a/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutationLauncher.java b/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutationLauncher.java index 741f41a2..e64f1d60 100644 --- a/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutationLauncher.java +++ b/samples/concurrent-modification/src/main/java/io/dgraph/example/MultiThreadedMutationLauncher.java @@ -1,11 +1,7 @@ package io.dgraph.example; -import java.util.ArrayList; -import java.util.List; - import com.google.gson.Gson; import com.google.protobuf.ByteString; - import io.dgraph.DgraphClient; import io.dgraph.DgraphGrpc; import io.dgraph.DgraphGrpc.DgraphStub; @@ -15,98 +11,97 @@ import io.dgraph.TxnConflictException; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; +import java.util.ArrayList; +import java.util.List; public class MultiThreadedMutationLauncher { - private static final String HOST="localhost"; - private static final int PORT=9080; - private DgraphClient dgraphClient = null; - - public static void main(String[] args) { - new MultiThreadedMutationLauncher().doProcess(); - } - - /* - * Initialize Dgraph client in the constructor - */ - public MultiThreadedMutationLauncher() { - //initialize client - ManagedChannel channel1 = ManagedChannelBuilder.forAddress(HOST, PORT).usePlaintext().build(); - DgraphStub stub1 = DgraphGrpc.newStub(channel1); - dgraphClient = new DgraphClient(stub1); - } - - /* - * Sequence of processing steps in this example - */ - private void doProcess() { - //drops schema and data - dropAll(); - //create a new schema - createSchema(); - //initialize "Alice" with a clickCount of 1 - doSetupTransaction(); - - // fire concurrent mutations - doQueryAndMutation(); - - } - - private void doQueryAndMutation() { - //collect mutations - List mutations=new ArrayList(); - for(int i=0;i<2;i++) { - MultiThreadedMutation mtMutation=new MultiThreadedMutation(dgraphClient); - mutations.add(mtMutation); - } - - //launch threads - for(MultiThreadedMutation mutation:mutations) { - Thread t=new Thread(mutation); - t.start(); - } - - } - - /* - * Initialize a user "Alice" and "clickCount" attribute - */ - private void doSetupTransaction() { - Transaction txn = dgraphClient.newTransaction(); - Gson gson = new Gson(); - try { - // Create Alice with a clickCount of 1 - Person personAlice = new Person(); - personAlice.name = "Alice"; - personAlice.clickCount = 1; - - String json = gson.toJson(personAlice); - Mutation mu = Mutation.newBuilder().setSetJson(ByteString.copyFromUtf8(json.toString())).build(); - txn.mutate(mu); - txn.commit(); - - } catch (TxnConflictException ex) { - System.out.println(ex); - } finally { - txn.discard(); - } - } - - /* - * The schema for this example - */ - private void createSchema() { - String schema = "name: string @index(exact) .\n " - + "clickCount: int .\n"; - - Operation operation = Operation.newBuilder().setSchema(schema).setRunInBackground(true).build(); - dgraphClient.alter(operation); - } - /* - * Drop schema and data in the Dgraph instance - */ - private void dropAll() { - dgraphClient.alter(Operation.newBuilder().setDropAll(true).build()); - System.out.println("existing schema dropped"); - } - + private static final String HOST = "localhost"; + private static final int PORT = 9080; + private DgraphClient dgraphClient = null; + + public static void main(String[] args) { + new MultiThreadedMutationLauncher().doProcess(); + } + + /* + * Initialize Dgraph client in the constructor + */ + public MultiThreadedMutationLauncher() { + // initialize client + ManagedChannel channel1 = ManagedChannelBuilder.forAddress(HOST, PORT).usePlaintext().build(); + DgraphStub stub1 = DgraphGrpc.newStub(channel1); + dgraphClient = new DgraphClient(stub1); + } + + /* + * Sequence of processing steps in this example + */ + private void doProcess() { + // drops schema and data + dropAll(); + // create a new schema + createSchema(); + // initialize "Alice" with a clickCount of 1 + doSetupTransaction(); + + // fire concurrent mutations + doQueryAndMutation(); + } + + private void doQueryAndMutation() { + // collect mutations + List mutations = new ArrayList(); + for (int i = 0; i < 2; i++) { + MultiThreadedMutation mtMutation = new MultiThreadedMutation(dgraphClient); + mutations.add(mtMutation); + } + + // launch threads + for (MultiThreadedMutation mutation : mutations) { + Thread t = new Thread(mutation); + t.start(); + } + } + + /* + * Initialize a user "Alice" and "clickCount" attribute + */ + private void doSetupTransaction() { + Transaction txn = dgraphClient.newTransaction(); + Gson gson = new Gson(); + try { + // Create Alice with a clickCount of 1 + Person personAlice = new Person(); + personAlice.name = "Alice"; + personAlice.clickCount = 1; + + String json = gson.toJson(personAlice); + Mutation mu = + Mutation.newBuilder().setSetJson(ByteString.copyFromUtf8(json.toString())).build(); + txn.mutate(mu); + txn.commit(); + + } catch (TxnConflictException ex) { + System.out.println(ex); + } finally { + txn.discard(); + } + } + + /* + * The schema for this example + */ + private void createSchema() { + String schema = "name: string @index(exact) .\n " + "clickCount: int .\n"; + + Operation operation = Operation.newBuilder().setSchema(schema).setRunInBackground(true).build(); + dgraphClient.alter(operation); + } + /* + * Drop schema and data in the Dgraph instance + */ + private void dropAll() { + dgraphClient.alter(Operation.newBuilder().setDropAll(true).build()); + System.out.println("existing schema dropped"); + } } diff --git a/samples/concurrent-modification/src/main/java/io/dgraph/example/People.java b/samples/concurrent-modification/src/main/java/io/dgraph/example/People.java index 49098f10..6d18e139 100644 --- a/samples/concurrent-modification/src/main/java/io/dgraph/example/People.java +++ b/samples/concurrent-modification/src/main/java/io/dgraph/example/People.java @@ -4,6 +4,6 @@ public class People { List all; - + public People() {} } diff --git a/samples/concurrent-modification/src/main/java/io/dgraph/example/Person.java b/samples/concurrent-modification/src/main/java/io/dgraph/example/Person.java index 63a4e15a..e4938135 100644 --- a/samples/concurrent-modification/src/main/java/io/dgraph/example/Person.java +++ b/samples/concurrent-modification/src/main/java/io/dgraph/example/Person.java @@ -8,6 +8,5 @@ public class Person { /* * Empty constructor */ - public Person() { - } + public Person() {} } diff --git a/src/main/java/io/dgraph/DgraphClient.java b/src/main/java/io/dgraph/DgraphClient.java index c6f36e72..11a436c1 100644 --- a/src/main/java/io/dgraph/DgraphClient.java +++ b/src/main/java/io/dgraph/DgraphClient.java @@ -18,11 +18,9 @@ import io.dgraph.DgraphProto.Operation; import io.dgraph.DgraphProto.TxnContext; import io.dgraph.DgraphProto.Version; - import io.grpc.ManagedChannelBuilder; import io.grpc.Metadata; import io.grpc.stub.MetadataUtils; - import java.net.MalformedURLException; import java.net.URL; @@ -46,8 +44,8 @@ public class DgraphClient { * Creates a gRPC stub that can be used to construct clients to connect with Slash GraphQL. * * @param slashEndpoint The url of the Slash GraphQL endpoint. Example: - * https://your-slash-instance.cloud.dgraph.io/graphql - * @param apiKey The API key used to connect to your Slash GraphQL instance. + * https://your-slash-instance.cloud.dgraph.io/graphql + * @param apiKey The API key used to connect to your Slash GraphQL instance. * @return A new DgraphGrpc.DgraphStub object to be used with DgraphClient/DgraphAsyncClient. */ public static DgraphGrpc.DgraphStub clientStubFromSlashEndpoint( @@ -59,8 +57,8 @@ public static DgraphGrpc.DgraphStub clientStubFromSlashEndpoint( String gRPCAddress = parts[0] + ".grpc." + parts[1]; Metadata metadata = new Metadata(); - metadata.put(Metadata.Key.of(gRPC_AUTHORIZATION_HEADER_NAME, - Metadata.ASCII_STRING_MARSHALLER), apiKey); + metadata.put( + Metadata.Key.of(gRPC_AUTHORIZATION_HEADER_NAME, Metadata.ASCII_STRING_MARSHALLER), apiKey); return MetadataUtils.attachHeaders( DgraphGrpc.newStub( ManagedChannelBuilder.forAddress(gRPCAddress, 443).useTransportSecurity().build()), @@ -73,7 +71,7 @@ public static DgraphGrpc.DgraphStub clientStubFromSlashEndpoint( *

A single client is thread safe. * * @param stubs - an array of grpc stubs to be used by this client. The stubs to be used are - * chosen at random per transaction. + * chosen at random per transaction. */ public DgraphClient(DgraphGrpc.DgraphStub... stubs) { this.asyncClient = new DgraphAsyncClient(stubs); @@ -177,7 +175,7 @@ public Version checkVersion() { * access JWT and a refresh JWT, which will be stored in the jwt field of this class, and used for * authorizing all subsequent requests sent to the server. * - * @param userid the id of the user who is trying to login, e.g. Alice + * @param userid the id of the user who is trying to login, e.g. Alice * @param password the password of the user */ public void login(String userid, String password) { diff --git a/src/test/java/io/dgraph/DgraphClientTest.java b/src/test/java/io/dgraph/DgraphClientTest.java index 74a44fd3..72d35ee7 100644 --- a/src/test/java/io/dgraph/DgraphClientTest.java +++ b/src/test/java/io/dgraph/DgraphClientTest.java @@ -15,6 +15,9 @@ */ package io.dgraph; +import static org.testng.Assert.*; +import static org.testng.Assert.fail; + import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.protobuf.ByteString; @@ -22,17 +25,12 @@ import io.dgraph.DgraphProto.Operation; import io.dgraph.DgraphProto.Response; import io.dgraph.DgraphProto.TxnContext; - import java.net.MalformedURLException; import java.util.Collections; import java.util.Map; - import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.testng.Assert.*; -import static org.testng.Assert.fail; - /** * @author Edgar Rodriguez-Diaz * @author Deepak Jois @@ -157,8 +155,8 @@ public void testCheckVersion() { @Test public void testFromSlashEndpoint_ValidURL() { try { - DgraphClient.clientStubFromSlashEndpoint("https://your-slash-instance.cloud.dgraph" + - ".io/graphql", ""); + DgraphClient.clientStubFromSlashEndpoint( + "https://your-slash-instance.cloud.dgraph.io/graphql", ""); } catch (MalformedURLException e) { fail(e.getMessage()); }