-
Notifications
You must be signed in to change notification settings - Fork 15
Migrate simple-store to kotlin and coroutines #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| #Tue Dec 01 12:24:16 PST 2020 | ||
| distributionBase=GRADLE_USER_HOME | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip | ||
| distributionPath=wrapper/dists | ||
| zipStorePath=wrapper/dists | ||
| zipStoreBase=GRADLE_USER_HOME |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /* | ||
| * Copyright (C) 2020. Uber Technologies | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.uber.simplestore | ||
|
|
||
| import java.io.File | ||
|
|
||
| interface DirectoryProvider { | ||
| fun cacheDirectoryPath(): File | ||
| fun filesDirectoryPath(): File | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /* | ||
| * Copyright (C) 2019. Uber Technologies | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.uber.simplestore | ||
|
|
||
| /** Configure how the store accesses a namespace. */ | ||
| sealed class NamespaceConfig { | ||
| /** | ||
| * Opens a namespace as performance & integrity critical. | ||
| * | ||
| * Bypasses future memory use optimizations. | ||
| */ | ||
| object CRITICAL : NamespaceConfig() | ||
|
|
||
| /** | ||
| * Use the cache directory. | ||
| * | ||
| * Hides errors due to data corruption by returning a miss. | ||
| */ | ||
| object CACHE : NamespaceConfig() | ||
|
|
||
| /** Default settings. */ | ||
| object DEFAULT : NamespaceConfig() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| /* | ||
| * Copyright (C) 2019. Uber Technologies | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.uber.simplestore | ||
|
|
||
| import com.google.common.annotations.Beta | ||
| import com.google.common.util.concurrent.ListenableFuture | ||
| import java.io.Closeable | ||
|
|
||
| /** Fast, reliable storage. */ | ||
| interface SimpleStore : Closeable { | ||
|
|
||
| /** | ||
| * Retrieve a byte[]-backed String. | ||
| * | ||
| * @param key to fetch from | ||
| */ | ||
| suspend fun getString(key: String): String | ||
|
|
||
| /** | ||
| * Stores a String as a byte[]. | ||
| * | ||
| * @param key to store to | ||
| * @param value to write | ||
| */ | ||
| suspend fun putString(key: String, value: String?): String | ||
|
|
||
| /** | ||
| * Retrieve a byte[] from disk. | ||
| * | ||
| * @param key to read from | ||
| * @return value if present, empty array if absent | ||
| */ | ||
| suspend fun get(key: String): ByteArray | ||
|
|
||
| /** | ||
| * Stores a byte[] on disk. | ||
| * | ||
| * @param key to store to | ||
| * @param value to store | ||
| */ | ||
| suspend fun put(key: String, value: ByteArray?): ByteArray | ||
|
|
||
| /** | ||
| * Removes a key from memory & disk. | ||
| * | ||
| * @param key to remove | ||
| * @return when complete | ||
| */ | ||
| suspend fun remove(key: String) | ||
|
|
||
| /** | ||
| * Determine if a key exists in storage. | ||
| * | ||
| * @param key to check | ||
| * @return if key is set | ||
| */ | ||
| suspend fun contains(key: String): Boolean | ||
|
|
||
| /** Delete all keys in this direct namespace. */ | ||
| suspend fun clear() | ||
|
|
||
| /** | ||
| * Recursively delete all keys in this scope and child scopes. Fails all outstanding operations on | ||
| * the stores. | ||
| */ | ||
| @Beta | ||
| suspend fun deleteAllNow() | ||
|
|
||
| /** Fails all outstanding operations then releases the memory cache. */ | ||
| override fun close() | ||
| } | ||
|
|
||
| /** | ||
| * Extension functions to provide ListenableFuture compatibility for Java callers | ||
| */ | ||
| fun SimpleStore.getStringFuture(key: String): ListenableFuture<String> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { getString(key) } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree Java consumers shouldn't need to know anything about coroutines, but concerned about |
||
| ) | ||
| } | ||
|
|
||
| fun SimpleStore.putStringFuture(key: String, value: String?): ListenableFuture<String> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { putString(key, value) } | ||
| ) | ||
| } | ||
|
|
||
| fun SimpleStore.getFuture(key: String): ListenableFuture<ByteArray> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { get(key) } | ||
| ) | ||
| } | ||
|
|
||
| fun SimpleStore.putFuture(key: String, value: ByteArray?): ListenableFuture<ByteArray> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { put(key, value) } | ||
| ) | ||
| } | ||
|
|
||
| fun SimpleStore.removeFuture(key: String): ListenableFuture<Void> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { | ||
| remove(key) | ||
| null | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| fun SimpleStore.containsFuture(key: String): ListenableFuture<Boolean> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { contains(key) } | ||
| ) | ||
| } | ||
|
|
||
| fun SimpleStore.clearFuture(): ListenableFuture<Void> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { | ||
| clear() | ||
| null | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| fun SimpleStore.deleteAllNowFuture(): ListenableFuture<Void> { | ||
| return kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { | ||
| deleteAllNow() | ||
| null | ||
| } | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| /* | ||
| * Copyright (C) 2019. Uber Technologies | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.uber.simplestore | ||
|
|
||
| import com.uber.simplestore.executors.StorageExecutors | ||
| import java.util.concurrent.Executor | ||
|
|
||
| /** | ||
| * Configure executors used by SimpleStore. | ||
| * | ||
| * Set may only be called once, and should be called before any use of stores. | ||
| */ | ||
| object SimpleStoreConfig { | ||
|
|
||
| private val writeLock = Any() | ||
|
|
||
| @Volatile | ||
| private var ioExecutor: Executor? = null | ||
|
|
||
| @Volatile | ||
| private var computationExecutor: Executor? = null | ||
|
|
||
| fun getIOExecutor(): Executor { | ||
| if (ioExecutor == null) { | ||
| synchronized(writeLock) { | ||
| if (ioExecutor == null) { | ||
| ioExecutor = StorageExecutors.ioExecutor() | ||
| } | ||
| } | ||
| } | ||
| return ioExecutor!! | ||
| } | ||
|
|
||
| /** | ||
| * Override the executor used for IO operations. | ||
| * | ||
| * @param executor to set, null unsets. | ||
| */ | ||
| fun setIOExecutor(executor: Executor?) { | ||
| synchronized(writeLock) { | ||
| ioExecutor = executor | ||
| } | ||
| } | ||
|
|
||
| fun getComputationExecutor(): Executor { | ||
| if (computationExecutor == null) { | ||
| synchronized(writeLock) { | ||
| if (computationExecutor == null) { | ||
| computationExecutor = StorageExecutors.computationExecutor() | ||
| } | ||
| } | ||
| } | ||
| return computationExecutor!! | ||
| } | ||
|
|
||
| /** | ||
| * Override the executor used for computation. | ||
| * | ||
| * @param executor to set, null unsets. | ||
| */ | ||
| fun setComputationExecutor(executor: Executor?) { | ||
| synchronized(writeLock) { | ||
| computationExecutor = executor | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| /* | ||
| * Copyright (C) 2019. Uber Technologies | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.uber.simplestore | ||
|
|
||
| import kotlinx.coroutines.async | ||
| import kotlinx.coroutines.coroutineScope | ||
|
|
||
| /** Useful wrappers for common storage operations. */ | ||
| object SimpleStoreHelpers { | ||
|
|
||
| /** | ||
| * Prefetch specified keys into the memory cache. | ||
| * | ||
| * @param store to warm | ||
| * @param keys to fetch | ||
| */ | ||
| suspend fun prefetch(store: SimpleStore, vararg keys: String) { | ||
| coroutineScope { | ||
| keys.map { key -> | ||
| async { store.get(key) } | ||
| }.awaitAll() | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Java-compatible version that returns ListenableFuture | ||
| */ | ||
| fun prefetchFuture(store: SimpleStore, vararg keys: String) = | ||
| kotlinx.coroutines.guava.asListenableFuture( | ||
| kotlinx.coroutines.GlobalScope.async { prefetch(store, *keys) } | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔥