Skip to content

Commit 8c50a96

Browse files
authored
Merge pull request #20 from scalableminds/rocksdb-configfile
optionally read rocksdb configfile
2 parents 7a6a995 + dc19df0 commit 8c50a96

File tree

7 files changed

+125
-18
lines changed

7 files changed

+125
-18
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ libraryDependencies ++= Seq(
2626
"io.grpc" % "grpc-netty" % scalapb.compiler.Version.grpcJavaVersion,
2727
"io.grpc" % "grpc-services" % scalapb.compiler.Version.grpcJavaVersion,
2828
"com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion,
29-
"org.rocksdb" % "rocksdbjni" % "5.1.2",
29+
"org.rocksdb" % "rocksdbjni" % "5.11.3",
3030
"com.github.scopt" %% "scopt" % "3.7.0"
3131
)
3232

src/main/scala/com/scalableminds/fossildb/FossilDB.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import fossildb.BuildInfo
88

99
import scala.concurrent.ExecutionContext
1010

11-
object ConfigDefaults {val port = 7155; val dataDir = "data"; val backupDir = "backup"; val columnFamilies = List()}
11+
object ConfigDefaults {val port = 7155; val dataDir = "data"; val backupDir = "backup"; val columnFamilies = List(); val rocksOptionsFile = None}
1212
case class Config(port: Int = ConfigDefaults.port, dataDir: String = ConfigDefaults.dataDir,
13-
backupDir: String = ConfigDefaults.backupDir, columnFamilies: List[String] = ConfigDefaults.columnFamilies)
13+
backupDir: String = ConfigDefaults.backupDir, columnFamilies: List[String] = ConfigDefaults.columnFamilies,
14+
rocksOptionsFile: Option[String] = ConfigDefaults.rocksOptionsFile)
1415

