All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.storehaus.leveldb.LevelDBStore.scala Maven / Gradle / Ivy

There is a newer version: 0.15.0-RC1
Show newest version
/*
 * Copyright 2015 Twitter inc.
 *
 *    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.twitter.storehaus.leveldb

import java.io.File
import java.util.concurrent.Executors

import com.twitter.storehaus.Store
import com.twitter.util.{FuturePool, Time, Future}
import org.iq80.leveldb._
import org.fusesource.leveldbjni.JniDBFactory._

/**
 * Store interacting with a LevelDB database.
 * Example usage:
 * {{{
 *   import java.io.File
 *   import org.iq80.leveldb.Options
 *   import com.twitter.storehaus.leveldb.LevelDBStore
 *
 *   val dir = new File("/some/path/myleveldb-directory")
 *   dir.mkdirs()
 *   val options = {
 *     val opt = new Options
 *     opt.createIfMissing(true)
 *     opt.blockSize(8192)
 *     opt
 *   }
 *   val store = new LevelDBStore(dir, new Options, 4)
 * }}}
 * @constructor Create a new LevelDB store.
 * @param dir Directory where the database is/will be stored.
 * @param options Different options for the database, see: https://github.com/google/leveldb/blob/master/util/options.cc
 * @param numThreads Number of threads in the pool of threads interacting with the db.
 * @author Ben Fradet
 * @since 10/03/15
 */
class LevelDBStore(val dir: File,
                   val options: Options,
                   val numThreads: Int = Runtime.getRuntime.availableProcessors)
    extends Store[Array[Byte], Array[Byte]] {

  private lazy val db = factory.open(dir, options)
  private val futurePool = FuturePool(Executors.newFixedThreadPool(numThreads))

  /**
   * Get a single key from the store.
   * Prefer multiGet if you are getting more than one key at a time.
   */
  override def get(k: Array[Byte]): Future[Option[Array[Byte]]] =
    futurePool { Option(db.get(k)) }

  /**
   * Replace a value.
   * Delete is the same as put((k,None)).
   */
  override def put(kv: (Array[Byte], Option[Array[Byte]])): Future[Unit] = {
    require(kv._1 != null)
    kv match {
      case (k, Some(v)) => futurePool {
        db.put(k, v)
      }
      case (k, None) => futurePool {
        db.delete(k)
      }
    }
  }

  /** Replace a set of (key, value) pairs at one time. */
  override def multiPut[K1 <: Array[Byte]](kvs: Map[K1, Option[Array[Byte]]])
      : Map[K1, Future[Unit]] = {
    val future = futurePool {
      val batch = db.createWriteBatch()
      kvs.foreach {
        case (k, Some(v)) => batch.put(k, v)
        case (k, None) => batch.delete(k)
      }
      db.write(batch)
      batch.close()
    }
    kvs.mapValues(_ => future)
  }

  /**
   * Close this store and release any resources.
   * It is undefined what happens on get/multiGet after close
   */
  override def close(time: Time): Future[Unit] =
    futurePool { db.close() }.flatMap { _ => super.close(time) }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy