Conversation
There was a problem hiding this comment.
Summary of Changes
Hello @robfrank, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly enhances ArcadeDB's communication capabilities by integrating a gRPC protocol. This new feature provides a more performant and robust alternative to the existing HTTP API, particularly beneficial for high-throughput data operations and real-time streaming. The changes span both server and client components, ensuring a comprehensive and well-tested implementation, alongside improvements to server-side monitoring for better operational visibility.
Highlights
- New gRPC Protocol Implementation: A complete gRPC layer has been added, including .proto definitions for various database operations (CRUD, queries, commands, transactions, admin tasks).
- Dedicated gRPC Client Library: A new arcadedb-grpc-client module provides a Java client that uses the gRPC protocol, offering methods for standard database interactions as well as new streaming and bulk ingest capabilities.
- Server-Side gRPC Plugin: The arcadedb-grpcw module introduces GrpcServerPlugin to enable and configure the gRPC server within ArcadeDB, supporting standard and XDS modes, TLS, and message compression.
- Enhanced Observability and Security: Server-side gRPC includes interceptors for logging, metrics (Micrometer), authentication, and compression, providing better insights and control over gRPC traffic.
- Comprehensive Testing and Benchmarking: New end-to-end tests (RemoteGrpcDatabaseTest, RemoteGrpcDatabaseRegressionTest) and a benchmarking tool (ArcadeDbHTTPTvsGRPCBench) have been added to validate functionality and compare performance against the existing HTTP protocol.
- Improved Server Monitoring: The ServerMonitor has been refactored to leverage JMX for more robust JVM monitoring, including heap and safepoint metrics.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
Coverage summary from CodacySee diff coverage on Codacy
Coverage variation details
Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: Diff coverage details
Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: See your quality gate settings Change summary preferences |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces comprehensive gRPC support for ArcadeDB, including a new gRPC client, server plugin, and Protobuf definitions. The implementation covers streaming queries, bulk inserts, record operations, and transaction management, which is a significant and valuable addition. My review focuses on improving robustness, performance, and maintainability. Key areas for improvement include removing hardcoded debug statements, addressing a bug in JDK version compatibility, making debugging features opt-in, and replacing fragile reflection-based calls with type-safe interfaces. Additionally, there are some cleanup opportunities regarding temporary or duplicated files.
| private static String legacyTidName(Thread t) { | ||
| return t.threadId() + ":" + t.getName(); | ||
| } |
There was a problem hiding this comment.
The legacyTidName method is intended as a fallback for JDKs older than 19, but it incorrectly calls t.threadId(), which was introduced in Java 19. This will cause a NoSuchMethodError on older supported JDKs. The correct fallback should use the deprecated t.getId() to maintain compatibility.
| private static String legacyTidName(Thread t) { | |
| return t.threadId() + ":" + t.getName(); | |
| } | |
| private static String legacyTidName(Thread t) { | |
| return t.getId() + ":" + t.getName(); | |
| } |
| @SuppressWarnings("unchecked") | ||
| private Collection<String> getDatabaseNames() { | ||
| // Replace with your server API: | ||
| // e.g., ((ArcadeDBServer)server).getDatabaseNames() | ||
| try { | ||
| var m = server.getClass().getMethod("getDatabaseNames"); | ||
| Object res = m.invoke(server); | ||
| if (res instanceof Collection<?> c) { | ||
| return (Collection<String>) c; | ||
| } else if (res instanceof String[] arr) { | ||
| return Arrays.asList(arr); | ||
| } | ||
| } catch (Throwable ignore) { | ||
| } | ||
| return Collections.emptyList(); | ||
| } | ||
|
|
||
| private boolean containsDatabaseIgnoreCase(String name) { | ||
| for (String n : getDatabaseNames()) { | ||
| if (n.equalsIgnoreCase(name)) | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Create DB physically with READ_WRITE mode. Adjust to your server signature. | ||
| */ | ||
| private void createDatabasePhysical(String name) throws Exception { | ||
| // Typical signature: createDatabase(String, ComponentFile.MODE) | ||
| var m = server.getClass().getMethod("createDatabase", String.class, ComponentFile.MODE.class); | ||
| m.invoke(server, name, ComponentFile.MODE.READ_WRITE); | ||
| } | ||
|
|
||
| /** | ||
| * Drop DB physically. Prefer API with 'removeFiles' boolean if available. | ||
| */ | ||
| private void dropDatabasePhysical(String name) throws Exception { | ||
| try { | ||
| var m = server.getClass().getMethod("dropDatabase", String.class, boolean.class); | ||
| m.invoke(server, name, Boolean.TRUE); | ||
| } catch (NoSuchMethodException nsme) { | ||
| // Fallback: dropDatabase(String) if present | ||
| var m2 = server.getClass().getMethod("dropDatabase", String.class); | ||
| m2.invoke(server, name); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Open database for read ops. Adjust to your server's open/get method. | ||
| */ | ||
| private Database openDatabase(String name) throws Exception { | ||
| // Commonly: server.getDatabase(name) or server.openDatabase(name) | ||
| try { | ||
| var m = server.getClass().getMethod("getDatabase", String.class); | ||
| Object db = m.invoke(server, name); | ||
| return (Database) db; | ||
| } catch (NoSuchMethodException nsme) { | ||
| var m2 = server.getClass().getMethod("openDatabase", String.class); | ||
| Object db = m2.invoke(server, name); | ||
| return (Database) db; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Approximate record count with a quick pass across types. | ||
| */ | ||
| private long approximateRecordCount(Database db) { | ||
| long total = 0L; | ||
| try { | ||
| for (DocumentType t : db.getSchema().getTypes()) { | ||
| try { | ||
| // exact=false when supported; otherwise this counts exactly | ||
| total += db.countType(t.getName(), false); | ||
| } catch (Throwable ignore) { | ||
| } | ||
| } | ||
| } catch (Throwable ignore) { | ||
| } | ||
| return total; | ||
| } | ||
|
|
||
| private boolean existsVertexType(Schema s, String name) { | ||
|
|
||
| try { | ||
| return s.existsType(name); | ||
| } catch (Throwable t) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| private boolean existsEdgeType(Schema s, String name) { | ||
|
|
||
| try { | ||
|
|
||
| return s.existsType(name); | ||
| } catch (Throwable t) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| // ---------- safe server info fallbacks (optional; return sentinel values if | ||
| // not exposed) ---------- | ||
|
|
||
| private String safeServerVersion() { | ||
| try { | ||
| var m = server.getClass().getMethod("getProductVersion"); | ||
| Object v = m.invoke(server); | ||
| return (v != null) ? v.toString() : "unknown"; | ||
| } catch (Throwable t) { | ||
| return "unknown"; | ||
| } | ||
| } | ||
|
|
||
| private long safeServerStartMs() { | ||
| try { | ||
| var m = server.getClass().getMethod("getStartTime"); | ||
| Object v = m.invoke(server); | ||
| if (v instanceof Number n) | ||
| return n.longValue(); | ||
| } catch (Throwable t) { | ||
| // ignore | ||
| } | ||
| return 0L; | ||
| } | ||
|
|
||
| private int safeHttpPort() { | ||
| try { | ||
| var m = server.getClass().getMethod("getHttpServer"); | ||
| Object http = m.invoke(server); | ||
| if (http != null) { | ||
| var pm = http.getClass().getMethod("getPort"); | ||
| Object p = pm.invoke(http); | ||
| if (p instanceof Number n) | ||
| return n.intValue(); | ||
| } | ||
| } catch (Throwable ignore) { | ||
| } | ||
| return -1; | ||
| } | ||
|
|
||
| private int safeGrpcPort() { | ||
| try { | ||
| var m = server.getClass().getMethod("getGrpcServer"); | ||
| Object g = m.invoke(server); | ||
| if (g != null) { | ||
| var pm = g.getClass().getMethod("getPort"); | ||
| Object p = pm.invoke(g); | ||
| if (p instanceof Number n) | ||
| return n.intValue(); | ||
| } | ||
| } catch (Throwable ignore) { | ||
| } | ||
| return -1; | ||
| } | ||
|
|
||
| private int safeBinaryPort() { | ||
| try { | ||
| var m = server.getClass().getMethod("getBinaryServer"); | ||
| Object b = m.invoke(server); | ||
| if (b != null) { | ||
| var pm = b.getClass().getMethod("getPort"); | ||
| Object p = pm.invoke(b); | ||
| if (p instanceof Number n) | ||
| return n.intValue(); | ||
| } | ||
| } catch (Throwable ignore) { | ||
| } | ||
| return -1; | ||
| } | ||
| } |
There was a problem hiding this comment.
This class uses reflection extensively to interact with ArcadeDBServer (e.g., in getDatabaseNames, createDatabasePhysical, safeServerVersion). This approach is brittle and can lead to runtime errors if the method names or signatures in ArcadeDBServer change. It would be much safer and more maintainable to define an interface with the required methods and have ArcadeDBServer implement it. The gRPC service could then call the methods through the interface, ensuring type safety and compile-time checks.
|
|
||
| PWD: /Users/ocohen/git/Verdance/ArcadeDB-GRPC/arcadedb-25.8.1-SNAPSHOT | ||
|
|
||
|
|
||
| ./bin/server.sh | ||
| -Darcadedb.server.rootPassword=root1234 | ||
| -Darcadedb.server.name=Arcade_GRPC_Test | ||
| -Darcadedb.dumpConfigAtStartup=true | ||
| -Darcadedb.server.mode=development | ||
| -Darcadedb.server.rootPath=../var/arcadedb | ||
| -Darcadedb.server.plugins=GRPC:com.arcadedb.server.grpc.GrpcServerPlugin | ||
| -Xms512M -Xmx4096M -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0 | ||
| -Darcadedb.server.httpIncomingPort=2489 | ||
| -Darcadedb.grpc.enabled=true | ||
| -Darcadedb.grpc.port=50059 | ||
| -Darcadedb.grpc.mode=standard | ||
| -Darcadedb.grpc.reflection.enabled=true | ||
| -Darcadedb.grpc.health.enabled=true | ||
|
|
||
|
|
||
| Ports: | ||
|
|
||
| HTTP: 2489 | ||
| GTPC: 50059 | ||
|
|
||
| root | ||
| root1234 | ||
|
|
||
| Logging: | ||
|
|
||
| d exec -it arcadedb1-vulcan sh | ||
|
|
||
|
|
||
| vi /home/arcadedb/config/arcadedb-log.properties | ||
|
|
||
|
|
||
| handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler | ||
|
|
||
| .level = INFO | ||
| com.arcadedb.level = INFO | ||
| com.arcadedb.server.grpc.level = FINE | ||
|
|
||
| java.util.logging.ConsoleHandler.level = INFO | ||
| java.util.logging.ConsoleHandler.formatter = com.arcadedb.utility.AnsiLogFormatter | ||
|
|
||
| java.util.logging.FileHandler.level = FINE | ||
| java.util.logging.FileHandler.pattern=./log/arcadedb.log | ||
| java.util.logging.FileHandler.formatter = com.arcadedb.log.LogFormatter | ||
| java.util.logging.FileHandler.limit=100000000 | ||
| java.util.logging.FileHandler.count=10 | ||
|
|
||
|
|
||
|
|
||
|
|
||
| tail -f /home/arcadedb/log/arcadedb.log.0 | ||
|
|
||
|
|
||
|
|
||
|
|
||
| d exec -it arcadedb1-vulcan sh |
There was a problem hiding this comment.
This file appears to contain temporary developer notes, including a user-specific local path (/Users/ocohen/...). Such files should generally not be committed to the repository. Please consider removing this file or cleaning it up and moving it to a more appropriate location if it contains valuable documentation.
| private String mapRecordType(GrpcRecord grpcRecord) { | ||
|
|
||
| // Determine record category from type name | ||
| String typeName = grpcRecord.getType(); | ||
|
|
||
| // Check schema to determine actual type | ||
| try { | ||
|
|
||
| if (typeName != null && !typeName.isBlank() && getSchema().existsType(typeName)) { | ||
|
|
||
| Object type = getSchema().getType(typeName); | ||
|
|
||
| if (type instanceof com.arcadedb.schema.VertexType) { | ||
|
|
||
| return "v"; | ||
| } else if (type instanceof com.arcadedb.schema.EdgeType) { | ||
|
|
||
| return "e"; | ||
| } else if (type instanceof com.arcadedb.schema.DocumentType) { | ||
|
|
||
| return "d"; | ||
| } else { | ||
|
|
||
| return null; | ||
| } | ||
| } else { | ||
|
|
||
| return null; | ||
| } | ||
| } catch (Exception e) { | ||
|
|
||
| throw new RuntimeException(e); | ||
| } | ||
| } |
There was a problem hiding this comment.
The mapRecordType method is called as a fallback when a GrpcRecord doesn't contain the @cat property. This method performs a schema lookup for every record, which can be a performance bottleneck when processing large result sets. To optimize this, the server should always include the @cat property in the GrpcRecord payload, making this client-side lookup unnecessary.
| } | ||
|
|
||
| // Optional knobs you can toggle from the TM for a single run | ||
| private volatile boolean txDebugEnabled = true; |
There was a problem hiding this comment.
The transaction debugging feature (txDebugEnabled) is enabled by default. This can add performance overhead and verbose logging in production environments. It's recommended to have debugging features disabled by default and enabled only when needed.
| private volatile boolean txDebugEnabled = true; | |
| private volatile boolean txDebugEnabled = false; |
| for (String propName : doc.getPropertyNames()) { | ||
| Object value = doc.get(propName); | ||
|
|
||
| System.out.print("toProtoRecord: " + propName + ": " + value); |
| syntax = "proto3"; | ||
|
|
||
| package com.arcadedb.grpc; | ||
|
|
||
| option java_multiple_files = true; | ||
| option java_package = "com.arcadedb.server.grpc"; | ||
| option java_outer_classname = "ArcadeDbProto"; | ||
|
|
||
| import "google/protobuf/empty.proto"; | ||
| import "google/protobuf/struct.proto"; | ||
|
|
||
| // Main ArcadeDB Service | ||
| service ArcadeDbService { | ||
| // Database operations | ||
| rpc CreateDatabase(CreateDatabaseRequest) returns (CreateDatabaseResponse); | ||
| rpc DropDatabase(DropDatabaseRequest) returns (DropDatabaseResponse); | ||
| rpc ListDatabases(ListDatabasesRequest) returns (ListDatabasesResponse); | ||
| rpc GetDatabaseInfo(GetDatabaseInfoRequest) returns (GetDatabaseInfoResponse); | ||
|
|
||
| // Query operations | ||
| rpc ExecuteQuery(ExecuteQueryRequest) returns (ExecuteQueryResponse); | ||
| rpc ExecuteCommand(ExecuteCommandRequest) returns (ExecuteCommandResponse); | ||
|
|
||
| // Transaction operations | ||
| rpc BeginTransaction(BeginTransactionRequest) returns (BeginTransactionResponse); | ||
| rpc CommitTransaction(CommitTransactionRequest) returns (CommitTransactionResponse); | ||
| rpc RollbackTransaction(RollbackTransactionRequest) returns (RollbackTransactionResponse); | ||
|
|
||
| // Record operations | ||
| rpc CreateRecord(CreateRecordRequest) returns (CreateRecordResponse); | ||
| rpc GetRecord(GetRecordRequest) returns (GetRecordResponse); | ||
| rpc UpdateRecord(UpdateRecordRequest) returns (UpdateRecordResponse); | ||
| rpc DeleteRecord(DeleteRecordRequest) returns (DeleteRecordResponse); | ||
|
|
||
| // Streaming operations | ||
| rpc StreamQuery(StreamQueryRequest) returns (stream QueryResult); | ||
| rpc BulkInsert(stream BulkInsertRequest) returns (BulkInsertResponse); | ||
|
|
||
| // Server operations | ||
| rpc GetServerStatus(google.protobuf.Empty) returns (ServerStatusResponse); | ||
| rpc Ping(google.protobuf.Empty) returns (PingResponse); | ||
| } | ||
|
|
||
| // Common messages | ||
| message DatabaseCredentials { | ||
| string username = 1; | ||
| string password = 2; | ||
| } | ||
|
|
||
| message TransactionContext { | ||
| string transaction_id = 1; | ||
| string database = 2; | ||
| } | ||
|
|
||
| // Database operations | ||
| message CreateDatabaseRequest { | ||
| string database_name = 1; | ||
| DatabaseCredentials credentials = 2; | ||
| map<string, string> options = 3; | ||
| } | ||
|
|
||
| message CreateDatabaseResponse { | ||
| bool success = 1; | ||
| string message = 2; | ||
| string database_id = 3; | ||
| } | ||
|
|
||
| message DropDatabaseRequest { | ||
| string database_name = 1; | ||
| DatabaseCredentials credentials = 2; | ||
| } | ||
|
|
||
| message DropDatabaseResponse { | ||
| bool success = 1; | ||
| string message = 2; | ||
| } | ||
|
|
||
| message ListDatabasesRequest { | ||
| DatabaseCredentials credentials = 1; | ||
| } | ||
|
|
||
| message ListDatabasesResponse { | ||
| repeated DatabaseInfo databases = 1; | ||
| } | ||
|
|
||
| message DatabaseInfo { | ||
| string name = 1; | ||
| int64 size = 2; | ||
| string status = 3; | ||
| map<string, string> properties = 4; | ||
| } | ||
|
|
||
| message GetDatabaseInfoRequest { | ||
| string database_name = 1; | ||
| DatabaseCredentials credentials = 2; | ||
| } | ||
|
|
||
| message GetDatabaseInfoResponse { | ||
| DatabaseInfo info = 1; | ||
| } | ||
|
|
||
| // Query operations | ||
| message ExecuteQueryRequest { | ||
| string database = 1; | ||
| string query = 2; | ||
| map<string, google.protobuf.Value> parameters = 3; | ||
| DatabaseCredentials credentials = 4; | ||
| TransactionContext transaction = 5; | ||
| int32 limit = 6; | ||
| int32 timeout_ms = 7; | ||
| } | ||
|
|
||
| message ExecuteQueryResponse { | ||
| repeated QueryResult results = 1; | ||
| int64 execution_time_ms = 2; | ||
| string query_plan = 3; | ||
| } | ||
|
|
||
| message ExecuteCommandRequest { | ||
| string database = 1; | ||
| string command = 2; | ||
| map<string, google.protobuf.Value> parameters = 3; | ||
| DatabaseCredentials credentials = 4; | ||
| TransactionContext transaction = 5; | ||
| } | ||
|
|
||
| message ExecuteCommandResponse { | ||
| bool success = 1; | ||
| string message = 2; | ||
| int64 affected_records = 3; | ||
| int64 execution_time_ms = 4; | ||
| } | ||
|
|
||
| message QueryResult { | ||
| repeated Record records = 1; | ||
| repeated ColumnMetadata columns = 2; | ||
| int64 total_records = 3; | ||
| } | ||
|
|
||
| message ColumnMetadata { | ||
| string name = 1; | ||
| string type = 2; | ||
| bool nullable = 3; | ||
| } | ||
|
|
||
| // Transaction operations | ||
| message BeginTransactionRequest { | ||
| string database = 1; | ||
| DatabaseCredentials credentials = 2; | ||
| TransactionIsolation isolation = 3; | ||
| } | ||
|
|
||
| enum TransactionIsolation { | ||
| READ_UNCOMMITTED = 0; | ||
| READ_COMMITTED = 1; | ||
| REPEATABLE_READ = 2; | ||
| SERIALIZABLE = 3; | ||
| } | ||
|
|
||
| message BeginTransactionResponse { | ||
| string transaction_id = 1; | ||
| int64 timestamp = 2; | ||
| } | ||
|
|
||
| message CommitTransactionRequest { | ||
| TransactionContext transaction = 1; | ||
| DatabaseCredentials credentials = 2; | ||
| } | ||
|
|
||
| message CommitTransactionResponse { | ||
| bool success = 1; | ||
| string message = 2; | ||
| int64 timestamp = 3; | ||
| } | ||
|
|
||
| message RollbackTransactionRequest { | ||
| TransactionContext transaction = 1; | ||
| DatabaseCredentials credentials = 2; | ||
| } | ||
|
|
||
| message RollbackTransactionResponse { | ||
| bool success = 1; | ||
| string message = 2; | ||
| } | ||
|
|
||
| // Record operations | ||
| message Record { | ||
| string rid = 1; | ||
| string type = 2; | ||
| map<string, google.protobuf.Value> properties = 3; | ||
| int32 version = 4; | ||
| } | ||
|
|
||
| message CreateRecordRequest { | ||
| string database = 1; | ||
| string type = 2; | ||
| map<string, google.protobuf.Value> properties = 3; | ||
| DatabaseCredentials credentials = 4; | ||
| TransactionContext transaction = 5; | ||
| } | ||
|
|
||
| message CreateRecordResponse { | ||
| Record record = 1; | ||
| bool success = 2; | ||
| string message = 3; | ||
| } | ||
|
|
||
| message GetRecordRequest { | ||
| string database = 1; | ||
| string rid = 2; | ||
| DatabaseCredentials credentials = 3; | ||
| TransactionContext transaction = 4; | ||
| } | ||
|
|
||
| message GetRecordResponse { | ||
| Record record = 1; | ||
| bool found = 2; | ||
| } | ||
|
|
||
| message UpdateRecordRequest { | ||
| string database = 1; | ||
| string rid = 2; | ||
| map<string, google.protobuf.Value> properties = 3; | ||
| DatabaseCredentials credentials = 4; | ||
| TransactionContext transaction = 5; | ||
| int32 expected_version = 6; | ||
| } | ||
|
|
||
| message UpdateRecordResponse { | ||
| Record record = 1; | ||
| bool success = 2; | ||
| string message = 3; | ||
| } | ||
|
|
||
| message DeleteRecordRequest { | ||
| string database = 1; | ||
| string rid = 2; | ||
| DatabaseCredentials credentials = 3; | ||
| TransactionContext transaction = 4; | ||
| } | ||
|
|
||
| message DeleteRecordResponse { | ||
| bool success = 1; | ||
| string message = 2; | ||
| } | ||
|
|
||
| // Streaming operations | ||
| message StreamQueryRequest { | ||
| string database = 1; | ||
| string query = 2; | ||
| map<string, google.protobuf.Value> parameters = 3; | ||
| DatabaseCredentials credentials = 4; | ||
| int32 batch_size = 5; | ||
| } | ||
|
|
||
| message BulkInsertRequest { | ||
| string database = 1; | ||
| string type = 2; | ||
| Record record = 3; | ||
| DatabaseCredentials credentials = 4; | ||
| } | ||
|
|
||
| message BulkInsertResponse { | ||
| int64 total_inserted = 1; | ||
| int64 total_failed = 2; | ||
| repeated string errors = 3; | ||
| } | ||
|
|
||
| // Server operations | ||
| message ServerStatusResponse { | ||
| string version = 1; | ||
| string status = 2; | ||
| int64 uptime_ms = 3; | ||
| int32 active_connections = 4; | ||
| map<string, string> metrics = 5; | ||
| } | ||
|
|
||
| message PingResponse { | ||
| int64 timestamp = 1; | ||
| string message = 2; | ||
| } |
There was a problem hiding this comment.
This file appears to be a duplicate or an older version of the protobuf definition located in grpc/src/main/proto/arcadedb-server.proto. Maintaining multiple versions of the API contract can lead to confusion and build issues. This file should likely be removed to ensure there is a single source of truth for the gRPC API.
) Co-authored-by: Oleg Cohen <oleg.cohen@shakeiq.ai> (cherry picked from commit aae1b32)
This is just a copy of #2462
What does this PR do?
This PR introduces full gRPC support for ArcadeDB, providing a strongly-typed, high-performance API for remote access to the database.
Key highlights include:
Streaming query execution with multiple retrieval modes:
LIMIT/SKIPfor efficient paging.Insert operations:
Record operations:
Transaction support:
TransactionContextflags forbegin,commit, androllbackto coordinate transactional operations across requests.Client-side API:
RemoteGrpcDatabasewith a simple, extensible API.Motivation
Related issues
N/A
Additional Notes
I don't yet have a set of client-side tests. These will be provided shortly.
Checklist
mvn -DskipTests installmvn clean package -Pdockerin thepackagemodule