1516
object FossilDB extends LazyLogging {
1617
def main(args: Array[String]) = {
@@ -24,7 +25,7 @@ object FossilDB extends LazyLogging {
2425
logger.info("BuildInfo: (" + BuildInfo + ")")
2526
logger.info("Config: " + config)
2627

27-
val storeManager = new StoreManager(Paths.get(config.dataDir), Paths.get(config.backupDir), config.columnFamilies)
28+
val storeManager = new StoreManager(Paths.get(config.dataDir), Paths.get(config.backupDir), config.columnFamilies, config.rocksOptionsFile)
2829

2930
val server = new FossilDBServer(storeManager, config.port, ExecutionContext.global)
3031

@@ -51,6 +52,9 @@ object FossilDB extends LazyLogging {
5152

5253
opt[Seq[String]]('c', "columnFamilies").required.valueName("<cf1>,<cf2>...").action( (x, c) =>
5354
c.copy(columnFamilies = x.toList) ).text("column families of the database (created if there is no db yet)")
55+
56+
opt[String]('r', "rocksOptionsFile").valueName("<filepath>").action( (x, c) =>
57+
c.copy(rocksOptionsFile = Some(x)) ).text("rocksdb options file. Default: " + ConfigDefaults.rocksOptionsFile)
5458
}
5559

5660
parser.parse(args, Config())

src/main/scala/com/scalableminds/fossildb/db/RocksDBStore.scala

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ import com.typesafe.scalalogging.LazyLogging
1010
import org.rocksdb._
1111

1212
import scala.collection.JavaConverters._
13+
import scala.collection.mutable
1314
import scala.concurrent.Future
1415

1516
case class BackupInfo(id: Int, timestamp: Long, size: Long)
1617

1718
case class KeyValuePair[T](key: String, value: T)
1819

19-
class RocksDBManager(dataDir: Path, columnFamilies: List[String]) extends LazyLogging {
20+
class RocksDBManager(dataDir: Path, columnFamilies: List[String], optionsFilePathOpt: Option[String]) extends LazyLogging {
2021

2122
val (db: RocksDB, columnFamilyHandles) = {
2223
RocksDB.loadLibrary()
@@ -28,7 +29,19 @@ class RocksDBManager(dataDir: Path, columnFamilies: List[String]) extends LazyLo
2829
new ColumnFamilyDescriptor(columnFamily, columnOptions)
2930
}
3031
val columnFamilyHandles = new util.ArrayList[ColumnFamilyHandle]
31-
val options = new DBOptions()
32+
var options = new DBOptions()
33+
var cfListRef: mutable.Buffer[ColumnFamilyDescriptor] = mutable.Buffer()
34+
optionsFilePathOpt.map { optionsFilePath =>
35+
try {
36+
org.rocksdb.OptionsUtil.loadOptionsFromFile(optionsFilePath, Env.getDefault, options, cfListRef.asJava)
37+
logger.info("successfully loaded rocksdb options from " + optionsFilePath)
38+
} catch {
39+
case e: Exception => {
40+
throw new Exception("Failed to load rocksdb options from file " + optionsFilePath, e)
41+
}
42+
}
43+
}
44+
options = options
3245
.setCreateIfMissing(true)
3346
.setCreateMissingColumnFamilies(true)
3447
logger.info("Opening RocksDB at " + dataDir.toAbsolutePath)

src/main/scala/com/scalableminds/fossildb/db/StoreManager.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ package com.scalableminds.fossildb.db
66
import java.nio.file.Path
77
import java.util.concurrent.atomic.AtomicBoolean
88

9-
class StoreManager(dataDir: Path, backupDir: Path, columnFamilies: List[String]) {
9+
class StoreManager(dataDir: Path, backupDir: Path, columnFamilies: List[String], rocksdbOptions: Option[String]) {
1010

1111
var rocksDBManager: Option[RocksDBManager] = None
1212
var stores: Option[Map[String, VersionedKeyValueStore]] = None
@@ -15,7 +15,7 @@ class StoreManager(dataDir: Path, backupDir: Path, columnFamilies: List[String])
1515

1616
def reInitialize = {
1717
rocksDBManager.map(_.close)
18-
rocksDBManager = Some(new RocksDBManager(dataDir, columnFamilies))
18+
rocksDBManager = Some(new RocksDBManager(dataDir, columnFamilies, rocksdbOptions))
1919
stores = Some(columnFamilies.map { cf =>
2020
val store: VersionedKeyValueStore = new VersionedKeyValueStore(rocksDBManager.get.getStoreForColumnFamily(cf).get)
2121
(cf -> store)

src/test/scala/com/scalableminds/fossildb/FossilDBSuite.scala

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import org.scalatest.{BeforeAndAfterEach, FlatSpec}
1515

1616
import scala.concurrent.ExecutionContext
1717

18-
class FossilDBSuite extends FlatSpec with BeforeAndAfterEach {
19-
val testTempDir = "testData"
18+
class FossilDBSuite extends FlatSpec with BeforeAndAfterEach with TestHelpers {
19+
val testTempDir = "testData1"
2020
val dataDir = Paths.get(testTempDir, "data")
2121
val backupDir = Paths.get(testTempDir, "backup")
2222

@@ -38,20 +38,13 @@ class FossilDBSuite extends FlatSpec with BeforeAndAfterEach {
3838
val anotherKey = "anotherKey"
3939
val aThirdKey = "aThirdKey"
4040

41-
private def deleteRecursively(file: File): Unit = {
42-
if (file.isDirectory)
43-
file.listFiles.foreach(deleteRecursively)
44-
if (file.exists && !file.delete)
45-
throw new Exception(s"Unable to delete ${file.getAbsolutePath}")
46-
}
47-
4841
override def beforeEach = {
4942
deleteRecursively(new File(testTempDir))
5043
new File(testTempDir).mkdir()
5144

5245
val columnFamilies = List(collectionA, collectionB)
5346

54-
val storeManager = new StoreManager(dataDir, backupDir, columnFamilies)
47+
val storeManager = new StoreManager(dataDir, backupDir, columnFamilies, None)
5548

5649
serverOpt.map(_.stop())
5750
serverOpt = Some(new FossilDBServer(storeManager, port, ExecutionContext.global))
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (C) 2011-2018 scalable minds UG (haftungsbeschränkt) & Co. KG. <http://scm.io>
3+
*/
4+
package com.scalableminds.fossildb
5+
6+
import java.io.File
7+
import java.nio.file.Paths
8+
9+
import com.scalableminds.fossildb.db.StoreManager
10+
import org.rocksdb.{ColumnFamilyDescriptor, DBOptions, Env}
11+
import org.scalatest.{BeforeAndAfterEach, FlatSpec}
12+
13+
import scala.collection.mutable
14+
import scala.collection.JavaConverters._
15+
import scala.io.Source
16+
17+
class RocksOptionsSuite extends FlatSpec with BeforeAndAfterEach with TestHelpers {
18+
19+
val testTempDir = "testData2"
20+
val dataDir = Paths.get(testTempDir, "data")
21+
val backupDir = Paths.get(testTempDir, "backup")
22+
23+
val collectionA = "collectionA"
24+
val collectionB = "collectionB"
25+
26+
val columnFamilies = List(collectionA, collectionB)
27+
28+
29+
30+
override def beforeEach = {
31+
deleteRecursively(new File(testTempDir))
32+
new File(testTempDir).mkdir()
33+
}
34+
35+
override def afterEach = {
36+
deleteRecursively(new File(testTempDir))
37+
}
38+
39+
40+
41+
"Initializing the StoreManager" should "load and use a specified config file" in {
42+
val file = new File(testTempDir, "testConfig.ini")
43+
writeToFile(file, "[Version]\n rocksdb_version=5.11.3\n options_file_version=1.1\n\n[DBOptions]\n stats_dump_period_sec=700\n\n[CFOptions \"default\"]\n\n")
44+
45+
val storeManager = new StoreManager(dataDir, backupDir, columnFamilies, Some(file.getPath))
46+
47+
var options = new DBOptions()
48+
.setStatsDumpPeriodSec(100)
49+
var cfListRef: mutable.Buffer[ColumnFamilyDescriptor] = mutable.Buffer()
50+
// if successful, the rocksdb writes the loaded options to a file that can then be retreived with loadLatestOptions
51+
// we test that that one now includes the value 700 from the file above, rather than the 100 specified as a default
52+
org.rocksdb.OptionsUtil.loadLatestOptions(dataDir.toString, Env.getDefault, options, cfListRef.asJava)
53+
assert(options.statsDumpPeriodSec() == 700)
54+
storeManager.close
55+
}
56+
57+
it should "fail if specified config file does not exist" in {
58+
assertThrows[Exception] {
59+
new StoreManager(dataDir, backupDir, columnFamilies, Some("nonExistingPath.ini"))
60+
}
61+
}
62+
63+
it should "fail if specified config file is invalid" in {
64+
val file = new File(testTempDir, "testConfig.ini")
65+
writeToFile(file, "[Version]\n rocksdb_version=5.11.3\n options_file_version=1.1\n\n[DBOptions]\n stats_dump_period_sec=700")
66+
67+
assertThrows[Exception] {
68+
new StoreManager(dataDir, backupDir, columnFamilies, Some(file.getPath))
69+
}
70+
}
71+
72+
73+
74+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (C) 2011-2018 scalable minds UG (haftungsbeschränkt) & Co. KG. <http://scm.io>
3+
*/
4+
package com.scalableminds.fossildb
5+
6+
import java.io.{BufferedWriter, File, FileWriter}
7+
8+
trait TestHelpers {
9+
10+
protected def deleteRecursively(file: File): Unit = {
11+
if (file.isDirectory)
12+
file.listFiles.foreach(deleteRecursively)
13+
if (file.exists && !file.delete)
14+
throw new Exception(s"Unable to delete ${file.getAbsolutePath}")
15+
}
16+
17+
protected def writeToFile(file: File, content: String): Unit = {
18+
val bw = new BufferedWriter(new FileWriter(file))
19+
bw.write(content)
20+
bw.close()
21+
}
22+
23+
}

0 commit comments

Comments
 (0)