From f0038517ecb520bfe9b5e6e766e0a7b496c77098 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 25 Oct 2022 09:50:21 -0300 Subject: [PATCH 1/4] chore: use immudb v1.4.0 Signed-off-by: Jeronimo Irazabal --- build.gradle | 2 +- immudb/start.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 46bc2e9..2cf56fd 100644 --- a/build.gradle +++ b/build.gradle @@ -134,7 +134,7 @@ task immudbStart { pb.command("/bin/bash", "immudb/start.sh") Process proc = pb.start() - proc.waitFor(10, TimeUnit.SECONDS) + proc.waitFor(5, TimeUnit.SECONDS) if (proc.isAlive()) { println "immudb has been started." diff --git a/immudb/start.sh b/immudb/start.sh index 3e357e4..277a6e2 100755 --- a/immudb/start.sh +++ b/immudb/start.sh @@ -13,10 +13,10 @@ then echo "Downloading immudb..." if [[ "$OSTYPE" == "linux-gnu"* ]]; then - URL=https://github.com/vchain-us/immudb/releases/download/v1.3.0/immudb-v1.3.0-linux-amd64 + URL=https://github.com/vchain-us/immudb/releases/download/v1.4.0/immudb-v1.4.0-linux-amd64 wget -O immudb $URL elif [[ "$OSTYPE" == "darwin"* ]]; then - URL=https://github.com/vchain-us/immudb/releases/download/v1.3.0/immudb-v1.3.0-darwin-amd64 + URL=https://github.com/vchain-us/immudb/releases/download/v1.4.0/immudb-v1.4.0-darwin-amd64 curl -o immudb -L $URL fi From 4b6d55fe15d1573095c08fd2c58afe52bc11072b Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 25 Oct 2022 09:52:09 -0300 Subject: [PATCH 2/4] chore: state handling by database name Signed-off-by: Jeronimo Irazabal --- .../io/codenotary/immudb4j/FileImmuStateHolder.java | 12 ++++++------ .../java/io/codenotary/immudb4j/ImmuStateHolder.java | 4 ++-- .../immudb4j/SerializableImmuStateHolder.java | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/codenotary/immudb4j/FileImmuStateHolder.java b/src/main/java/io/codenotary/immudb4j/FileImmuStateHolder.java index 9f2be64..b30d701 100644 --- a/src/main/java/io/codenotary/immudb4j/FileImmuStateHolder.java +++ b/src/main/java/io/codenotary/immudb4j/FileImmuStateHolder.java @@ -59,21 +59,21 @@ private FileImmuStateHolder(Builder builder) throws IOException, IllegalStateExc } @Override - public synchronized ImmuState getState(String serverUuid, String database) { - return stateHolder.getState(serverUuid, database); + public synchronized ImmuState getState(String database) { + return stateHolder.getState(database); } @Override - public synchronized void setState(String serverUuid, ImmuState state) throws IllegalStateException { + public synchronized void setState(ImmuState state) throws IllegalStateException { - ImmuState currentState = stateHolder.getState(serverUuid, state.getDatabase()); + ImmuState currentState = stateHolder.getState(state.getDatabase()); if (currentState != null && currentState.getTxId() >= state.getTxId()) { return; } - stateHolder.setState(serverUuid, state); + stateHolder.setState(state); - Path newStateFile = statesFolder.resolve("state_" + serverUuid + "_" + state.getDatabase() + "_" + System.nanoTime()); + Path newStateFile = statesFolder.resolve("state_" + state.getDatabase() + "_" + System.nanoTime()); if (Files.exists(newStateFile)) { throw new RuntimeException("Failed attempting to create a new state file. Please retry."); diff --git a/src/main/java/io/codenotary/immudb4j/ImmuStateHolder.java b/src/main/java/io/codenotary/immudb4j/ImmuStateHolder.java index 7938b11..f2b7821 100644 --- a/src/main/java/io/codenotary/immudb4j/ImmuStateHolder.java +++ b/src/main/java/io/codenotary/immudb4j/ImmuStateHolder.java @@ -18,8 +18,8 @@ public interface ImmuStateHolder { - ImmuState getState(String serverUuid, String database); + ImmuState getState(String database); - void setState(String serverUuid, ImmuState state); + void setState(ImmuState state); } diff --git a/src/main/java/io/codenotary/immudb4j/SerializableImmuStateHolder.java b/src/main/java/io/codenotary/immudb4j/SerializableImmuStateHolder.java index b72a867..772318a 100644 --- a/src/main/java/io/codenotary/immudb4j/SerializableImmuStateHolder.java +++ b/src/main/java/io/codenotary/immudb4j/SerializableImmuStateHolder.java @@ -27,7 +27,7 @@ public class SerializableImmuStateHolder implements ImmuStateHolder { /** - * Mapping "{serverUuid}_{databaseName}" to the appropriate state. + * Mapping "{databaseName}" to the appropriate state. */ private Map statesMap = new HashMap<>(); @@ -46,13 +46,13 @@ public void writeTo(OutputStream os) throws IOException { } @Override - public ImmuState getState(String serverUuid, String database) { - return this.statesMap.get(serverUuid + "_" + database); + public ImmuState getState(String database) { + return this.statesMap.get(database); } @Override - public void setState(String serverUuid, ImmuState state) { - this.statesMap.put(serverUuid + "_" + state.getDatabase(), state); + public void setState(ImmuState state) { + this.statesMap.put(state.getDatabase(), state); } } From de50cdaaad35138ba6685fef4426cd47c016a932 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 25 Oct 2022 15:49:50 -0300 Subject: [PATCH 3/4] chore: session-based authentication Signed-off-by: Jeronimo Irazabal --- .../io/codenotary/immudb4j/ImmuClient.java | 443 +++++----- .../immudb4j/ImmuServerUUIDInterceptor.java | 45 - .../ImmudbAuthRequestInterceptor.java | 37 + .../java/io/codenotary/immudb4j/Session.java} | 33 +- src/main/proto/schema.proto | 774 +++++++++--------- .../immudb4j/BasicImmuClientTest.java | 21 +- .../io/codenotary/immudb4j/HTreeTest.java | 4 - .../io/codenotary/immudb4j/HistoryTest.java | 7 +- .../immudb4j/ListDatabasesTest.java | 5 +- .../io/codenotary/immudb4j/ListUsersTest.java | 5 +- .../LoginAndHealthCheckAndCleanIndexTest.java | 14 +- .../immudb4j/MultidatabaseTest.java | 22 +- .../codenotary/immudb4j/MultithreadTest.java | 12 +- .../io/codenotary/immudb4j/ReferenceTest.java | 5 +- .../java/io/codenotary/immudb4j/ScanTest.java | 12 +- .../immudb4j/SetAllAndGetAllTest.java | 6 +- .../io/codenotary/immudb4j/SetAndGetTest.java | 6 +- .../io/codenotary/immudb4j/ShutdownTest.java | 9 +- .../io/codenotary/immudb4j/StateTest.java | 19 +- .../java/io/codenotary/immudb4j/TxTest.java | 12 +- .../io/codenotary/immudb4j/UserMgmtTest.java | 23 +- .../immudb4j/VerifiedSetAndGetTest.java | 12 +- .../java/io/codenotary/immudb4j/ZAddTest.java | 6 +- tests.sh | 11 +- 24 files changed, 758 insertions(+), 785 deletions(-) delete mode 100644 src/main/java/io/codenotary/immudb4j/ImmuServerUUIDInterceptor.java create mode 100644 src/main/java/io/codenotary/immudb4j/ImmudbAuthRequestInterceptor.java rename src/{test/java/io/codenotary/immudb4j/UseDatabaseTest.java => main/java/io/codenotary/immudb4j/Session.java} (56%) diff --git a/src/main/java/io/codenotary/immudb4j/ImmuClient.java b/src/main/java/io/codenotary/immudb4j/ImmuClient.java index b62ae36..277fd97 100644 --- a/src/main/java/io/codenotary/immudb4j/ImmuClient.java +++ b/src/main/java/io/codenotary/immudb4j/ImmuClient.java @@ -28,9 +28,8 @@ import io.codenotary.immudb4j.user.User; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; -import io.grpc.Metadata; import io.grpc.StatusRuntimeException; -import io.grpc.stub.MetadataUtils; +import io.grpc.ConnectivityState; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; @@ -49,21 +48,19 @@ */ public class ImmuClient { - private static final String AUTH_HEADER = "authorization"; - private final ImmuServiceGrpc.ImmuServiceBlockingStub stub; - private final boolean withAuth; + private final PublicKey serverSigningKey; private final ImmuStateHolder stateHolder; + private ManagedChannel channel; - private String authToken; - private String currentServerUuid; - private String currentDb = "defaultdb"; - private final PublicKey serverSigningKey; + + private final ImmuServiceGrpc.ImmuServiceBlockingStub stub; + + private Session session; public ImmuClient(Builder builder) { - this.stub = createStubFrom(builder); - this.withAuth = builder.isWithAuth(); this.stateHolder = builder.getStateHolder(); this.serverSigningKey = builder.getServerSigningKey(); + this.stub = createStubFrom(builder); } public static Builder newBuilder() { @@ -73,96 +70,108 @@ public static Builder newBuilder() { private ImmuServiceGrpc.ImmuServiceBlockingStub createStubFrom(Builder builder) { channel = ManagedChannelBuilder.forAddress(builder.getServerUrl(), builder.getServerPort()) .usePlaintext() - .intercept(new ImmuServerUUIDInterceptor(this)) + .intercept(new ImmudbAuthRequestInterceptor(this)) .build(); return ImmuServiceGrpc.newBlockingStub(channel); } - // --------------------------------------------------------------------- - // These two currentServerUuid related methods are not publicly exposed, - // since these should be called by the ImmuServerUUIDInterceptor only. - - void setCurrentServerUuid(String serverUuid) { - currentServerUuid = serverUuid; - } - - String getCurrentServerUuid() { - return currentServerUuid; - } - // --------------------------------------------------------------------- - public synchronized void shutdown() { if (channel == null) { return; } - channel.shutdown(); - if (!channel.isShutdown()) { - try { - channel.awaitTermination(2, TimeUnit.SECONDS); - } catch (InterruptedException e) { - // nothing to do here. + + if (session != null) { + closeSession(); + } + + try { + channel.shutdown(); + if (!channel.isShutdown()) { + try { + channel.awaitTermination(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + channel.shutdownNow(); + } } + } finally { + channel = null; } - channel = null; } - public synchronized boolean isShutdown() { - return channel == null; + Session getSession() { + return this.session; } - private ImmuServiceGrpc.ImmuServiceBlockingStub getStub() { - if (!withAuth || authToken == null) { - return stub; + public synchronized void openSession(String username, String password, String database) { + if (this.session != null) { + throw new IllegalStateException("session already opened"); } - Metadata metadata = new Metadata(); - metadata.put(Metadata.Key.of(AUTH_HEADER, Metadata.ASCII_STRING_MARSHALLER), "Bearer " + authToken); - - return MetadataUtils.attachHeaders(stub, metadata); - } - - public synchronized void login(String username, String password) { - ImmudbProto.LoginRequest loginRequest = ImmudbProto.LoginRequest + final ImmudbProto.OpenSessionRequest req = ImmudbProto.OpenSessionRequest .newBuilder() - .setUser(Utils.toByteString(username)) + .setUsername(Utils.toByteString(username)) .setPassword(Utils.toByteString(password)) + .setDatabaseName(database) .build(); - ImmudbProto.LoginResponse loginResponse = getStub().login(loginRequest); - authToken = loginResponse.getToken(); + final ImmudbProto.OpenSessionResponse resp = this.stub.openSession(req); + + this.session = new Session(resp.getSessionID(), username, database); } - public synchronized void logout() { - getStub().logout(com.google.protobuf.Empty.getDefaultInstance()); - authToken = null; + public synchronized void closeSession() { + if (this.session == null) { + throw new IllegalStateException("no open session"); + } + + try { + this.stub.closeSession(Empty.getDefaultInstance()); + } finally { + this.session = null; + } } /** * Get the locally saved state of the current database. * If nothing exists already, it is fetched from the server and save it locally. */ - public ImmuState state() throws VerificationException { - ImmuState state = stateHolder.getState(currentServerUuid, currentDb); + private ImmuState state() throws VerificationException { + if (this.session == null) { + throw new IllegalStateException("no open session"); + } + + ImmuState state = this.stateHolder.getState(this.session.getDatabase()); + if (state == null) { - state = currentState(); - stateHolder.setState(currentServerUuid, state); + state = this.currentState(); + stateHolder.setState(state); } + return state; } /** * Get the current database state that exists on the server. - * It may throw a RuntimeException if server's state signature verification fails + * It may throw VerificationException if server's state signature verification + * fails * (if this feature is enabled on the client side, at least). + * Note: local state is not updated because this is not a verified operation */ - public ImmuState currentState() throws VerificationException { - final Empty empty = com.google.protobuf.Empty.getDefaultInstance(); - final ImmudbProto.ImmutableState state = getStub().currentState(empty); + public synchronized ImmuState currentState() throws VerificationException { + if (this.session == null) { + throw new IllegalStateException("no open session"); + } + + final ImmudbProto.ImmutableState state = this.stub.currentState(Empty.getDefaultInstance()); final ImmuState immuState = ImmuState.valueOf(state); - if (!immuState.checkSignature(serverSigningKey)) { + if (!this.session.getDatabase().equals(immuState.getDatabase())) { + throw new VerificationException("database mismatch"); + } + + if (!immuState.checkSignature(this.serverSigningKey)) { throw new VerificationException("State signature verification failed"); } @@ -173,32 +182,29 @@ public ImmuState currentState() throws VerificationException { // ========== DATABASE ========== // - public void createDatabase(String database) { - final ImmudbProto.CreateDatabaseRequest db = ImmudbProto.CreateDatabaseRequest.newBuilder() + public synchronized void createDatabase(String database) { + if (this.session == null) { + throw new IllegalStateException("no open session"); + } + + final ImmudbProto.CreateDatabaseRequest req = ImmudbProto.CreateDatabaseRequest.newBuilder() .setName(database) .build(); - getStub().createDatabaseV2(db); + this.stub.createDatabaseV2(req); } - public synchronized void useDatabase(String database) { - final ImmudbProto.Database db = ImmudbProto.Database.newBuilder() - .setDatabaseName(database) - .build(); + public synchronized List databases() { + if (this.session == null) { + throw new IllegalStateException("no open session"); + } - final ImmudbProto.UseDatabaseReply response = getStub().useDatabase(db); + final ImmudbProto.DatabaseListRequestV2 req = ImmudbProto.DatabaseListRequestV2.newBuilder().build(); + final ImmudbProto.DatabaseListResponseV2 resp = this.stub.databaseListV2(req); - authToken = response.getToken(); - currentDb = database; - } + final List list = new ArrayList<>(resp.getDatabasesCount()); - public List databases() { - final ImmudbProto.DatabaseListRequestV2 req = ImmudbProto.DatabaseListRequestV2.newBuilder().build(); - final ImmudbProto.DatabaseListResponseV2 res = getStub().databaseListV2(req); - - final List list = new ArrayList<>(res.getDatabasesCount()); - - for (ImmudbProto.DatabaseWithSettings db : res.getDatabasesList()) { + for (ImmudbProto.DatabaseWithSettings db : resp.getDatabasesList()) { list.add(db.getName()); } @@ -221,14 +227,14 @@ public Entry getAtTx(String key, long tx) throws KeyNotFoundException { return getAtTx(Utils.toByteArray(key), tx); } - public Entry getAtTx(byte[] key, long tx) throws KeyNotFoundException { - final ImmudbProto.KeyRequest req =ImmudbProto.KeyRequest.newBuilder() - .setKey(Utils.toByteString(key)) - .setAtTx(tx) - .build(); + public synchronized Entry getAtTx(byte[] key, long tx) throws KeyNotFoundException { + final ImmudbProto.KeyRequest req = ImmudbProto.KeyRequest.newBuilder() + .setKey(Utils.toByteString(key)) + .setAtTx(tx) + .build(); try { - return Entry.valueOf(getStub().get(req)); + return Entry.valueOf(this.stub.get(req)); } catch (StatusRuntimeException e) { if (e.getMessage().contains("key not found")) { throw new KeyNotFoundException(); @@ -242,14 +248,14 @@ public Entry getSinceTx(String key, long tx) throws KeyNotFoundException { return getSinceTx(Utils.toByteArray(key), tx); } - public Entry getSinceTx(byte[] key, long tx) throws KeyNotFoundException { - final ImmudbProto.KeyRequest req =ImmudbProto.KeyRequest.newBuilder() + public synchronized Entry getSinceTx(byte[] key, long tx) throws KeyNotFoundException { + final ImmudbProto.KeyRequest req = ImmudbProto.KeyRequest.newBuilder() .setKey(Utils.toByteString(key)) .setSinceTx(tx) .build(); try { - return Entry.valueOf(getStub().get(req)); + return Entry.valueOf(this.stub.get(req)); } catch (StatusRuntimeException e) { if (e.getMessage().contains("key not found")) { throw new KeyNotFoundException(); @@ -263,14 +269,14 @@ public Entry getAtRevision(String key, long rev) throws KeyNotFoundException { return getAtRevision(Utils.toByteArray(key), rev); } - public Entry getAtRevision(byte[] key, long rev) throws KeyNotFoundException { - final ImmudbProto.KeyRequest req =ImmudbProto.KeyRequest.newBuilder() + public synchronized Entry getAtRevision(byte[] key, long rev) throws KeyNotFoundException { + final ImmudbProto.KeyRequest req = ImmudbProto.KeyRequest.newBuilder() .setKey(Utils.toByteString(key)) .setAtRevision(rev) .build(); try { - return Entry.valueOf(getStub().get(req)); + return Entry.valueOf(this.stub.get(req)); } catch (StatusRuntimeException e) { if (e.getMessage().contains("key not found")) { throw new KeyNotFoundException(); @@ -280,15 +286,15 @@ public Entry getAtRevision(byte[] key, long rev) throws KeyNotFoundException { } } - public List getAll(List keys) { + public synchronized List getAll(List keys) { final List keysBS = new ArrayList<>(keys.size()); - + for (String key : keys) { keysBS.add(Utils.toByteString(key)); } final ImmudbProto.KeyListRequest req = ImmudbProto.KeyListRequest.newBuilder().addAllKeys(keysBS).build(); - final ImmudbProto.Entries entries = getStub().getAll(req); + final ImmudbProto.Entries entries = this.stub.getAll(req); final List result = new ArrayList<>(entries.getEntriesCount()); @@ -311,51 +317,62 @@ public Entry verifiedGetAtTx(String key, long tx) throws KeyNotFoundException, V return verifiedGetAtTx(Utils.toByteArray(key), tx); } - public Entry verifiedGetAtTx(byte[] key, long tx) throws KeyNotFoundException, VerificationException { + public synchronized Entry verifiedGetAtTx(byte[] key, long tx) throws KeyNotFoundException, VerificationException { + final ImmuState state = this.state(); + final ImmudbProto.KeyRequest keyReq = ImmudbProto.KeyRequest.newBuilder() .setKey(Utils.toByteString(key)) .setAtTx(tx) .build(); - return verifiedGet(keyReq, state()); + return verifiedGet(keyReq, state); } public Entry verifiedGetSinceTx(String key, long tx) throws KeyNotFoundException, VerificationException { return verifiedGetSinceTx(Utils.toByteArray(key), tx); } - public Entry verifiedGetSinceTx(byte[] key, long tx) throws KeyNotFoundException, VerificationException { + public synchronized Entry verifiedGetSinceTx(byte[] key, long tx) + throws KeyNotFoundException, VerificationException { + + final ImmuState state = this.state(); + final ImmudbProto.KeyRequest keyReq = ImmudbProto.KeyRequest.newBuilder() .setKey(Utils.toByteString(key)) .setSinceTx(tx) .build(); - return verifiedGet(keyReq, state()); + return verifiedGet(keyReq, state); } public Entry verifiedGetAtRevision(String key, long rev) throws KeyNotFoundException, VerificationException { return verifiedGetAtRevision(Utils.toByteArray(key), rev); } - public Entry verifiedGetAtRevision(byte[] key, long rev) throws KeyNotFoundException, VerificationException { + public synchronized Entry verifiedGetAtRevision(byte[] key, long rev) + throws KeyNotFoundException, VerificationException { + + final ImmuState state = this.state(); + final ImmudbProto.KeyRequest keyReq = ImmudbProto.KeyRequest.newBuilder() .setKey(Utils.toByteString(key)) .setAtRevision(rev) .build(); - return verifiedGet(keyReq, state()); + return verifiedGet(keyReq, state); } - private Entry verifiedGet(ImmudbProto.KeyRequest keyReq, ImmuState state) throws KeyNotFoundException, VerificationException { + private Entry verifiedGet(ImmudbProto.KeyRequest keyReq, ImmuState state) + throws KeyNotFoundException, VerificationException { final ImmudbProto.VerifiableGetRequest vGetReq = ImmudbProto.VerifiableGetRequest.newBuilder() .setKeyRequest(keyReq) .setProveSinceTx(state.getTxId()) .build(); - + final ImmudbProto.VerifiableEntry vEntry; try { - vEntry = getStub().verifiableGet(vGetReq); + vEntry = this.stub.verifiableGet(vGetReq); } catch (StatusRuntimeException e) { if (e.getMessage().contains("key not found")) { throw new KeyNotFoundException(); @@ -371,14 +388,15 @@ private Entry verifiedGet(ImmudbProto.KeyRequest keyReq, ImmuState state) throws long sourceId, targetId; byte[] sourceAlh; byte[] targetAlh; - + final Entry entry = Entry.valueOf(vEntry.getEntry()); if (entry.getReferenceBy() == null && !Arrays.equals(keyReq.getKey().toByteArray(), entry.getKey())) { throw new VerificationException("Data is corrupted: entry does not belong to specified key"); } - if (entry.getReferenceBy() != null && !Arrays.equals(keyReq.getKey().toByteArray(), entry.getReferenceBy().getKey())) { + if (entry.getReferenceBy() != null + && !Arrays.equals(keyReq.getKey().toByteArray(), entry.getReferenceBy().getKey())) { throw new VerificationException("Data is corrupted: entry does not belong to specified key"); } @@ -420,14 +438,13 @@ private Entry verifiedGet(ImmudbProto.KeyRequest keyReq, ImmuState state) throws sourceId, targetId, sourceAlh, - targetAlh - )) { + targetAlh)) { throw new VerificationException("Dual proof verification failed."); } } final ImmuState newState = new ImmuState( - currentDb, + this.session.getDatabase(), targetId, targetAlh, vEntry.getVerifiableTx().getSignature().toByteArray()); @@ -436,7 +453,7 @@ private Entry verifiedGet(ImmudbProto.KeyRequest keyReq, ImmuState state) throws throw new VerificationException("State signature verification failed"); } - stateHolder.setState(currentServerUuid, newState); + this.stateHolder.setState(newState); return Entry.valueOf(vEntry.getEntry()); } @@ -449,13 +466,13 @@ public TxHeader delete(String key) throws KeyNotFoundException { return delete(Utils.toByteArray(key)); } - public TxHeader delete(byte[] key) throws KeyNotFoundException { + public synchronized TxHeader delete(byte[] key) throws KeyNotFoundException { try { final ImmudbProto.DeleteKeysRequest req = ImmudbProto.DeleteKeysRequest.newBuilder() .addKeys(Utils.toByteString(key)) .build(); - return TxHeader.valueOf(getStub().delete(req)); + return TxHeader.valueOf(this.stub.delete(req)); } catch (StatusRuntimeException e) { if (e.getMessage().contains("key not found")) { throw new KeyNotFoundException(); @@ -473,15 +490,15 @@ public List history(String key, int limit, long offset, boolean desc) thr return history(Utils.toByteArray(key), limit, offset, desc); } - public List history(byte[] key, int limit, long offset, boolean desc) throws KeyNotFoundException { + public synchronized List history(byte[] key, int limit, long offset, boolean desc) + throws KeyNotFoundException { try { - ImmudbProto.Entries entries = getStub().history(ImmudbProto.HistoryRequest.newBuilder() - .setKey(Utils.toByteString(key)) - .setLimit(limit) - .setOffset(offset) - .setDesc(desc) - .build() - ); + ImmudbProto.Entries entries = this.stub.history(ImmudbProto.HistoryRequest.newBuilder() + .setKey(Utils.toByteString(key)) + .setLimit(limit) + .setOffset(offset) + .setDesc(desc) + .build()); return buildList(entries); } catch (StatusRuntimeException e) { @@ -529,8 +546,9 @@ public List scan(byte[] prefix, byte[] seekKey, byte[] endKey, long limit return scan(prefix, seekKey, endKey, false, false, limit, desc); } - public List scan(byte[] prefix, byte[] seekKey, byte[] endKey, boolean inclusiveSeek, boolean inclusiveEnd, - long limit, boolean desc) { + public synchronized List scan(byte[] prefix, byte[] seekKey, byte[] endKey, boolean inclusiveSeek, + boolean inclusiveEnd, + long limit, boolean desc) { final ImmudbProto.ScanRequest req = ScanRequest.newBuilder() .setPrefix(Utils.toByteString(prefix)) .setSeekKey(Utils.toByteString(seekKey)) @@ -541,7 +559,7 @@ public List scan(byte[] prefix, byte[] seekKey, byte[] endKey, boolean in .setDesc(desc) .build(); - final ImmudbProto.Entries entries = getStub().scan(req); + final ImmudbProto.Entries entries = this.stub.scan(req); return buildList(entries); } @@ -553,15 +571,15 @@ public TxHeader set(String key, byte[] value) throws CorruptedDataException { return set(Utils.toByteArray(key), value); } - public TxHeader set(byte[] key, byte[] value) throws CorruptedDataException { + public synchronized TxHeader set(byte[] key, byte[] value) throws CorruptedDataException { final ImmudbProto.KeyValue kv = ImmudbProto.KeyValue.newBuilder() .setKey(Utils.toByteString(key)) .setValue(Utils.toByteString(value)) .build(); final ImmudbProto.SetRequest req = ImmudbProto.SetRequest.newBuilder().addKVs(kv).build(); - final ImmudbProto.TxHeader txHdr = getStub().set(req); - + final ImmudbProto.TxHeader txHdr = this.stub.set(req); + if (txHdr.getNentries() != 1) { throw new CorruptedDataException(); } @@ -569,9 +587,9 @@ public TxHeader set(byte[] key, byte[] value) throws CorruptedDataException { return TxHeader.valueOf(txHdr); } - public TxHeader setAll(List kvList) throws CorruptedDataException { + public synchronized TxHeader setAll(List kvList) throws CorruptedDataException { final ImmudbProto.SetRequest.Builder reqBuilder = ImmudbProto.SetRequest.newBuilder(); - + for (KVPair kv : kvList) { ImmudbProto.KeyValue.Builder kvBuilder = ImmudbProto.KeyValue.newBuilder(); @@ -581,7 +599,7 @@ public TxHeader setAll(List kvList) throws CorruptedDataException { reqBuilder.addKVs(kvBuilder.build()); } - final ImmudbProto.TxHeader txHdr = getStub().set(reqBuilder.build()); + final ImmudbProto.TxHeader txHdr = this.stub.set(reqBuilder.build()); if (txHdr.getNentries() != kvList.size()) { throw new CorruptedDataException(); @@ -602,7 +620,8 @@ public TxHeader setReference(String key, String referencedKey, long atTx) throws return setReference(Utils.toByteArray(key), Utils.toByteArray(referencedKey), atTx); } - public TxHeader setReference(byte[] key, byte[] referencedKey, long atTx) throws CorruptedDataException { + public synchronized TxHeader setReference(byte[] key, byte[] referencedKey, long atTx) + throws CorruptedDataException { final ImmudbProto.ReferenceRequest req = ImmudbProto.ReferenceRequest.newBuilder() .setKey(Utils.toByteString(key)) .setReferencedKey(Utils.toByteString(referencedKey)) @@ -610,8 +629,8 @@ public TxHeader setReference(byte[] key, byte[] referencedKey, long atTx) throws .setBoundRef(atTx > 0) .build(); - final ImmudbProto.TxHeader txHdr = getStub().setReference(req); - + final ImmudbProto.TxHeader txHdr = this.stub.setReference(req); + if (txHdr.getNentries() != 1) { throw new CorruptedDataException(); } @@ -619,34 +638,34 @@ public TxHeader setReference(byte[] key, byte[] referencedKey, long atTx) throws return TxHeader.valueOf(txHdr); } - public TxHeader verifiedSet(String key, byte[] value) throws VerificationException { + public TxHeader verifiedSet(String key, byte[] value) throws VerificationException { return verifiedSet(Utils.toByteArray(key), value); } - public TxHeader verifiedSet(byte[] key, byte[] value) throws VerificationException { - final ImmuState state = state(); + public synchronized TxHeader verifiedSet(byte[] key, byte[] value) throws VerificationException { + final ImmuState state = this.state(); + final ImmudbProto.KeyValue kv = ImmudbProto.KeyValue.newBuilder() - .setKey(Utils.toByteString(key)) - .setValue(Utils.toByteString(value)) - .build(); - + .setKey(Utils.toByteString(key)) + .setValue(Utils.toByteString(value)) + .build(); + final ImmudbProto.VerifiableSetRequest vSetReq = ImmudbProto.VerifiableSetRequest.newBuilder() .setSetRequest(ImmudbProto.SetRequest.newBuilder().addKVs(kv).build()) .setProveSinceTx(state.getTxId()) .build(); - - final ImmudbProto.VerifiableTx vtx = getStub().verifiableSet(vSetReq); - + + final ImmudbProto.VerifiableTx vtx = this.stub.verifiableSet(vSetReq); + final int ne = vtx.getTx().getHeader().getNentries(); - + if (ne != 1 || vtx.getTx().getEntriesList().size() != 1) { throw new VerificationException( - String.format("Got back %d entries (in tx metadata) instead of 1.", ne) - ); + String.format("Got back %d entries (in tx metadata) instead of 1.", ne)); } - + final Tx tx; - + try { tx = Tx.valueOf(vtx.getTx()); } catch (Exception e) { @@ -658,8 +677,7 @@ public TxHeader verifiedSet(byte[] key, byte[] value) throws VerificationExcepti final Entry entry = Entry.valueOf(ImmudbProto.Entry.newBuilder() .setKey(Utils.toByteString(key)) .setValue(Utils.toByteString(value)) - .build() - ); + .build()); final InclusionProof inclusionProof = tx.proof(entry.getEncodedKey()); @@ -673,18 +691,19 @@ public TxHeader verifiedSet(byte[] key, byte[] value) throws VerificationExcepti throw new VerificationException("State signature verification failed"); } - stateHolder.setState(currentServerUuid, newState); + this.stateHolder.setState(newState); return TxHeader.valueOf(vtx.getTx().getHeader()); } - public TxHeader verifiedSetReference(byte[] key, byte[] referencedKey) throws VerificationException { return verifiedSetReference(key, referencedKey, 0); } - public TxHeader verifiedSetReference(byte[] key, byte[] referencedKey, long atTx) throws VerificationException { - final ImmuState state = state(); + public synchronized TxHeader verifiedSetReference(byte[] key, byte[] referencedKey, long atTx) + throws VerificationException { + + final ImmuState state = this.state(); final ImmudbProto.ReferenceRequest refReq = ImmudbProto.ReferenceRequest.newBuilder() .setKey(Utils.toByteString(key)) @@ -698,8 +717,8 @@ public TxHeader verifiedSetReference(byte[] key, byte[] referencedKey, long atTx .setProveSinceTx(state.getTxId()) .build(); - final ImmudbProto.VerifiableTx vtx = getStub().verifiableSetReference(vRefReq); - + final ImmudbProto.VerifiableTx vtx = this.stub.verifiableSetReference(vRefReq); + final int vtxNentries = vtx.getTx().getHeader().getNentries(); if (vtxNentries != 1) { throw new VerificationException(String.format("Data is corrupted (verifTx has %d Nentries instead of 1).", @@ -720,18 +739,17 @@ public TxHeader verifiedSetReference(byte[] key, byte[] referencedKey, long atTx .setReferencedBy(ImmudbProto.Reference.newBuilder() .setKey(Utils.toByteString(key)) .setAtTx(atTx) - .build() - ) - .build() - ); + .build()) + .build()); final InclusionProof inclusionProof = tx.proof(entry.getEncodedKey()); - + if (!CryptoUtils.verifyInclusion(inclusionProof, entry.digestFor(txHeader.getVersion()), txHeader.getEh())) { throw new VerificationException("Data is corrupted (inclusion verification failed)."); } - if (Arrays.equals(txHeader.getEh(), CryptoUtils.digestFrom(vtx.getDualProof().getTargetTxHeader().getEH().toByteArray()))) { + if (Arrays.equals(txHeader.getEh(), + CryptoUtils.digestFrom(vtx.getDualProof().getTargetTxHeader().getEH().toByteArray()))) { throw new VerificationException("Data is corrupted (different digests)."); } @@ -741,7 +759,7 @@ public TxHeader verifiedSetReference(byte[] key, byte[] referencedKey, long atTx throw new VerificationException("State signature verification failed"); } - stateHolder.setState(currentServerUuid, newState); + this.stateHolder.setState(newState); return TxHeader.valueOf(vtx.getTx().getHeader()); } @@ -760,13 +778,12 @@ private ImmuState verifyDualProof(ImmudbProto.VerifiableTx vtx, Tx tx, ImmuState sourceId, targetId, sourceAlh, - targetAlh - )) { + targetAlh)) { throw new VerificationException("Data is corrupted (dual proof verification failed)."); } } - return new ImmuState(currentDb, targetId, targetAlh, vtx.getSignature().getSignature().toByteArray()); + return new ImmuState(state.getDatabase(), targetId, targetAlh, vtx.getSignature().getSignature().toByteArray()); } // @@ -781,17 +798,16 @@ public TxHeader zAdd(byte[] set, byte[] key, double score) throws CorruptedDataE return zAdd(set, key, 0, score); } - public TxHeader zAdd(byte[] set, byte[] key, long atTx, double score) throws CorruptedDataException { - final ImmudbProto.TxHeader txHdr = getStub().zAdd( + public synchronized TxHeader zAdd(byte[] set, byte[] key, long atTx, double score) throws CorruptedDataException { + final ImmudbProto.TxHeader txHdr = this.stub.zAdd( ImmudbProto.ZAddRequest.newBuilder() .setSet(Utils.toByteString(set)) .setKey(Utils.toByteString(key)) .setAtTx(atTx) .setScore(score) .setBoundRef(atTx > 0) - .build() - ); - + .build()); + if (txHdr.getNentries() != 1) { throw new CorruptedDataException(); } @@ -799,21 +815,22 @@ public TxHeader zAdd(byte[] set, byte[] key, long atTx, double score) throws Cor return TxHeader.valueOf(txHdr); } - public TxHeader verifiedZAdd(String set, String key, double score) throws VerificationException { return verifiedZAdd(Utils.toByteArray(set), Utils.toByteArray(key), score); } public TxHeader verifiedZAdd(byte[] set, byte[] key, double score) throws VerificationException { - return verifiedZAdd(set, key,0, score); + return verifiedZAdd(set, key, 0, score); } public TxHeader verifiedZAdd(String set, String key, long atTx, double score) throws VerificationException { return verifiedZAdd(Utils.toByteArray(set), Utils.toByteArray(key), atTx, score); } - public TxHeader verifiedZAdd(byte[] set, byte[] key, long atTx, double score) throws VerificationException { - final ImmuState state = state(); + public synchronized TxHeader verifiedZAdd(byte[] set, byte[] key, long atTx, double score) + throws VerificationException { + + final ImmuState state = this.state(); final ImmudbProto.ZAddRequest zAddReq = ImmudbProto.ZAddRequest.newBuilder() .setSet(Utils.toByteString(set)) @@ -822,13 +839,13 @@ public TxHeader verifiedZAdd(byte[] set, byte[] key, long atTx, double score) th .setBoundRef(atTx > 0) .setScore(score) .build(); - + final ImmudbProto.VerifiableZAddRequest vZAddReq = ImmudbProto.VerifiableZAddRequest.newBuilder() .setZAddRequest(zAddReq) .setProveSinceTx(state.getTxId()) .build(); - - final ImmudbProto.VerifiableTx vtx = getStub().verifiableZAdd(vZAddReq); + + final ImmudbProto.VerifiableTx vtx = this.stub.verifiableZAdd(vZAddReq); if (vtx.getTx().getHeader().getNentries() != 1) { throw new VerificationException("Data is corrupted."); @@ -848,8 +865,7 @@ public TxHeader verifiedZAdd(byte[] set, byte[] key, long atTx, double score) th .setKey(Utils.toByteString(key)) .setAtTx(atTx) .setScore(score) - .build() - ); + .build()); InclusionProof inclusionProof = tx.proof(entry.getEncodedKey()); @@ -857,7 +873,8 @@ public TxHeader verifiedZAdd(byte[] set, byte[] key, long atTx, double score) th throw new VerificationException("Data is corrupted (inclusion verification failed)."); } - if (!Arrays.equals(txHeader.getEh(), CryptoUtils.digestFrom(vtx.getDualProof().getTargetTxHeader().getEH().toByteArray()))) { + if (!Arrays.equals(txHeader.getEh(), + CryptoUtils.digestFrom(vtx.getDualProof().getTargetTxHeader().getEH().toByteArray()))) { throw new VerificationException("Data is corrupted (different digests)."); } @@ -867,7 +884,7 @@ public TxHeader verifiedZAdd(byte[] set, byte[] key, long atTx, double score) th throw new VerificationException("State signature verification failed"); } - stateHolder.setState(currentServerUuid, newState); + this.stateHolder.setState(newState); return TxHeader.valueOf(vtx.getTx().getHeader()); } @@ -876,7 +893,7 @@ public List zScan(String set, long limit, boolean reverse) { return zScan(Utils.toByteArray(set), limit, reverse); } - public List zScan(byte[] set, long limit, boolean reverse) { + public synchronized List zScan(byte[] set, long limit, boolean reverse) { final ImmudbProto.ZScanRequest req = ImmudbProto.ZScanRequest .newBuilder() .setSet(Utils.toByteString(set)) @@ -884,7 +901,7 @@ public List zScan(byte[] set, long limit, boolean reverse) { .setDesc(reverse) .build(); - final ImmudbProto.ZEntries zEntries = getStub().zScan(req); + final ImmudbProto.ZEntries zEntries = this.stub.zScan(req); return buildList(zEntries); } @@ -893,9 +910,9 @@ public List zScan(byte[] set, long limit, boolean reverse) { // ========== TX ========== // - public Tx txById(long txId) throws TxNotFoundException, NoSuchAlgorithmException { + public synchronized Tx txById(long txId) throws TxNotFoundException, NoSuchAlgorithmException { try { - final ImmudbProto.Tx tx = getStub().txById(ImmudbProto.TxRequest.newBuilder().setTx(txId).build()); + final ImmudbProto.Tx tx = this.stub.txById(ImmudbProto.TxRequest.newBuilder().setTx(txId).build()); return Tx.valueOf(tx); } catch (StatusRuntimeException e) { if (e.getMessage().contains("tx not found")) { @@ -906,17 +923,18 @@ public Tx txById(long txId) throws TxNotFoundException, NoSuchAlgorithmException } } - public Tx verifiedTxById(long txId) throws TxNotFoundException, VerificationException { - final ImmuState state = state(); + public synchronized Tx verifiedTxById(long txId) throws TxNotFoundException, VerificationException { + final ImmuState state = this.state(); + final ImmudbProto.VerifiableTxRequest vTxReq = ImmudbProto.VerifiableTxRequest.newBuilder() .setTx(txId) .setProveSinceTx(state.getTxId()) .build(); - + final ImmudbProto.VerifiableTx vtx; try { - vtx = getStub().verifiableTxById(vTxReq); + vtx = this.stub.verifiableTxById(vTxReq); } catch (StatusRuntimeException e) { if (e.getMessage().contains("tx not found")) { throw new TxNotFoundException(); @@ -950,8 +968,7 @@ public Tx verifiedTxById(long txId) throws TxNotFoundException, VerificationExce sourceId, targetId, sourceAlh, - targetAlh - )) { + targetAlh)) { throw new VerificationException("Data is corrupted (dual proof verification failed)."); } } @@ -963,31 +980,32 @@ public Tx verifiedTxById(long txId) throws TxNotFoundException, VerificationExce throw new VerificationException("Failed to extract the transaction.", e); } - final ImmuState newState = new ImmuState(currentDb, targetId, targetAlh, vtx.getSignature().getSignature().toByteArray()); + final ImmuState newState = new ImmuState(state.getDatabase(), targetId, targetAlh, + vtx.getSignature().getSignature().toByteArray()); if (!newState.checkSignature(serverSigningKey)) { throw new VerificationException("State signature verification failed"); } - stateHolder.setState(currentServerUuid, newState); + stateHolder.setState(newState); return tx; } - public List txScan(long initialTxId) { + public synchronized List txScan(long initialTxId) { final ImmudbProto.TxScanRequest req = ImmudbProto.TxScanRequest.newBuilder().setInitialTx(initialTxId).build(); - final ImmudbProto.TxList txList = getStub().txScan(req); + final ImmudbProto.TxList txList = this.stub.txScan(req); return buildList(txList); } - public List txScan(long initialTxId, int limit, boolean desc) { + public synchronized List txScan(long initialTxId, int limit, boolean desc) { final ImmudbProto.TxScanRequest req = ImmudbProto.TxScanRequest .newBuilder() .setInitialTx(initialTxId) .setLimit(limit) .setDesc(desc) .build(); - final ImmudbProto.TxList txList = getStub().txScan(req); + final ImmudbProto.TxList txList = this.stub.txScan(req); return buildList(txList); } @@ -995,20 +1013,24 @@ public List txScan(long initialTxId, int limit, boolean desc) { // ========== HEALTH ========== // - public boolean healthCheck() { - return getStub().health(Empty.getDefaultInstance()).getStatus(); + public boolean isConnected() { + return channel != null && channel.getState(false) == ConnectivityState.READY; } - public boolean isConnected() { - return channel != null; + public boolean isShutdown() { + return channel != null && channel.isShutdown(); + } + + public synchronized boolean healthCheck() { + return this.stub.serverInfo(ImmudbProto.ServerInfoRequest.getDefaultInstance()) != null; } // // ========== USER MGMT ========== // - public List listUsers() { - final ImmudbProto.UserList userList = getStub().listUsers(Empty.getDefaultInstance()); + public synchronized List listUsers() { + final ImmudbProto.UserList userList = this.stub.listUsers(Empty.getDefaultInstance()); return userList.getUsersList() .stream() @@ -1018,8 +1040,7 @@ public List listUsers() { .setCreatedAt(u.getCreatedat()) .setCreatedBy(u.getCreatedby()) .setPermissions(buildPermissions(u.getPermissionsList())) - .build() - ) + .build()) .collect(Collectors.toList()); } @@ -1030,7 +1051,7 @@ private List buildPermissions(List permissio .collect(Collectors.toList()); } - public void createUser(String user, String password, Permission permission, String database) { + public synchronized void createUser(String user, String password, Permission permission, String database) { final ImmudbProto.CreateUserRequest createUserRequest = ImmudbProto.CreateUserRequest.newBuilder() .setUser(Utils.toByteString(user)) .setPassword(Utils.toByteString(password)) @@ -1039,10 +1060,10 @@ public void createUser(String user, String password, Permission permission, Stri .build(); // noinspection ResultOfMethodCallIgnored - getStub().createUser(createUserRequest); + this.stub.createUser(createUserRequest); } - public void changePassword(String user, String oldPassword, String newPassword) { + public synchronized void changePassword(String user, String oldPassword, String newPassword) { final ImmudbProto.ChangePasswordRequest changePasswordRequest = ImmudbProto.ChangePasswordRequest.newBuilder() .setUser(Utils.toByteString(user)) .setOldPassword(Utils.toByteString(oldPassword)) @@ -1050,24 +1071,24 @@ public void changePassword(String user, String oldPassword, String newPassword) .build(); // noinspection ResultOfMethodCallIgnored - getStub().changePassword(changePasswordRequest); + this.stub.changePassword(changePasswordRequest); } // // ========== INDEX MGMT ========== // - public void flushIndex(float cleanupPercentage, boolean synced) { + public synchronized void flushIndex(float cleanupPercentage, boolean synced) { ImmudbProto.FlushIndexRequest req = ImmudbProto.FlushIndexRequest.newBuilder() .setCleanupPercentage(cleanupPercentage) .setSynced(synced) .build(); - getStub().flushIndex(req); + this.stub.flushIndex(req); } - public void compactIndex() { - getStub().compactIndex(Empty.getDefaultInstance()); + public synchronized void compactIndex() { + this.stub.compactIndex(Empty.getDefaultInstance()); } // diff --git a/src/main/java/io/codenotary/immudb4j/ImmuServerUUIDInterceptor.java b/src/main/java/io/codenotary/immudb4j/ImmuServerUUIDInterceptor.java deleted file mode 100644 index f665143..0000000 --- a/src/main/java/io/codenotary/immudb4j/ImmuServerUUIDInterceptor.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.codenotary.immudb4j; - -import io.grpc.*; -import io.grpc.ForwardingClientCallListener.SimpleForwardingClientCallListener; - - -public class ImmuServerUUIDInterceptor implements ClientInterceptor { - - private static final String SERVER_UUID = "immudb-uuid"; - - private final ImmuClient client; - - public ImmuServerUUIDInterceptor(ImmuClient client) { - this.client = client; - } - - @Override - public ClientCall interceptCall( - MethodDescriptor method, - CallOptions callOptions, Channel next) { - - return new ForwardingClientCall.SimpleForwardingClientCall(next.newCall(method, callOptions)) { - - @Override - public void start(Listener responseListener, Metadata headers) { - - SimpleForwardingClientCallListener listener = new SimpleForwardingClientCallListener(responseListener) { - - @Override - public void onHeaders(Metadata headers) { - String serverUuid = headers.get(Metadata.Key.of(SERVER_UUID, Metadata.ASCII_STRING_MARSHALLER)); - if (serverUuid != null && !serverUuid.equals(client.getCurrentServerUuid())) { - client.setCurrentServerUuid(serverUuid); - } - super.onHeaders(headers); - } - }; - super.start(listener, headers); - } - - }; - - } - -} diff --git a/src/main/java/io/codenotary/immudb4j/ImmudbAuthRequestInterceptor.java b/src/main/java/io/codenotary/immudb4j/ImmudbAuthRequestInterceptor.java new file mode 100644 index 0000000..8b4b430 --- /dev/null +++ b/src/main/java/io/codenotary/immudb4j/ImmudbAuthRequestInterceptor.java @@ -0,0 +1,37 @@ +package io.codenotary.immudb4j; + +import io.grpc.*; + + +public class ImmudbAuthRequestInterceptor implements ClientInterceptor { + + private static final String SESSION_ID = "sessionid"; + + private final ImmuClient client; + + public ImmudbAuthRequestInterceptor(ImmuClient client) { + this.client = client; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor method, + CallOptions callOptions, Channel next) { + + return new ForwardingClientCall.SimpleForwardingClientCall(next.newCall(method, callOptions)) { + + @Override + public void start(Listener responseListener, Metadata headers) { + final Session session = client.getSession(); + + if (session != null) { + headers.put(Metadata.Key.of(SESSION_ID, Metadata.ASCII_STRING_MARSHALLER), session.getSessionID()); + } + + super.start(responseListener, headers); + } + + }; + } + +} diff --git a/src/test/java/io/codenotary/immudb4j/UseDatabaseTest.java b/src/main/java/io/codenotary/immudb4j/Session.java similarity index 56% rename from src/test/java/io/codenotary/immudb4j/UseDatabaseTest.java rename to src/main/java/io/codenotary/immudb4j/Session.java index 37edd34..701147c 100644 --- a/src/test/java/io/codenotary/immudb4j/UseDatabaseTest.java +++ b/src/main/java/io/codenotary/immudb4j/Session.java @@ -15,25 +15,28 @@ */ package io.codenotary.immudb4j; -import org.testng.Assert; -import org.testng.annotations.Test; +public class Session { -import java.util.List; + private String username; + private String sessionID; + private String database; + public Session(String sessionID, String username, String database) { + this.sessionID = sessionID; + this.username = username; + this.database = database; + } -public class UseDatabaseTest extends ImmuClientIntegrationTest { - - @Test(testName = "useDatabase") - public void t1() { - - immuClient.login("immudb", "immudb"); - - immuClient.useDatabase("defaultdb"); - - List databases = immuClient.databases(); - Assert.assertTrue(databases.size() > 0); + public String getSessionID() { + return sessionID; + } + + public String getUsername() { + return username; + } - immuClient.logout(); + public String getDatabase() { + return database; } } diff --git a/src/main/proto/schema.proto b/src/main/proto/schema.proto index 92f9fd6..dfa61f9 100644 --- a/src/main/proto/schema.proto +++ b/src/main/proto/schema.proto @@ -18,446 +18,443 @@ import "google/protobuf/struct.proto"; package immudb.schema; -option go_package = "github.com/codenotary/immudb/pkg/api/schema"; option java_package = "io.codenotary.immudb"; option java_outer_classname = "ImmudbProto"; message Key { - bytes key = 1; + bytes key = 1; } message Permission { - string database = 1; - uint32 permission = 2; + string database = 1; + uint32 permission = 2; } message User { - bytes user = 1; - repeated Permission permissions = 3; - string createdby = 4; - string createdat = 5; - bool active = 6; + bytes user = 1; + repeated Permission permissions = 3; + string createdby = 4; + string createdat = 5; + bool active = 6; } message UserList { - repeated User users = 1; + repeated User users = 1; } message CreateUserRequest { - bytes user = 1; - bytes password = 2; - uint32 permission = 3; - string database = 4; + bytes user = 1; + bytes password = 2; + uint32 permission = 3; + string database = 4; } message UserRequest { - bytes user = 1; + bytes user = 1; } message ChangePasswordRequest { - bytes user = 1; - bytes oldPassword = 2; - bytes newPassword = 3; -} - -message LoginRequest { bytes user = 1; - bytes password = 2; -} - -message LoginResponse { - string token = 1; - bytes warning = 2; + bytes oldPassword = 2; + bytes newPassword = 3; } message OpenSessionRequest { - bytes username = 1; - bytes password = 2; - string databaseName = 3; + bytes username = 1; + bytes password = 2; + string databaseName = 3; } message OpenSessionResponse { - string sessionID = 1; - string serverUUID = 2; + string sessionID = 1; + string serverUUID = 2; } //////////////////////////////////////////////////////// message Precondition { - message KeyMustExistPrecondition { - bytes key = 1; - } + message KeyMustExistPrecondition { + bytes key = 1; + } - message KeyMustNotExistPrecondition { - bytes key = 1; - } + message KeyMustNotExistPrecondition { + bytes key = 1; + } - message KeyNotModifiedAfterTXPrecondition { - bytes key = 1; - uint64 txID = 2; - } + message KeyNotModifiedAfterTXPrecondition { + bytes key = 1; + uint64 txID = 2; + } - oneof precondition { - KeyMustExistPrecondition keyMustExist = 1; - KeyMustNotExistPrecondition keyMustNotExist = 2; - KeyNotModifiedAfterTXPrecondition keyNotModifiedAfterTX = 3; - } + oneof precondition { + KeyMustExistPrecondition keyMustExist = 1; + KeyMustNotExistPrecondition keyMustNotExist = 2; + KeyNotModifiedAfterTXPrecondition keyNotModifiedAfterTX = 3; + } } message KeyValue { - bytes key = 1; - bytes value = 2; - KVMetadata metadata = 3; + bytes key = 1; + bytes value = 2; + KVMetadata metadata = 3; } message Entry { - uint64 tx = 1; - bytes key = 2; - bytes value = 3; - Reference referencedBy = 4; - KVMetadata metadata = 5; - bool expired = 6; + uint64 tx = 1; + bytes key = 2; + bytes value = 3; + Reference referencedBy = 4; + KVMetadata metadata = 5; + bool expired = 6; + uint64 revision = 7; } message Reference { - uint64 tx = 1; - bytes key = 2; - uint64 atTx = 3; - KVMetadata metadata = 4; + uint64 tx = 1; + bytes key = 2; + uint64 atTx = 3; + KVMetadata metadata = 4; + uint64 revision = 5; } message Op { - oneof operation { - KeyValue kv = 1; - ZAddRequest zAdd = 2; - ReferenceRequest ref = 3; - } + oneof operation { + KeyValue kv = 1; + ZAddRequest zAdd = 2; + ReferenceRequest ref = 3; + } } message ExecAllRequest { - repeated Op Operations = 1; - bool noWait = 2; - repeated Precondition preconditions = 3; + repeated Op Operations = 1; + bool noWait = 2; + repeated Precondition preconditions = 3; } message Entries { - repeated Entry entries = 1; + repeated Entry entries = 1; } message ZEntry { - bytes set = 1; - bytes key = 2; - Entry entry = 3; - double score = 4; - uint64 atTx = 5; + bytes set = 1; + bytes key = 2; + Entry entry = 3; + double score = 4; + uint64 atTx = 5; } message ZEntries { - repeated ZEntry entries = 1; + repeated ZEntry entries = 1; } message ScanRequest { - bytes seekKey = 1; - bytes endKey = 7; - bytes prefix = 2; - bool desc = 3; - uint64 limit = 4; - uint64 sinceTx = 5; - bool noWait = 6; - bool inclusiveSeek = 8; - bool inclusiveEnd = 9; + bytes seekKey = 1; + bytes endKey = 7; + bytes prefix = 2; + bool desc = 3; + uint64 limit = 4; + uint64 sinceTx = 5; + bool noWait = 6; + bool inclusiveSeek = 8; // If set to true, results will include seekKey + bool inclusiveEnd = 9; // If set to true, results will include endKey if needed + uint64 offset = 10; // Specify the initial entry to be returned by excluding the initial set of entries } message KeyPrefix { - bytes prefix = 1; + bytes prefix = 1; } message EntryCount { - uint64 count = 1; + uint64 count = 1; } /////////////// message Signature { - bytes publicKey = 1; - bytes signature = 2; + bytes publicKey = 1; + bytes signature = 2; } message TxHeader { - uint64 id = 1; - bytes prevAlh = 2; - int64 ts = 3; - int32 nentries = 4; - bytes eH = 5; - uint64 blTxId = 6; - bytes blRoot = 7; - int32 version = 8; - TxMetadata metadata = 9; + uint64 id = 1; + bytes prevAlh = 2; + int64 ts = 3; + int32 nentries = 4; + bytes eH = 5; + uint64 blTxId = 6; + bytes blRoot = 7; + int32 version = 8; + TxMetadata metadata = 9; } message TxMetadata { } message LinearProof { - uint64 sourceTxId = 1; - uint64 TargetTxId = 2; - repeated bytes terms = 3; + uint64 sourceTxId = 1; + uint64 TargetTxId = 2; + repeated bytes terms = 3; } message DualProof { - TxHeader sourceTxHeader = 1; - TxHeader targetTxHeader = 2; + TxHeader sourceTxHeader = 1; + TxHeader targetTxHeader = 2; - repeated bytes inclusionProof = 3; - repeated bytes consistencyProof = 4; + repeated bytes inclusionProof = 3; + repeated bytes consistencyProof = 4; - bytes targetBlTxAlh = 5; - repeated bytes lastInclusionProof = 6; + bytes targetBlTxAlh = 5; + repeated bytes lastInclusionProof = 6; - LinearProof linearProof = 7; + LinearProof linearProof = 7; } message Tx { - TxHeader header = 1; - repeated TxEntry entries = 2; - repeated Entry kvEntries = 3; - repeated ZEntry zEntries = 4; + TxHeader header = 1; + repeated TxEntry entries = 2; + repeated Entry kvEntries = 3; + repeated ZEntry zEntries = 4; } message TxEntry { - bytes key = 1; - bytes hValue = 2; - int32 vLen = 3; - KVMetadata metadata = 4; - bytes value = 5; // value must be ignored when len(value) == 0 and vLen > 0. Otherwise, sha256(value) must be equal to hValue + bytes key = 1; + bytes hValue = 2; + int32 vLen = 3; + KVMetadata metadata = 4; + bytes value = 5; // value must be ignored when len(value) == 0 and vLen > 0. Otherwise, sha256(value) must be equal to hValue } message KVMetadata { - bool deleted = 1; - Expiration expiration = 2; - bool nonIndexable = 3; + bool deleted = 1; + Expiration expiration = 2; + bool nonIndexable = 3; } message Expiration { - int64 expiresAt = 1; + int64 expiresAt = 1; } message VerifiableTx { - Tx tx = 1; - DualProof dualProof = 2; - Signature signature = 3; + Tx tx = 1; + DualProof dualProof = 2; + Signature signature = 3; } ////////////////// message VerifiableEntry { - Entry entry = 1; - VerifiableTx verifiableTx = 2; - InclusionProof inclusionProof = 3; + Entry entry = 1; + VerifiableTx verifiableTx = 2; + InclusionProof inclusionProof = 3; } message InclusionProof { - int32 leaf = 1; - int32 width = 2; - repeated bytes terms = 3; + int32 leaf = 1; + int32 width = 2; + repeated bytes terms = 3; } message SetRequest { - repeated KeyValue KVs = 1; - bool noWait = 2; - repeated Precondition preconditions = 3; + repeated KeyValue KVs = 1; + bool noWait = 2; + repeated Precondition preconditions = 3; } message KeyRequest { - bytes key = 1; - uint64 atTx = 2; - uint64 sinceTx = 3; - bool noWait = 4; - int64 atRevision = 5; + bytes key = 1; + uint64 atTx = 2; // if > 0, query for the value exactly at given transaction + + + // if 0 (and nowait=false), wait for the index to be up=to-date + uint64 sinceTx = 3; + + // if set to true - do not wait for any indexing update considering only the currently indexed state + bool noWait = 4; + + // if > 0, get the nth version of the value, 1 being the first version, 2 being the second and so on + // if < 0, get the historical nth value of the key, -1 being the previous version, -2 being the one before and so on + int64 atRevision = 5; + } message KeyListRequest { - repeated bytes keys = 1; - uint64 sinceTx = 2; + repeated bytes keys = 1; + uint64 sinceTx = 2; } message DeleteKeysRequest { - repeated bytes keys = 1; - uint64 sinceTx = 2; - bool noWait = 3; + repeated bytes keys = 1; + uint64 sinceTx = 2; + bool noWait = 3; } message VerifiableSetRequest { - SetRequest setRequest = 1; - uint64 proveSinceTx = 2; + SetRequest setRequest = 1; + uint64 proveSinceTx = 2; } message VerifiableGetRequest { - KeyRequest keyRequest = 1; - uint64 proveSinceTx = 2; + KeyRequest keyRequest = 1; + uint64 proveSinceTx = 2; +} + +// ServerInfoRequest exists to provide extensibility for rpc ServerInfo. +message ServerInfoRequest {} + +// ServerInfoResponse contains information about the server instance. +message ServerInfoResponse { + // The version of the server instance. + string version = 1; } message HealthResponse { - bool status = 1; - string version = 2; + bool status = 1; + string version = 2; } message DatabaseHealthResponse { - uint32 pendingRequests = 1; - int64 lastRequestCompletedAt = 2; + uint32 pendingRequests = 1; + int64 lastRequestCompletedAt = 2; } message ImmutableState { - string db = 1; - uint64 txId = 2; - bytes txHash = 3; - Signature signature = 4; + string db = 1; + uint64 txId = 2; + bytes txHash = 3; + Signature signature = 4; } message ReferenceRequest { - bytes key = 1; - bytes referencedKey = 2; - uint64 atTx = 3; - bool boundRef = 4; - bool noWait = 5; - repeated Precondition preconditions = 6; + bytes key = 1; + bytes referencedKey = 2; + uint64 atTx = 3; + bool boundRef = 4; + bool noWait = 5; + repeated Precondition preconditions = 6; } message VerifiableReferenceRequest { - ReferenceRequest referenceRequest = 1; - uint64 proveSinceTx = 2; + ReferenceRequest referenceRequest = 1; + uint64 proveSinceTx = 2; } message ZAddRequest { - bytes set = 1; - double score = 2; - bytes key = 3; - uint64 atTx = 4; - bool boundRef = 5; - bool noWait = 6; + bytes set = 1; + double score = 2; + bytes key = 3; + uint64 atTx = 4; + bool boundRef = 5; + bool noWait = 6; } message Score { - double score = 1; + double score = 1; } message ZScanRequest { - bytes set = 1; - bytes seekKey = 2; - double seekScore = 3; - uint64 seekAtTx = 4; - bool inclusiveSeek = 5; - uint64 limit = 6; - bool desc = 7; - Score minScore = 8; - Score maxScore = 9; - uint64 sinceTx = 10; - bool noWait = 11; + bytes set = 1; + bytes seekKey = 2; + double seekScore = 3; + uint64 seekAtTx = 4; + bool inclusiveSeek = 5; + uint64 limit = 6; + bool desc = 7; + Score minScore = 8; + Score maxScore = 9; + uint64 sinceTx = 10; + bool noWait = 11; + uint64 offset = 12; // Specify the initial entry to be returned by excluding the initial set of entries } message HistoryRequest { - bytes key = 1; - uint64 offset = 2; - int32 limit = 3; - bool desc = 4; - uint64 sinceTx = 5; + bytes key = 1; + uint64 offset = 2; // Specify the initial entry to be returned by excluding the initial set of entries + int32 limit = 3; + bool desc = 4; + uint64 sinceTx = 5; } message VerifiableZAddRequest { - ZAddRequest zAddRequest = 1; - uint64 proveSinceTx = 2; + ZAddRequest zAddRequest = 1; + uint64 proveSinceTx = 2; } message TxRequest { - uint64 tx = 1; - EntriesSpec entriesSpec = 2; - uint64 sinceTx = 3; - bool noWait = 4; + uint64 tx = 1; + EntriesSpec entriesSpec = 2; + uint64 sinceTx = 3; + bool noWait = 4; + bool keepReferencesUnresolved = 5; } message EntriesSpec { - EntryTypeSpec kvEntriesSpec = 1; - EntryTypeSpec zEntriesSpec = 2; - EntryTypeSpec sqlEntriesSpec = 3; + EntryTypeSpec kvEntriesSpec = 1; + EntryTypeSpec zEntriesSpec = 2; + EntryTypeSpec sqlEntriesSpec = 3; } message EntryTypeSpec { - EntryTypeAction action = 1; + EntryTypeAction action = 1; } enum EntryTypeAction { - EXCLUDE = 0; - ONLY_DIGEST = 1; - RAW_VALUE = 2; - RESOLVE = 3; + EXCLUDE = 0; + ONLY_DIGEST = 1; + RAW_VALUE = 2; + RESOLVE = 3; } message VerifiableTxRequest { - uint64 tx = 1; - uint64 proveSinceTx = 2; - EntriesSpec entriesSpec = 3; - uint64 sinceTx = 4; - bool noWait = 5; + uint64 tx = 1; + uint64 proveSinceTx = 2; + EntriesSpec entriesSpec = 3; + uint64 sinceTx = 4; + bool noWait = 5; + bool keepReferencesUnresolved = 6; } message TxScanRequest { - uint64 initialTx = 1; - uint32 limit = 2; - bool desc = 3; - EntriesSpec entriesSpec = 4; - uint64 sinceTx = 5; - bool noWait = 6; + uint64 initialTx = 1; + uint32 limit = 2; + bool desc = 3; + EntriesSpec entriesSpec = 4; + uint64 sinceTx = 5; + bool noWait = 6; } message TxList { - repeated Tx txs = 1; + repeated Tx txs = 1; } message ExportTxRequest { - uint64 tx = 1; + uint64 tx = 1; } message Database { - string databaseName = 1; -} - -message DatabaseSettings { - string databaseName = 1; - - bool replica = 2; - string masterDatabase = 3; - string masterAddress = 4; - uint32 masterPort = 5; - string followerUsername = 6; - string followerPassword = 7; - - uint32 fileSize = 8; - uint32 maxKeyLen = 9; - uint32 maxValueLen = 10; - uint32 maxTxEntries = 11; - - bool excludeCommitTime = 12; + string databaseName = 1; } message CreateDatabaseRequest { - string name = 1; - DatabaseNullableSettings settings = 2; + string name = 1; + DatabaseNullableSettings settings = 2; + bool ifNotExists = 3; } message CreateDatabaseResponse { - string name = 1; - DatabaseNullableSettings settings = 2; + string name = 1; + DatabaseNullableSettings settings = 2; + bool alreadyExisted = 3; } message UpdateDatabaseRequest { - string database = 1; - DatabaseNullableSettings settings = 2; + string database = 1; + DatabaseNullableSettings settings = 2; } message UpdateDatabaseResponse { // Reserved to reply with more advanced response later - string database = 1; - DatabaseNullableSettings settings = 2; + string database = 1; + DatabaseNullableSettings settings = 2; } message DatabaseSettingsRequest { @@ -465,279 +462,292 @@ message DatabaseSettingsRequest { } message DatabaseSettingsResponse { - string database = 1; - DatabaseNullableSettings settings = 2; + string database = 1; + DatabaseNullableSettings settings = 2; } message NullableUint32 { - uint32 value = 1; + uint32 value = 1; } message NullableUint64 { - uint64 value = 1; + uint64 value = 1; } message NullableFloat { - float value = 1; + float value = 1; } message NullableBool { - bool value = 1; + bool value = 1; } message NullableString { - string value = 1; + string value = 1; +} + +message NullableMilliseconds { + int64 value = 1; } message DatabaseNullableSettings { - ReplicationNullableSettings replicationSettings = 2; + ReplicationNullableSettings replicationSettings = 2; - NullableUint32 fileSize = 8; - NullableUint32 maxKeyLen = 9; - NullableUint32 maxValueLen = 10; - NullableUint32 maxTxEntries = 11; + NullableUint32 fileSize = 8; + NullableUint32 maxKeyLen = 9; + NullableUint32 maxValueLen = 10; + NullableUint32 maxTxEntries = 11; - NullableBool excludeCommitTime = 12; + NullableBool excludeCommitTime = 12; - NullableUint32 maxConcurrency = 13; - NullableUint32 maxIOConcurrency = 14; + NullableUint32 maxConcurrency = 13; + NullableUint32 maxIOConcurrency = 14; - NullableUint32 txLogCacheSize = 15; - NullableUint32 vLogMaxOpenedFiles = 16; - NullableUint32 txLogMaxOpenedFiles = 17; - NullableUint32 commitLogMaxOpenedFiles = 18; + NullableUint32 txLogCacheSize = 15; + NullableUint32 vLogMaxOpenedFiles = 16; + NullableUint32 txLogMaxOpenedFiles = 17; + NullableUint32 commitLogMaxOpenedFiles = 18; - IndexNullableSettings indexSettings = 19; + IndexNullableSettings indexSettings = 19; - NullableUint32 writeTxHeaderVersion = 20; + NullableUint32 writeTxHeaderVersion = 20; - NullableBool autoload = 21; + NullableBool autoload = 21; + + NullableUint32 readTxPoolSize = 22; + + NullableMilliseconds syncFrequency = 23; + + NullableUint32 writeBufferSize = 24; + + AHTNullableSettings ahtSettings = 25; } message ReplicationNullableSettings { - NullableBool replica = 1; - NullableString masterDatabase = 2; - NullableString masterAddress = 3; - NullableUint32 masterPort = 4; - NullableString followerUsername = 5; - NullableString followerPassword = 6; + NullableBool replica = 1; + NullableString masterDatabase = 2; + NullableString masterAddress = 3; + NullableUint32 masterPort = 4; + NullableString followerUsername = 5; + NullableString followerPassword = 6; } message IndexNullableSettings { - NullableUint32 flushThreshold = 1; - NullableUint32 syncThreshold = 2; - NullableUint32 cacheSize = 3; - NullableUint32 maxNodeSize = 4; - NullableUint32 maxActiveSnapshots = 5; - NullableUint64 renewSnapRootAfter = 6; - NullableUint32 compactionThld = 7; - NullableUint32 delayDuringCompaction = 8; - NullableUint32 nodesLogMaxOpenedFiles = 9; - NullableUint32 historyLogMaxOpenedFiles = 10; - NullableUint32 commitLogMaxOpenedFiles = 11; - NullableUint32 flushBufferSize = 12; - NullableFloat cleanupPercentage = 13; + NullableUint32 flushThreshold = 1; + NullableUint32 syncThreshold = 2; + NullableUint32 cacheSize = 3; + NullableUint32 maxNodeSize = 4; + NullableUint32 maxActiveSnapshots = 5; + NullableUint64 renewSnapRootAfter = 6; + NullableUint32 compactionThld = 7; + NullableUint32 delayDuringCompaction = 8; + NullableUint32 nodesLogMaxOpenedFiles = 9; + NullableUint32 historyLogMaxOpenedFiles = 10; + NullableUint32 commitLogMaxOpenedFiles = 11; + NullableUint32 flushBufferSize = 12; + NullableFloat cleanupPercentage = 13; +} + +message AHTNullableSettings { + NullableUint32 syncThreshold = 1; + NullableUint32 writeBufferSize = 2; } message LoadDatabaseRequest { - string database = 1; - // may add createIfNotExist + string database = 1; + // may add createIfNotExist } message LoadDatabaseResponse { - string database = 1; - // may add setttings + string database = 1; + // may add setttings } message UnloadDatabaseRequest { - string database = 1; + string database = 1; } message UnloadDatabaseResponse { - string database = 1; + string database = 1; } message DeleteDatabaseRequest { - string database = 1; + string database = 1; } message DeleteDatabaseResponse { - string database = 1; + string database = 1; } message FlushIndexRequest { - float cleanupPercentage = 1; - bool synced = 2; + float cleanupPercentage = 1; + bool synced = 2; } message FlushIndexResponse { - string database = 1; + string database = 1; } message Table { - string tableName = 1; + string tableName = 1; } message SQLGetRequest { - string table = 1; - repeated SQLValue pkValues = 2; - uint64 atTx = 3; - uint64 sinceTx = 4; + string table = 1; + repeated SQLValue pkValues = 2; + uint64 atTx = 3; + uint64 sinceTx = 4; } message VerifiableSQLGetRequest { - SQLGetRequest sqlGetRequest = 1; - uint64 proveSinceTx = 2; + SQLGetRequest sqlGetRequest = 1; + uint64 proveSinceTx = 2; } message SQLEntry { - uint64 tx = 1; - bytes key = 2; - bytes value = 3; - KVMetadata metadata = 4; + uint64 tx = 1; + bytes key = 2; + bytes value = 3; + KVMetadata metadata = 4; } message VerifiableSQLEntry { - reserved 6; - SQLEntry sqlEntry = 1; - VerifiableTx verifiableTx = 2; - InclusionProof inclusionProof = 3; - uint32 DatabaseId = 4; - uint32 TableId = 5; - repeated uint32 PKIDs = 16; - map ColNamesById = 8; - map ColIdsByName = 9; - map ColTypesById = 10; - map ColLenById = 11; + reserved 6; + SQLEntry sqlEntry = 1; + VerifiableTx verifiableTx = 2; + InclusionProof inclusionProof = 3; + uint32 DatabaseId = 4; + uint32 TableId = 5; + repeated uint32 PKIDs = 16; + map ColNamesById = 8; + map ColIdsByName = 9; + map ColTypesById = 10; + map ColLenById = 11; } message UseDatabaseReply{ - string token = 1; + string token = 1; } enum PermissionAction { - GRANT = 0; - REVOKE = 1; + GRANT = 0; + REVOKE = 1; } message ChangePermissionRequest { - PermissionAction action = 1; - string username = 2; - string database = 3; - uint32 permission = 4; + PermissionAction action = 1; + string username = 2; + string database = 3; + uint32 permission = 4; } message SetActiveUserRequest { - bool active = 1; - string username = 2; -} - -message DatabaseListResponse { - repeated Database databases = 1; + bool active = 1; + string username = 2; } message DatabaseListRequestV2 { } message DatabaseListResponseV2 { - repeated DatabaseWithSettings databases = 1; + repeated DatabaseWithSettings databases = 1; } message DatabaseWithSettings { - string name = 1; - DatabaseNullableSettings settings = 2; - bool loaded = 3; + string name = 1; + DatabaseNullableSettings settings = 2; + bool loaded = 3; } message Chunk { - bytes content = 1; + bytes content = 1; } message UseSnapshotRequest { - uint64 sinceTx = 1; - uint64 asBeforeTx = 2; + uint64 sinceTx = 1; + uint64 asBeforeTx = 2; } message SQLExecRequest { - string sql = 1; - repeated NamedParam params = 2; - bool noWait = 3; + string sql = 1; + repeated NamedParam params = 2; + bool noWait = 3; } message SQLQueryRequest { - string sql = 1; - repeated NamedParam params = 2; - bool reuseSnapshot = 3; + string sql = 1; + repeated NamedParam params = 2; + bool reuseSnapshot = 3; } message NamedParam { - string name = 1; - SQLValue value = 2; + string name = 1; + SQLValue value = 2; } message SQLExecResult { - repeated CommittedSQLTx txs = 5; - bool ongoingTx = 6; + repeated CommittedSQLTx txs = 5; + bool ongoingTx = 6; } message CommittedSQLTx { - TxHeader header = 1; - uint32 updatedRows = 2; - map lastInsertedPKs = 3; - map firstInsertedPKs = 4; + TxHeader header = 1; + uint32 updatedRows = 2; + map lastInsertedPKs = 3; + map firstInsertedPKs = 4; } message SQLQueryResult { - repeated Column columns = 2; - repeated Row rows = 1; + repeated Column columns = 2; + repeated Row rows = 1; } message Column { - string name = 1; - string type = 2; + string name = 1; + string type = 2; } message Row { - repeated string columns = 1; - repeated SQLValue values = 2; + repeated string columns = 1; + repeated SQLValue values = 2; } message SQLValue { - oneof value { - google.protobuf.NullValue null = 1; - int64 n = 2; - string s = 3; - bool b = 4; - bytes bs = 5; - int64 ts = 6; - } + oneof value { + google.protobuf.NullValue null = 1; + int64 n = 2; + string s = 3; + bool b = 4; + bytes bs = 5; + int64 ts = 6; + } } enum TxMode { - ReadOnly = 0; - WriteOnly = 1; - ReadWrite = 2; + ReadOnly = 0; + WriteOnly = 1; + ReadWrite = 2; } message NewTxRequest { - TxMode mode = 1; + TxMode mode = 1; } message NewTxResponse { - string transactionID = 1; + string transactionID = 1; } message ErrorInfo { - string code = 1; - string cause = 2; + string code = 1; + string cause = 2; } message DebugInfo { - string stack = 1; + string stack = 1; } message RetryInfo { - int32 retry_delay = 1; + int32 retry_delay = 1; } // immudb gRPC & REST service @@ -768,14 +778,6 @@ service ImmuService { rpc TxSQLExec(SQLExecRequest) returns (google.protobuf.Empty) {}; rpc TxSQLQuery(SQLQueryRequest) returns (SQLQueryResult) {}; - rpc Login (LoginRequest) returns (LoginResponse){ - option deprecated = true; - }; - - rpc Logout (google.protobuf.Empty) returns (google.protobuf.Empty){ - option deprecated = true; - }; - rpc Set (SetRequest) returns (TxHeader){ }; @@ -800,14 +802,6 @@ service ImmuService { rpc Scan(ScanRequest) returns (Entries){ }; - // NOT YET SUPPORTED - rpc Count(KeyPrefix) returns (EntryCount){ - }; - - // NOT YET SUPPORTED - rpc CountAll(google.protobuf.Empty) returns (EntryCount){ - }; - rpc TxById(TxRequest) returns (Tx){ }; @@ -820,11 +814,13 @@ service ImmuService { rpc History(HistoryRequest) returns (Entries){ }; - rpc Health (google.protobuf.Empty) returns (HealthResponse){ - }; + // ServerInfo returns information about the server instance. + // ServerInfoRequest is defined for future extensions. + rpc ServerInfo (ServerInfoRequest) returns (ServerInfoResponse){ + }; rpc DatabaseHealth (google.protobuf.Empty) returns (DatabaseHealthResponse){ - }; + }; rpc CurrentState (google.protobuf.Empty) returns (ImmutableState){ }; diff --git a/src/test/java/io/codenotary/immudb4j/BasicImmuClientTest.java b/src/test/java/io/codenotary/immudb4j/BasicImmuClientTest.java index e3f214d..eaca0a5 100644 --- a/src/test/java/io/codenotary/immudb4j/BasicImmuClientTest.java +++ b/src/test/java/io/codenotary/immudb4j/BasicImmuClientTest.java @@ -24,16 +24,14 @@ import java.util.ArrayList; import java.util.List; - public class BasicImmuClientTest extends ImmuClientIntegrationTest { @Test(testName = "set, get") public void t1() throws VerificationException, CorruptedDataException { - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); - byte[] v0 = new byte[]{0, 1, 2, 3}; - byte[] v1 = new byte[]{3, 2, 1, 0}; + byte[] v0 = new byte[] { 0, 1, 2, 3 }; + byte[] v1 = new byte[] { 3, 2, 1, 0 }; TxHeader hdr0 = immuClient.set("k0", v0); Assert.assertNotNull(hdr0); @@ -53,7 +51,7 @@ public void t1() throws VerificationException, CorruptedDataException { Entry ventry1 = immuClient.verifiedGet("k1"); Assert.assertEquals(ventry1.getValue(), v1); - byte[] v2 = new byte[]{0, 1, 2, 3}; + byte[] v2 = new byte[] { 0, 1, 2, 3 }; TxHeader hdr2 = immuClient.verifiedSet("k2", v2); Assert.assertNotNull(hdr2); @@ -65,21 +63,20 @@ public void t1() throws VerificationException, CorruptedDataException { Assert.assertNotNull(e); Assert.assertEquals(e.getValue(), v2); - immuClient.logout(); + immuClient.closeSession(); } @Test(testName = "setAll, getAll") public void t2() { - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); List keys = new ArrayList<>(); keys.add("k0"); keys.add("k1"); List values = new ArrayList<>(); - values.add(new byte[]{0, 1, 0, 1}); - values.add(new byte[]{1, 0, 1, 0}); + values.add(new byte[] { 0, 1, 0, 1 }); + values.add(new byte[] { 1, 0, 1, 0 }); KVListBuilder kvListBuilder = KVListBuilder.newBuilder(); @@ -109,7 +106,7 @@ public void t2() { Assert.assertEquals(entry.getValue(), values.get(i)); } - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/HTreeTest.java b/src/test/java/io/codenotary/immudb4j/HTreeTest.java index f68cf4c..9c74e5c 100644 --- a/src/test/java/io/codenotary/immudb4j/HTreeTest.java +++ b/src/test/java/io/codenotary/immudb4j/HTreeTest.java @@ -17,7 +17,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.security.NoSuchAlgorithmException; import org.testng.Assert; import org.testng.annotations.Test; @@ -29,13 +28,11 @@ public class HTreeTest { @Test(testName = "Empty HTree", expectedExceptions = IllegalArgumentException.class) public void t1() { - new HTree(0); } @Test(testName = "HTree init & root", expectedExceptions = IllegalStateException.class) public void t2() { - final int maxWidth = 1000; HTree tree = new HTree(maxWidth); @@ -46,7 +43,6 @@ public void t2() { @Test(testName = "HTree buildWith, root, inclusionProof, verifyInclusion") public void t3() { - final int maxWidth = 1000; HTree tree = new HTree(maxWidth); diff --git a/src/test/java/io/codenotary/immudb4j/HistoryTest.java b/src/test/java/io/codenotary/immudb4j/HistoryTest.java index 4618ca7..f0b0cce 100644 --- a/src/test/java/io/codenotary/immudb4j/HistoryTest.java +++ b/src/test/java/io/codenotary/immudb4j/HistoryTest.java @@ -17,7 +17,6 @@ import io.codenotary.immudb4j.exceptions.CorruptedDataException; import io.codenotary.immudb4j.exceptions.KeyNotFoundException; -import io.grpc.StatusRuntimeException; import org.testng.Assert; import org.testng.annotations.Test; @@ -28,9 +27,7 @@ public class HistoryTest extends ImmuClientIntegrationTest { @Test(testName = "set, history", priority = 2) public void t1() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); byte[] value1 = {0, 1, 2, 3}; byte[] value2 = {4, 5, 6, 7}; @@ -80,7 +77,7 @@ public void t1() { // exception is expected here } - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/ListDatabasesTest.java b/src/test/java/io/codenotary/immudb4j/ListDatabasesTest.java index de15f97..fc19652 100644 --- a/src/test/java/io/codenotary/immudb4j/ListDatabasesTest.java +++ b/src/test/java/io/codenotary/immudb4j/ListDatabasesTest.java @@ -23,8 +23,7 @@ public class ListDatabasesTest extends ImmuClientIntegrationTest { @Test(testName = "databases") public void t1() { - - immuClient.login("immudb", "immudb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); List databases = immuClient.databases(); if (databases.size() > 0) { @@ -36,7 +35,7 @@ public void t1() { System.out.print(">>> There are no databases."); } - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/ListUsersTest.java b/src/test/java/io/codenotary/immudb4j/ListUsersTest.java index 5ee4e82..6e8f762 100644 --- a/src/test/java/io/codenotary/immudb4j/ListUsersTest.java +++ b/src/test/java/io/codenotary/immudb4j/ListUsersTest.java @@ -21,12 +21,11 @@ public class ListUsersTest extends ImmuClientIntegrationTest { @Test(testName = "listUsers") public void t1() { - - immuClient.login("immudb", "immudb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); immuClient.listUsers().forEach(user -> System.out.printf(">>> Got user %s", user)); - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/LoginAndHealthCheckAndCleanIndexTest.java b/src/test/java/io/codenotary/immudb4j/LoginAndHealthCheckAndCleanIndexTest.java index fa049c9..4b46e30 100644 --- a/src/test/java/io/codenotary/immudb4j/LoginAndHealthCheckAndCleanIndexTest.java +++ b/src/test/java/io/codenotary/immudb4j/LoginAndHealthCheckAndCleanIndexTest.java @@ -21,23 +21,21 @@ public class LoginAndHealthCheckAndCleanIndexTest extends ImmuClientIntegrationTest { - @Test(testName = "login (with default credentials), healthCheck, logout") + @Test(testName = "openSession (with default credentials), healthCheck, logout") public void t1() { - - immuClient.login("immudb", "immudb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); boolean isHealthy = immuClient.healthCheck(); Assert.assertTrue(isHealthy); - immuClient.compactIndex(); + immuClient.flushIndex(10.0f, true); - immuClient.logout(); + immuClient.closeSession(); } - @Test(testName = "login (with wrong credentials)", expectedExceptions = StatusRuntimeException.class) + @Test(testName = "openSession (with wrong credentials)", expectedExceptions = StatusRuntimeException.class) public void t2() { - - immuClient.login("immudb", "incorrect_password"); + immuClient.openSession("immudb", "incorrect_password", "defaultdb"); } } diff --git a/src/test/java/io/codenotary/immudb4j/MultidatabaseTest.java b/src/test/java/io/codenotary/immudb4j/MultidatabaseTest.java index 4d0de41..777e19e 100644 --- a/src/test/java/io/codenotary/immudb4j/MultidatabaseTest.java +++ b/src/test/java/io/codenotary/immudb4j/MultidatabaseTest.java @@ -26,13 +26,15 @@ public class MultidatabaseTest extends ImmuClientIntegrationTest { @Test(testName = "Interacting with multiple databases (creating them, setting, and getting, listing)") public void t1() throws VerificationException { - - immuClient.login("immudb", "immudb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); immuClient.createDatabase("db1"); immuClient.createDatabase("db2"); - immuClient.useDatabase("db1"); + immuClient.closeSession(); + + immuClient.openSession("immudb", "immudb", "db1"); + byte[] v0 = new byte[]{0, 1, 2, 3}; try { immuClient.set("k0", v0); @@ -40,7 +42,9 @@ public void t1() throws VerificationException { Assert.fail("Failed at set.", e); } - immuClient.useDatabase("db2"); + immuClient.closeSession(); + + immuClient.openSession("immudb", "immudb", "db2"); byte[] v1 = new byte[]{3, 2, 1, 0}; try { @@ -49,7 +53,9 @@ public void t1() throws VerificationException { Assert.fail("Failed at set.", e); } - immuClient.useDatabase("db1"); + immuClient.closeSession(); + + immuClient.openSession("immudb", "immudb", "db1"); Entry entry1 = immuClient.get("k0"); Assert.assertNotNull(entry1); @@ -59,7 +65,9 @@ public void t1() throws VerificationException { Assert.assertNotNull(ventry1); Assert.assertEquals(ventry1.getValue(), v0); - immuClient.useDatabase("db2"); + immuClient.closeSession(); + + immuClient.openSession("immudb", "immudb", "db2"); Entry entry2 = immuClient.get("k1"); Assert.assertEquals(entry2.getValue(), v1); @@ -74,7 +82,7 @@ public void t1() throws VerificationException { Assert.assertTrue(dbs.contains("db1")); Assert.assertTrue(dbs.contains("db2")); - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/MultithreadTest.java b/src/test/java/io/codenotary/immudb4j/MultithreadTest.java index 07d3f07..95fbe19 100644 --- a/src/test/java/io/codenotary/immudb4j/MultithreadTest.java +++ b/src/test/java/io/codenotary/immudb4j/MultithreadTest.java @@ -29,9 +29,7 @@ public class MultithreadTest extends ImmuClientIntegrationTest { @Test(testName = "Multithread without key overlap") public void t1() throws InterruptedException, VerificationException { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); final int threadCount = 10; final int keyCount = 100; @@ -71,13 +69,13 @@ public void t1() throws InterruptedException, VerificationException { immuClient.verifiedGet("t" + i + "k" + i); } } + + immuClient.closeSession(); } @Test(testName = "Multithread with key overlap") public void t2() throws InterruptedException, VerificationException { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); final int threadCount = 10; final int keyCount = 100; @@ -118,6 +116,8 @@ public void t2() throws InterruptedException, VerificationException { immuClient.verifiedGet("k" + i); } } + + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/ReferenceTest.java b/src/test/java/io/codenotary/immudb4j/ReferenceTest.java index 99c4e84..7bc4c9c 100644 --- a/src/test/java/io/codenotary/immudb4j/ReferenceTest.java +++ b/src/test/java/io/codenotary/immudb4j/ReferenceTest.java @@ -25,8 +25,7 @@ public class ReferenceTest extends ImmuClientIntegrationTest { @Test(testName = "set, setReference, setReferenceAt") public void t1() { - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); byte[] key = "testRef".getBytes(StandardCharsets.UTF_8); byte[] val = "abc".getBytes(StandardCharsets.UTF_8); @@ -57,7 +56,7 @@ public void t1() { } Assert.assertNotNull(ref2TxHdr); - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/ScanTest.java b/src/test/java/io/codenotary/immudb4j/ScanTest.java index eda915d..3a66d8c 100644 --- a/src/test/java/io/codenotary/immudb4j/ScanTest.java +++ b/src/test/java/io/codenotary/immudb4j/ScanTest.java @@ -26,9 +26,7 @@ public class ScanTest extends ImmuClientIntegrationTest { @Test(testName = "scan", priority = 2) public void t1() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); byte[] value1 = {0, 1, 2, 3}; byte[] value2 = {4, 5, 6, 7}; @@ -53,14 +51,12 @@ public void t1() { Assert.assertEquals(immuClient.scan("scan", "scan1", 1, false).size(), 1); - immuClient.logout(); + immuClient.closeSession(); } @Test(testName = "set, zAdd, zScan", priority = 3) public void t2() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); byte[] value1 = {0, 1, 2, 3}; byte[] value2 = {4, 5, 6, 7}; @@ -91,7 +87,7 @@ public void t2() { List zScan2 = immuClient.zScan("set2", 5, false); Assert.assertEquals(zScan2.size(), 2); - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/SetAllAndGetAllTest.java b/src/test/java/io/codenotary/immudb4j/SetAllAndGetAllTest.java index e35a92c..71d91aa 100644 --- a/src/test/java/io/codenotary/immudb4j/SetAllAndGetAllTest.java +++ b/src/test/java/io/codenotary/immudb4j/SetAllAndGetAllTest.java @@ -26,9 +26,7 @@ public class SetAllAndGetAllTest extends ImmuClientIntegrationTest { @Test(testName = "setAll & getAll") public void t1() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); String key1 = "sga-key1"; byte[] val1 = new byte[] { 1 }; @@ -59,7 +57,7 @@ public void t1() { Assert.assertEquals(got.get(i).getValue(), kvs.get(i).getValue(), String.format("Expected: %s got: %s", kvs.get(i), got.get(i))); } - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/SetAndGetTest.java b/src/test/java/io/codenotary/immudb4j/SetAndGetTest.java index 2e15ec3..6f39d81 100644 --- a/src/test/java/io/codenotary/immudb4j/SetAndGetTest.java +++ b/src/test/java/io/codenotary/immudb4j/SetAndGetTest.java @@ -26,9 +26,7 @@ public class SetAndGetTest extends ImmuClientIntegrationTest { @Test(testName = "set, get") public void t1() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); String key = "key1"; byte[] val = new byte[]{1, 2, 3, 4, 5}; @@ -69,7 +67,7 @@ public void t1() { Assert.fail("key not found exception expected"); } - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/ShutdownTest.java b/src/test/java/io/codenotary/immudb4j/ShutdownTest.java index 542ec99..6df992c 100644 --- a/src/test/java/io/codenotary/immudb4j/ShutdownTest.java +++ b/src/test/java/io/codenotary/immudb4j/ShutdownTest.java @@ -27,13 +27,8 @@ public void t1() { Assert.assertFalse(immuClient.isShutdown()); immuClient.shutdown(); - - Assert.assertTrue(immuClient.isShutdown()); - - Assert.assertFalse(immuClient.isConnected()); - - immuClient.login("immudb", "immudb"); - + + immuClient.openSession("immudb", "immudb", "defaultdb"); } } diff --git a/src/test/java/io/codenotary/immudb4j/StateTest.java b/src/test/java/io/codenotary/immudb4j/StateTest.java index 1a03876..2e5ab96 100644 --- a/src/test/java/io/codenotary/immudb4j/StateTest.java +++ b/src/test/java/io/codenotary/immudb4j/StateTest.java @@ -30,9 +30,7 @@ public class StateTest extends ImmuClientIntegrationTest { @Test(testName = "currentState") public void t2() throws VerificationException { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); ImmuState currState = immuClient.currentState(); @@ -50,7 +48,7 @@ public void t2() throws VerificationException { publicKey = CryptoUtils.getDERPublicKey(publicKeyFile.getAbsolutePath()); } catch (Exception e) { // Not a test itself fault, but we cannot continue it. - immuClient.logout(); + immuClient.closeSession(); return; } @@ -61,12 +59,11 @@ public void t2() throws VerificationException { ImmuState someState = new ImmuState(currState.getDatabase(), currState.getTxId(), currState.getTxHash(), new byte[1]); Assert.assertFalse(someState.checkSignature(publicKey)); - immuClient.logout(); + immuClient.closeSession(); } @Test(testName = "currentState with server signature checking, but only on the client side") public void t3() { - // Provisioning the client side with the public key file. ClassLoader classLoader = getClass().getClassLoader(); File publicKeyFile = new File(Objects.requireNonNull(classLoader.getResource(publicKeyResource)).getFile()); @@ -85,8 +82,7 @@ public void t3() { return; } - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); try { immuClient.currentState(); @@ -96,7 +92,7 @@ public void t3() { // (this feature is active when starting it like: `immudb --signingKey test_private_key.pem`). } - immuClient.logout(); + immuClient.closeSession(); } @@ -128,8 +124,7 @@ public void t4() { return; } - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); try { ImmuState state = immuClient.currentState(); @@ -140,7 +135,7 @@ public void t4() { Assert.fail(e.getMessage(), e.getCause()); } - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/TxTest.java b/src/test/java/io/codenotary/immudb4j/TxTest.java index a58cc7a..72b2493 100644 --- a/src/test/java/io/codenotary/immudb4j/TxTest.java +++ b/src/test/java/io/codenotary/immudb4j/TxTest.java @@ -28,9 +28,7 @@ public class TxTest extends ImmuClientIntegrationTest { @Test(testName = "verifiedSet, txById, verifiedTxById") public void t1() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); String key = "test-txid"; byte[] val = "test-txid-value".getBytes(StandardCharsets.UTF_8); @@ -59,14 +57,12 @@ public void t1() { Assert.assertEquals(txHdr.getId(), tx.getHeader().getId()); - immuClient.logout(); + immuClient.closeSession(); } @Test(testName = "set, txScan") public void t2() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); String key = "txtest-t2"; byte[] val1 = "immuRocks!".getBytes(StandardCharsets.UTF_8); @@ -93,7 +89,7 @@ public void t2() { Assert.assertNotNull(immuClient.txScan(initialTxId)); - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/src/test/java/io/codenotary/immudb4j/UserMgmtTest.java b/src/test/java/io/codenotary/immudb4j/UserMgmtTest.java index 7681568..f338250 100644 --- a/src/test/java/io/codenotary/immudb4j/UserMgmtTest.java +++ b/src/test/java/io/codenotary/immudb4j/UserMgmtTest.java @@ -23,21 +23,17 @@ import java.util.Collections; import java.util.List; -import java.util.Optional; - public class UserMgmtTest extends ImmuClientIntegrationTest { @Test(testName = "createUser, listUsers", priority = 100) public void t1() { - String database = "defaultdb"; String username = "testCreateUser"; String password = "testTest123!"; Permission permission = Permission.PERMISSION_RW; - immuClient.login("immudb", "immudb"); - immuClient.useDatabase(database); + immuClient.openSession("immudb", "immudb", database); // Should not contain testCreateUser. Skipping it as not valid for the current unit tests setup // (where a clean immudb server is started for each Test class). @@ -68,14 +64,12 @@ public void t1() { // Assert.assertEquals(user.getCreatedBy(), "immudb"); // Assert.assertEquals(user.getPermissions().get(0), permission); - immuClient.logout(); + immuClient.closeSession(); } @Test(testName = "createUser, changePassword", priority = 101) public void t2() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); try { immuClient.createUser("testUser", "testTest123!", Permission.PERMISSION_ADMIN, "defaultdb"); @@ -86,18 +80,19 @@ public void t2() { immuClient.changePassword("testUser", "testTest123!", "newTestTest123!"); - immuClient.logout(); + immuClient.closeSession(); // This must fail. try { - immuClient.login("testUser", "testTest123!"); - Assert.fail("Login with wrong (old) password must fail."); + immuClient.openSession("testUser", "testTest123", "defaultdb"); + Assert.fail("should fail with wrong (old) password must fail."); } catch (StatusRuntimeException e) { // Login failed, everything's fine. } - immuClient.login("testUser", "newTestTest123!"); - immuClient.logout(); + immuClient.openSession("testUser", "newTestTest123!", "defaultdb"); + + immuClient.closeSession(); // Some basic test to temporary (until t1 test above can be used) increase the code coverage. User myUser = new User.UserBuilder().setUser("myUsername").setCreatedAt("someTimestamp").setCreatedBy("me") diff --git a/src/test/java/io/codenotary/immudb4j/VerifiedSetAndGetTest.java b/src/test/java/io/codenotary/immudb4j/VerifiedSetAndGetTest.java index c85873a..a0a812d 100644 --- a/src/test/java/io/codenotary/immudb4j/VerifiedSetAndGetTest.java +++ b/src/test/java/io/codenotary/immudb4j/VerifiedSetAndGetTest.java @@ -26,9 +26,7 @@ public class VerifiedSetAndGetTest extends ImmuClientIntegrationTest { @Test(testName = "set, verifiedGet") public void t1() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); String key = "vsg"; byte[] val = "test-set-vget".getBytes(StandardCharsets.UTF_8); @@ -48,14 +46,12 @@ public void t1() { Assert.assertEquals(val, vEntry.getValue()); - immuClient.logout(); + immuClient.closeSession(); } @Test(testName = "verifiedSet, verifiedGet, verifiedGetAt, verifiedGetSince") public void t2() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); byte[] key = "vsg".getBytes(StandardCharsets.UTF_8); byte[] val = "test-vset-vget".getBytes(StandardCharsets.UTF_8); @@ -96,7 +92,7 @@ public void t2() { } // Assert.assertNotNull(txMd); - immuClient.logout(); + immuClient.closeSession(); } diff --git a/src/test/java/io/codenotary/immudb4j/ZAddTest.java b/src/test/java/io/codenotary/immudb4j/ZAddTest.java index f8030ce..eb5be6d 100644 --- a/src/test/java/io/codenotary/immudb4j/ZAddTest.java +++ b/src/test/java/io/codenotary/immudb4j/ZAddTest.java @@ -26,9 +26,7 @@ public class ZAddTest extends ImmuClientIntegrationTest { @Test(testName = "zAdd, verifiedZAdd, verifiedZAddAt") public void t1() { - - immuClient.login("immudb", "immudb"); - immuClient.useDatabase("defaultdb"); + immuClient.openSession("immudb", "immudb", "defaultdb"); String set = "test-zadd"; String key1 = "test-zadd-key1"; @@ -61,7 +59,7 @@ public void t1() { } Assert.assertNotNull(txHdr); - immuClient.logout(); + immuClient.closeSession(); } } diff --git a/tests.sh b/tests.sh index 0825e5d..3095cc7 100755 --- a/tests.sh +++ b/tests.sh @@ -9,19 +9,20 @@ echo ## Unit Tests TESTS="${TESTS} BasicImmuClientTest" +TESTS="${TESTS} HistoryTest" TESTS="${TESTS} HTreeTest" TESTS="${TESTS} ListDatabasesTest ListUsersTest" -TESTS="${TESTS} LoginAndHealthCheckTest" +TESTS="${TESTS} LoginAndHealthCheckAndCleanIndexTest" TESTS="${TESTS} MultidatabaseTest MultithreadTest" TESTS="${TESTS} ReferenceTest" -TESTS="${TESTS} ScanAndHistoryTest" -TESTS="${TESTS} SetAndGetTest SetAllAndGetAllTest" -TESTS="${TESTS} ShutdownTest" +TESTS="${TESTS} ScanTest" +TESTS="${TESTS} SetAllAndGetAllTest SetAndGetTest" TESTS="${TESTS} StateTest" TESTS="${TESTS} TxTest" -TESTS="${TESTS} UseDatabaseTest UserMgmtTest" +TESTS="${TESTS} UserMgmtTest" TESTS="${TESTS} VerifiedSetAndGetTest" TESTS="${TESTS} ZAddTest" +TESTS="${TESTS} ShutdownTest" # ----------------------------------------------------------------------------- From 90bac3c69af19ac0379e1a7af469b62042d8217d Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 1 Nov 2022 16:51:41 -0300 Subject: [PATCH 4/4] chore: session keep alive heartbeat Signed-off-by: Jeronimo Irazabal --- .../io/codenotary/immudb4j/ImmuClient.java | 36 ++++++++++++++----- .../java/io/codenotary/immudb4j/Session.java | 8 +---- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/main/java/io/codenotary/immudb4j/ImmuClient.java b/src/main/java/io/codenotary/immudb4j/ImmuClient.java index 277fd97..99ad078 100644 --- a/src/main/java/io/codenotary/immudb4j/ImmuClient.java +++ b/src/main/java/io/codenotary/immudb4j/ImmuClient.java @@ -37,6 +37,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -50,16 +52,19 @@ public class ImmuClient { private final PublicKey serverSigningKey; private final ImmuStateHolder stateHolder; + private long keepAlivePeriod; private ManagedChannel channel; private final ImmuServiceGrpc.ImmuServiceBlockingStub stub; private Session session; - + private Timer sessionHeartBeat; + public ImmuClient(Builder builder) { this.stateHolder = builder.getStateHolder(); this.serverSigningKey = builder.getServerSigningKey(); + this.keepAlivePeriod = builder.getKeepAlivePeriod(); this.stub = createStubFrom(builder); } @@ -117,7 +122,20 @@ public synchronized void openSession(String username, String password, String da final ImmudbProto.OpenSessionResponse resp = this.stub.openSession(req); - this.session = new Session(resp.getSessionID(), username, database); + this.session = new Session(resp.getSessionID(), database); + + this.sessionHeartBeat = new Timer(); + + this.sessionHeartBeat.schedule(new TimerTask() { + @Override + public void run() { + try { + stub.keepAlive(Empty.getDefaultInstance()); + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 0, keepAlivePeriod); } public synchronized void closeSession() { @@ -125,6 +143,8 @@ public synchronized void closeSession() { throw new IllegalStateException("no open session"); } + this.sessionHeartBeat.cancel(); + try { this.stub.closeSession(Empty.getDefaultInstance()); } finally { @@ -1133,7 +1153,7 @@ public static class Builder { private PublicKey serverSigningKey; - private boolean withAuth; + private long keepAlivePeriod; private ImmuStateHolder stateHolder; @@ -1141,7 +1161,7 @@ private Builder() { this.serverUrl = "localhost"; this.serverPort = 3322; this.stateHolder = new SerializableImmuStateHolder(); - this.withAuth = true; + this.keepAlivePeriod = 60 * 1000; // 1 minute } public ImmuClient build() { @@ -1179,12 +1199,12 @@ public Builder withServerSigningKey(String publicKeyFilename) throws Exception { return this; } - public boolean isWithAuth() { - return withAuth; + public long getKeepAlivePeriod() { + return keepAlivePeriod; } - public Builder withAuth(boolean withAuth) { - this.withAuth = withAuth; + public Builder withKeepAlivePeriod(long keepAlivePeriod) { + this.keepAlivePeriod = keepAlivePeriod; return this; } diff --git a/src/main/java/io/codenotary/immudb4j/Session.java b/src/main/java/io/codenotary/immudb4j/Session.java index 701147c..5b4d130 100644 --- a/src/main/java/io/codenotary/immudb4j/Session.java +++ b/src/main/java/io/codenotary/immudb4j/Session.java @@ -17,23 +17,17 @@ public class Session { - private String username; private String sessionID; private String database; - public Session(String sessionID, String username, String database) { + public Session(String sessionID, String database) { this.sessionID = sessionID; - this.username = username; this.database = database; } public String getSessionID() { return sessionID; } - - public String getUsername() { - return username; - } public String getDatabase() { return database;