Skip to content

Commit 1a96eb4

Browse files
committed
Add basic Get and Put Api signatures along with protobuf setup
1 parent 4b6af13 commit 1a96eb4

File tree

5 files changed

+241
-2
lines changed

5 files changed

+241
-2
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.protoc-version
2+
.idea/*
3+
*.ipr
4+
*.iws
5+
.settings/*
6+
.project
7+
.gradle/*
8+
gradle/*
9+
gradlew*
10+
build/*
11+
app/build/*
12+
app/bin/*
13+
app/.classpath
14+
app/.project
15+
app/.settings
16+

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
# ess-server
2-
Encrypted Storage Service
1+
# vss-server
2+
Versioned Storage Service

app/build.gradle

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
buildscript {
2+
ext.gradleVersion = '7.5.1'
3+
ext.protobufPlugInVersion = '0.8.12'
4+
ext.protobufVersion = '3.21.7'
5+
ext.jerseyVersion = '3.1.0'
6+
ext.junitVersion = '5.9.0'
7+
}
8+
9+
plugins {
10+
id 'java'
11+
id 'com.google.protobuf' version "${protobufPlugInVersion}"
12+
id 'war'
13+
id 'idea'
14+
}
15+
16+
repositories {
17+
mavenCentral()
18+
}
19+
20+
idea {
21+
module {
22+
generatedSourceDirs.add(file("build/generated/proto/main"))
23+
}
24+
}
25+
26+
group 'org.vss'
27+
version '1.0'
28+
29+
30+
dependencies {
31+
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
32+
33+
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
34+
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
35+
}
36+
37+
test {
38+
useJUnitPlatform()
39+
}

app/src/main/proto/vss.proto

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
syntax = "proto3";
2+
option java_multiple_files = true;
3+
package org.vss;
4+
5+
message GetObjectRequest {
6+
7+
/*
8+
StoreId: All APIs operate within a single storeId.
9+
StoreId is a keyspace identifier.
10+
Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
11+
It is up to clients to use single or multiple stores for their use-case.
12+
This can be used for client-isolation/ rate-limiting / throttling on the server-side.
13+
Authorization and billing can also be performed at the storeId level.
14+
*/
15+
string storeId = 1;
16+
17+
/*
18+
Key for which the value is to be fetched.
19+
20+
Consistency Guarantee:
21+
Get/Read operations against a key are consistent reads and will reflect all previous writes,
22+
since Put/Write provides read-after-write and read-after-update consistency guarantees.
23+
24+
Read Isolation:
25+
Get/Read operations against a key are ensured to have read-committed isolation.
26+
Ref: https://en.wikipedia.org/wiki/Isolation_(database_systems)#Read_committed
27+
*/
28+
string key = 2;
29+
}
30+
31+
32+
message GetObjectResponse {
33+
/*
34+
Fetched value and version along with the corresponding key in the request.
35+
*/
36+
KeyValue value = 2;
37+
}
38+
39+
40+
message PutObjectRequest {
41+
42+
/*
43+
StoreId: All APIs operate within a single storeId.
44+
StoreId is a keyspace identifier.
45+
Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
46+
It is up to clients to use single or multiple stores for their use-case.
47+
This can be used for client-isolation/ rate-limiting / throttling on the server-side.
48+
Authorization and billing can also be performed at the storeId level.
49+
*/
50+
string storeId = 1;
51+
/*
52+
If present, the write will only succeed if the current server-side globalVersion against
53+
a storeId is same as in the request.
54+
Clients are expected to store (client-side) the global version against storeId.
55+
And the request should contain their client-side value of globalVersion.
56+
57+
For the first write of the store, global version should be '0'. If the write succeeds, clients
58+
must increment their global version (client-side) by 1.
59+
The server increments globalVersion (server-side) for every successful write, hence this
60+
client-side increment is required to ensure matching versions. This updated global version
61+
should be used in subsequent PutObjectRequests for the store.
62+
63+
Requests with conflicting version will fail with `ConflictException` as ErrorCode.
64+
*/
65+
optional int64 globalVersion = 2;
66+
67+
/*
68+
Items to be written as a result of this PutObjectRequest.
69+
70+
In an item, each key is supplied with its corresponding value and version.
71+
Clients can choose to encrypt the keys client-side in order to obfuscate user's usage patterns.
72+
If write is successful, previous value corresponding to the key will be overwritten.
73+
74+
Multiple items in transactionItems of a single PutObjectRequest are written in
75+
a database-transaction in all-or-nothing fashion.
76+
Items in single PutObjectRequest must have distinct keys.
77+
78+
Write will only succeed if current DB version against key is same as in request.
79+
Client is expected to store version against every key.
80+
When initiating a PutObjectRequest, the request should contain their client-side version for
81+
that key-value.
82+
83+
For first write of key, version should be '0'. If the write succeeds, clients must increment
84+
their corresponding key versions (client-side) by 1.
85+
The server increments key version (server-side) for every successful write, hence this
86+
client-side increment is required to ensure matching versions. These updated key versions should
87+
be used in subsequent PutObjectRequests for the keys.
88+
89+
Requests with conflicting version will fail with `ConflictException` as ErrorCode.
90+
91+
Considerations for transactions:
92+
Transaction writes of multiple items have a performance overhead, hence it is recommended to use
93+
them only if required by the client application to ensure logic/code correctness.
94+
That is, transactionItems are not a substitute for batch-write of multiple unrelated items.
95+
When write of multiple unrelated items is desired, it is recommended to use separate
96+
PutObjectRequests.
97+
98+
Consistency Guarantee:
99+
All PutObjectRequests are strongly consistent i.e. they provide read-after-write and
100+
read-after-update consistency guarantees.
101+
*/
102+
repeated KeyValue transactionItems = 3;
103+
}
104+
105+
message PutObjectResponse {
106+
}
107+
108+
109+
/*
110+
When HttpStatusCode is not ok (200), the response `content` contains serialized ErrorResponse with
111+
the relevant ErrorCode and ErrorCode's integer value as HttpStatusCode.
112+
*/
113+
message ErrorResponse {
114+
/*
115+
The error code enum-value uniquely identifies an error condition.
116+
It is meant to be read and understood programmatically by code that detects/handles errors by
117+
type.
118+
*/
119+
ErrorCode errorCode = 1;
120+
/*
121+
The error message contains a generic description of the error condition in English.
122+
It is intended for a human audience only. And should not be parsed to extract any information
123+
programmatically. Client-side code may use it for logging only.
124+
*/
125+
string message = 2;
126+
}
127+
128+
129+
/*
130+
ErrorCodes to be used in ErrorResponse along with corresponding integer values that will be used
131+
as HttpStatusCode in HttpResponse.
132+
*/
133+
enum ErrorCode {
134+
/*
135+
Default protobuf Enum value. Will not be used as ErrorCode by server.
136+
*/
137+
Unknown = 0;
138+
/*
139+
ConflictException is used when the request contains mismatched version (either key or global)
140+
in PutObjectRequest. For more info refer PutObjectRequest.
141+
*/
142+
ConflictException = 409;
143+
/*
144+
InvalidRequestException is used in the following cases:
145+
- The request was missing a required argument.
146+
- The specified argument was invalid, incomplete or in the wrong format.
147+
- The request body of api cannot be deserialized into corresponding protobuf object.
148+
*/
149+
InvalidRequestException = 400;
150+
/*
151+
An internal server error occurred, client is probably at no fault and can safely retry this
152+
error with exponential backoff.
153+
*/
154+
InternalServerException = 500;
155+
}
156+
157+
158+
message KeyValue {
159+
/*
160+
Key against which the value is stored.
161+
*/
162+
string key = 1;
163+
164+
/*
165+
For first write of key, version should be '0'. If the write succeeds, clients must increment
166+
their corresponding key version (client-side) by 1.
167+
The server increments key version (server-side) for every successful write, hence this
168+
client-side increment is required to ensure matching versions. These updated key versions should
169+
be used in subsequent PutObjectRequests for the keys.
170+
*/
171+
int64 version = 2;
172+
173+
/*
174+
Object value in bytes which is stored (in put) and fetched (in get).
175+
Clients must encrypt this blob client-side before sending it over the wire to server in order
176+
to preserve privacy and security.
177+
*/
178+
bytes value = 3;
179+
}
180+
181+
182+

settings.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
rootProject.name = 'vss-server'
2+
include 'app'

0 commit comments

Comments
 (0)