Skip to content

Commit

Permalink
Store blobs on file system as if blob key were a Unix filesystem path. (
Browse files Browse the repository at this point in the history
#105)

This is a backwards-incompatible change. Blobs written using the previous implementation of FileSystemStorageClient will not be able to be read.
  • Loading branch information
SanjayVas committed Apr 28, 2022
1 parent 2ecae06 commit 48bef89
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ import org.wfanet.measurement.storage.StorageClient

private const val READ_BUFFER_SIZE = 1024 * 4 // 4 KiB

/** [StorageClient] implementation that utilizes flat files in the specified directory as blobs. */
/** [StorageClient] implementation that stores blobs as files under [directory]. */
class FileSystemStorageClient(private val directory: File) : StorageClient {
init {
require(directory.isDirectory) { "$directory is not a directory" }
}

override suspend fun writeBlob(blobKey: String, content: Flow<ByteString>): StorageClient.Blob {
val file = File(directory, blobKey.base64UrlEncode())
val file: File = resolvePath(blobKey)
withContext(Dispatchers.IO) {
file.parentFile.mkdirs()
file.outputStream().channel.use { byteChannel ->
content.collect { bytes ->
for (buffer in bytes.asReadOnlyByteBufferList()) {
Expand All @@ -49,8 +50,18 @@ class FileSystemStorageClient(private val directory: File) : StorageClient {
}

override suspend fun getBlob(blobKey: String): StorageClient.Blob? {
val file = File(directory, blobKey.base64UrlEncode())
return if (file.exists()) Blob(file) else null
val file: File = resolvePath(blobKey)
return withContext(Dispatchers.IO) { if (file.exists()) Blob(file) else null }
}

private fun resolvePath(blobKey: String): File {
val relativePath =
if (File.separatorChar == '/') {
blobKey
} else {
blobKey.replace('/', File.separatorChar)
}
return directory.resolve(relativePath)
}

private inner class Blob(private val file: File) : StorageClient.Blob {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@

package org.wfanet.measurement.storage.filesystem

import com.google.common.truth.Truth.assertThat
import com.google.protobuf.kotlin.toByteStringUtf8
import java.nio.file.Paths
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.wfanet.measurement.common.readByteString
import org.wfanet.measurement.storage.testing.AbstractStorageClientTest

@RunWith(JUnit4::class)
Expand All @@ -29,4 +35,17 @@ class FileSystemStorageClientTest : AbstractStorageClientTest<FileSystemStorageC
fun initClient() {
storageClient = FileSystemStorageClient(tempDirectory.root)
}

@Test
fun `writeBlob writes blob to file in subdirectory`() {
val content = "Lorem ipsum dolor sit amet".toByteStringUtf8()
val blobKey = "a/b/c/file.txt"

runBlocking { storageClient.writeBlob(blobKey, content) }

val relativePath = Paths.get("a", "b", "c", "file.txt")
val file = tempDirectory.root.toPath().resolve(relativePath).toFile()
assertThat(file.exists()).isTrue()
assertThat(file.readByteString()).isEqualTo(content)
}
}

0 comments on commit 48bef89

Please sign in to comment.