rkv

package module
v0.0.0-...-f82fe14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2015 License: MIT Imports: 15 Imported by: 0

README

Rkv - reliable kv

Rkv - embeddable KV database in Go (golang).

  • Based on Riak bitcast format
  • Minimalistic design
  • Embeddable and self-contained (no C dependencies)
  • Contains both direct and goroutine friendly interfaces
  • Use rkv.NewSafe("test.kv") if you want to use with goroutines
  • Basic KV admin tool is included in /rkv subfolder, build it and install in your bin folder
  • Ability to save records with expiration
  • Use Rkv for databases under 50K records

Basic usage:

package main

import (
	"log"
	"strconv"

	"github.com/tadvi/rkv"
)

func main() {
	kv, err := rkv.New("test.kv")
	if err != nil {
		log.Fatal("Can not open database file")
	}
	defer kv.Close()

	type Mytype struct {
		Name string
		Pos  int
	}

	total := 10
	for i := 0; i < total; i++ {
		data1 := Mytype{Name: "one", Pos: 1}
		data2 := Mytype{Name: "two", Pos: 2}
		data3 := Mytype{Name: "three", Pos: 3}

		// this record will be saved for 2 days
		key1 := "key1_" + strconv.Itoa(i)
		err = kv.PutForDays(key1, &data1, 2)
		if err != nil {
			log.Fatal(err)
		}

		// this record will be saved for 3 days
		key2 := "key2_" + strconv.Itoa(i)
		err = kv.PutForDays(key2, &data2, 3)
		if err != nil {
			log.Fatal(err)
		}

		// this record will be saved until removed
		key3 := "key3_" + strconv.Itoa(i)
		err = kv.Put(key3, &data3)
		if err != nil {
			log.Fatal(err)
		}
	}
}

Use rkv tool

Use rkv tool to export or import data. Exported data is in JSON format. This makes it easier to move data around since so many other tools talk JSON.

You can also compact database files with rkv tool.

Basic usage:

$ rkv -c test.kv > test.json

This will compact database and export to JSON.

$ rkv test.kv > test.json

This simply exports database.

$ rkv test.kv < test.json

Imports previously exported database.

Use rkvcsv tool

Basic utility to bring data from relational databases into Rkv. Export your data into CSV then load it into Rkv using this tool.

First row of CSV must have field names.

rkvcsv tool imports CSV files. If all the column's values are numbers then that column is stored as number inside KV. Otherwise it is a string.

Since Rkv is KV datastore you should specify key field that will be used to find record using Get or similar methods. If you do not specify what field in CSV should become record key field inside Rkv then first field is used as key.

Basic usage:

$ rkvcsv -key 0 test.kv < test.csv

Import CSV file and take first field to be a key inside KV database.

$ rkvcsv -key 2 test.kv < test.csv

Import CSV file and take third field from CSV to be a key inside KV database.

Keys and values

Keys are strings. You can use numbers too by simply converting them into strings before you do Put.

Internally values are stored as JSON. So you can store your structs.

Fetch number of keys at once by using GetKeys(with, limit) and then iterate over them and use Get to get actual values like this:

// open database
kv, err := rkv.New("test.kv")
if err != nil {
    log.Fatal("Can not open database file")
}
defer kv.Close()

// get all keys from database - only do this on very small databases!
arr := kv.GetKeys("", -1)	

for _, key := range arr {
    v := Mytype{}
    err := kv.Get(key, &v)
    if err != nil {
        log.Fatal("Error while iterating %q", err.Error())
    }
}

TODO

  • Change to use RWMutex instead of Mutex
  • Add better iteration techniques
  • Add more test cases

Documentation

Overview

    Copyright (c) 2014-2015 Rkv Authors.
    Released under MIT license.

    This is based on https://code.google.com/p/gocask/ initial work by andrebq.

    Implementation of the bitcask key-value store from Riak.
    Paper available at: http://downloads.basho.com/papers/bitcask-intro.pdf
    The key-value pairs is stored in a log file, which only writes to the append, so a write never include a disk seek.
    Each record is stored in the following format:

   	|-------------------------------------------------------------------------------------------------------------------|
	|crc (int32) | tstamp (int32) | key length (int32) | value length (int32) | key data ([]byte) | value data ([]byte) |
	|-------------------------------------------------------------------------------------------------------------------|

    We use mostly same format but diverge in few aspects:
    1. If []byte value contains no data and is empty array, then it is deleted key, no data.
    2. tstamp contains days or 0. If tstamp is not 0 and it is less than todays day, key record has expired.
        Use PutForDays to take advantage of automatic record expiration.
    3. Compact and AutoCompact reads database and compacts it.
    4. Internally structs stored as JSON.

    This is decent format for databases up to 50K records.

Index

Constants

View Source
const (
	/* Header offset for each record in the store.
	This offset contains the following information (in the given order)
	| -------------------------------------------------------------------------|
	| crc (int32) | tstamp (int32) | key length (int32) | value length (int32) |
	| -------------------------------------------------------------------------|
	*/
	RecordHeaderSize int32 = 16
	MinCapKeys             = 1000
)

Variables

View Source
var (
	ErrBlankKey        = errors.New("rkv: key can not be blank")
	ErrKeyNotFound     = errors.New("rkv: key not found")
	ErrInvalidKeyIndex = errors.New("rkv: key index is greater than number of fields")
)

Functions

func ConvertToString

func ConvertToString(buff []byte) string

ConvertToString convert the given byte buffer using the default Go encoding (utf-8).

Types

type GFile

type GFile struct {
	// contains filtered or unexported fields
}

GFile wrap a os.file and provide some convenient methods.

func NewGFile

func NewGFile(f *os.File) *GFile

NewGFile wrap the file f in an convenient structure.

type Interface

type Interface interface {
	Reopen() error
	Close()

	Compact() error

	GetKeys(with string, limit int) []string
	Get(key string, value interface{}) error
	GetBytes(key string) ([]byte, error)

	Put(key string, value interface{}) error
	PutForDays(key string, value interface{}, days int32) error

	Exist(key string) bool

	Delete(key string) error
	DeleteAllKeys(with string) error

	ExportJSON(w io.Writer) error
	ImportJSON(r io.Reader) error
}

Interface only contains functions applicable to both Rkv and SafeRkv. Rkv has few more functions that are not goroutine friendly and not part of this common interface.

type Keydir

type Keydir struct {
	// contains filtered or unexported fields
}

Keydir in memory structure that holds the location of all the keys in the key-value store.

type KeydirEntry

type KeydirEntry struct {
	// contains filtered or unexported fields
}

KeydirEntry entries in the keydir, which holds the location of any key in the key-store.

type Rkv

type Rkv struct {

	// values below are calculated only when store is open, they are not updated on Delete or Put
	FillRatio float64 // active records divided by dead-removed records, used for AutoCompact
	CapKeys   int     // total number of keys = alive + dead
	LenKeys   int     // number of keys = alive
	// contains filtered or unexported fields
}

Main structure for any Rkv file. Holds the current directory and the active file

func New

func New(filename string) (*Rkv, error)

NewRkv open the key-value store at the given file. If the file doesn't exist one will be created. Always try to open for read-write, but if someone is already using this file, open in read-only mode. Populate the KeyDir structure with the information obtained from the data file.

func (*Rkv) AutoCompact

func (kv *Rkv) AutoCompact(fillRatio float64) error

AutoCompact auto compacts database once active records divided by dead-removed records (fill ratio) drops below fillRatio and there are enough alive and dead keys expressed as MinCapKeys.

func (*Rkv) Close

func (kv *Rkv) Close()

Close the key-value store.

func (*Rkv) Compact

func (kv *Rkv) Compact() error

Compact database.

func (*Rkv) Delete

func (kv *Rkv) Delete(key string) error

Delete specific key.

func (*Rkv) DeleteAllKeys

func (kv *Rkv) DeleteAllKeys(with string) error

DeleteAllKeys that match.

func (*Rkv) Exist

func (kv *Rkv) Exist(key string) bool

Exist returns true if such key exist in the store already.

func (*Rkv) ExportJSON

