Skip to content

Commit ad47baf

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

File tree

5 files changed

+213
-2
lines changed

5 files changed

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

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)