func (kv *Rkv) ExportJSON(w io.Writer) error

ExportJSON export all data from KV store as mixed JSON.

func (*Rkv) ExportKeyJSON

func (kv *Rkv) ExportKeyJSON(w io.Writer, key string) error

ExportKeyJSON export single key data from KV store as mixed JSON.

func (*Rkv) ExportKeysJSON

func (kv *Rkv) ExportKeysJSON(w io.Writer, with string) error

ExportKeysJSON export keys data from KV store as mixed JSON. Will return KeyNotFound error if can not find such key in datastore.

func (*Rkv) Get

func (kv *Rkv) Get(key string, value interface{}) error

Get retrieves the value for the given key from the keystore. May return ErrKeyNotFound error if can not find such key in datastore.

func (*Rkv) GetBytes

func (kv *Rkv) GetBytes(key string) ([]byte, error)

GetBytes returns raw bytes from the database.

func (*Rkv) GetKeys

func (kv *Rkv) GetKeys(with string, limit int) []string

GetKeys returns limited number of keys matching criterio, if limit is negative then returns all.

func (*Rkv) ImportCSV

func (kv *Rkv) ImportCSV(r io.Reader, key int) error

ImportCSV import CSV files with first row as field names.

func (*Rkv) ImportJSON

func (kv *Rkv) ImportJSON(r io.Reader) error

ImportJSON imports files produced with ExportJSON function, may use os.Stdin.

func (*Rkv) Iterator

func (kv *Rkv) Iterator(with string) <-chan string

Iterator returns iterator object (channel) of key values, do not use in more than one goroutine.

func (*Rkv) Put

func (kv *Rkv) Put(key string, value interface{}) error

Put save the key-value pair in the current file.

func (*Rkv) PutForDays

func (kv *Rkv) PutForDays(key string, value interface{}, days int32) error

PutForDays save the key-value pair in the current file with expiration in future date. Checking for expiration happens on database load, so only when database is reopen records become expired.

func (*Rkv) Reopen

func (kv *Rkv) Reopen() error

Reopen KV store.

type SafeRkv

type SafeRkv struct {
	Rkv
	// contains filtered or unexported fields
}

SafeRkv wraps Rkv to provide goroutine safe access to KV store.

func NewSafe

func NewSafe(filename string) (*SafeRkv, error)

NewSafe opens or creates new Rkv.

func (*SafeRkv) Compact

func (kv *SafeRkv) Compact() error

Compact same as Rkv function but goroutine friendly.

func (*SafeRkv) Delete

func (kv *SafeRkv) Delete(key string) error

Delete same as Rkv function but goroutine friendly.

func (*SafeRkv) DeleteAllKeys

func (kv *SafeRkv) DeleteAllKeys(with string) error

DeleteAllKeys same as Rkv function but goroutine friendly.

func (*SafeRkv) Exist

func (kv *SafeRkv) Exist(key string) bool

Exist same as Rkv function but goroutine friendly.

func (*SafeRkv) ExportJSON

func (kv *SafeRkv) ExportJSON(w io.Writer) error

ExportJSON same as Rkv function but goroutine friendly.

func (*SafeRkv) Get

func (kv *SafeRkv) Get(key string, value interface{}) error

Get same as Rkv function but goroutine friendly.

func (*SafeRkv) GetBytes

func (kv *SafeRkv) GetBytes(key string) ([]byte, error)

GetBytes same as Rkv function but goroutine friendly.

func (*SafeRkv) GetKeys

func (kv *SafeRkv) GetKeys(with string, limit int) []string

GetKeys same as Rkv function but goroutine friendly.

func (*SafeRkv) Iterator

func (kv *SafeRkv) Iterator(with string) <-chan string

Iterator is unsupported in goroutines.

func (*SafeRkv) Put

func (kv *SafeRkv) Put(key string, value interface{}) error

Put same as Rkv function but goroutine friendly.

func (*SafeRkv) PutForDays

func (kv *SafeRkv) PutForDays(key string, value interface{}, days int32) error

PutForDays same as Rkv function but goroutine friendly.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL