Skip to content
Merged
28 changes: 28 additions & 0 deletions .github/workflows/test-leveldb.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
on:
push:
branches:
- master
- main
paths:
- 'leveldb/**'
pull_request:
paths:
- 'leveldb/**'
name: "Tests LevelDB"
jobs:
Tests:
strategy:
matrix:
go-version:
- 1.23.x
- 1.24.x
runs-on: ubuntu-latest
steps:
- name: Fetch Repository
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '${{ matrix.go-version }}'
- name: Test LevelDB
run: cd ./leveldb && go test ./... -v -race
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type Storage interface {
- [Couchbase](./couchbase/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Couchbase%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-couchbase.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [DynamoDB](./dynamodb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+DynamoDB%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-dynamodb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [Etcd](./etcd/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Etcd%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-etcd.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [LevelDB](./leveldb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+LevelDB%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-leveldb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="LevelDB Tests Status"/> </a>
- [Memcache](./memcache/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Memcache%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-memcache.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [Memory](./memory/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Local+Storage%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-memory.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [Minio](./minio/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Minio%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-minio.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
Expand All @@ -76,4 +77,4 @@ type Storage interface {
- [ScyllaDB](./scylladb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+scylladb%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-scylladb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [SQLite3](./sqlite3/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Sqlite3%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-sqlite3.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [ClickHouse](./clickhouse/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Clickhouse%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-clickhouse.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [Valkey](./valkey/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+valkey%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-valkey.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
- [Valkey](./valkey/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+valkey%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-valkey.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
174 changes: 174 additions & 0 deletions leveldb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
---
id: leveldb
title: LevelDB
---

![Release](https://img.shields.io/github/v/tag/gofiber/storage?filter=leveldb*)
[![Discord](https://img.shields.io/discord/704680098577514527?style=flat&label=%F0%9F%92%AC%20discord&color=00ACD7)](https://gofiber.io/discord)
![Test](https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-leveldb.yml?label=Tests)
![Linter](https://img.shields.io/github/actions/workflow/status/gofiber/storage/linter.yml?label=Linter)

A fast key-value DB using [syndtr/goleveldb](https://github.com/syndtr/goleveldb)

### Table of Contents

- [Signatures](#signatures)
- [Installation](#installation)
- [Examples](#examples)
- [Config](#config)
- [Default Config](#default-config)

### Signatures

```go
func New(config ...Config) Storage
func (s *Storage) Get(key string) ([]byte, error)
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
func (s *Storage) Delete(key string) error
func (s *Storage) Reset() error
func (s *Storage) Close() error
func (s *Storage) Conn() *leveldb.DB
```

### Installation

LevelDB is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:

```bash
go mod init github.com/<user>/<repo>
```

And then install the leveldb implementation:

```bash
go get github.com/gofiber/storage/leveldb
```

### Examples

Import the storage package.

```go
import "github.com/gofiber/storage/leveldb"
```

You can use the following possibilities to create a storage:

```go
// Initialize default config
store := leveldb.New()

// Initialize custom config
store := leveldb.New(leveldb.Config{
Path: "./testdb",
GCInterval: 10 * time.Second,
})
```

### Config

```go
type Config struct {
// Path is the filesystem path for the database
//
// Optional. Default is "./fiber.leveldb"
Path string

// CacheSize is the size of LevelDB's cache (in MB)
//
// Optional. Default is 8MB
CacheSize int

// BlockSize is the size of data blocks (in KB)
//
// Optional. Default is 4KB
BlockSize int

// WriteBuffer is the size of write buffer (in MB)
//
// Optional. Default is 4MB
WriteBuffer int

// CompactionL0Trigger is the number of level-0 tables that triggers compaction
//
// Optional. Default is 4
CompactionL0Trigger int

// WriteL0PauseTrigger is the number of level-0 tables that triggers write pause
//
// Optional. Default is 12
WriteL0PauseTrigger int

// WriteL0SlowdownTrigger is the number of level-0 tables that triggers write slowdown
//
// Optional. Default is 8
WriteL0SlowdownTrigger int

// MaxOpenFiles is the maximum number of open files that can be held
//
// Optional. Default is 200 on MacOS, 500 on others
MaxOpenFiles int

// CompactionTableSize is the size of compaction table (in MB)
//
// Optional. Default is 2MB
CompactionTableSize int

// BloomFilterBits is the number of bits used in bloom filter
//
// Optional. Default is 10 bits/key
BloomFilterBits int

// NoSync completely disables fsync
//
// Optional. Default is false
NoSync bool

// ReadOnly opens the database in read-only mode
//
// Optional. Default is false
ReadOnly bool

// ErrorIfMissing returns error if database doesn't exist
//
// Optional. Default is false
ErrorIfMissing bool

// ErrorIfExist returns error if database exists
//
// Optional. Default is false
ErrorIfExist bool

// GCInterval is the garbage collection interval
//
// Optional. Default is 10 minutes
GCInterval time.Duration
}
```

### Default Config

```go
var ConfigDefault = Config{
Path: "./fiber.leveldb",
CacheSize: 8, // 8 MB
BlockSize: 4, // 4 KB
WriteBuffer: 4, // 4 MB
CompactionL0Trigger: 4,
WriteL0PauseTrigger: 12,
WriteL0SlowdownTrigger: 8,
MaxOpenFiles: func() int {
if runtime.GOOS == "darwin" {
return 200 // MacOS
}
return 500 // Unix/Linux
}(),
CompactionTableSize: 2, // 2 MB
BloomFilterBits: 10, // 10 bits per key
NoSync: false,
ReadOnly: false,
ErrorIfMissing: false,
ErrorIfExist: false,
GCInterval: 10 * time.Minute,
}
```
163 changes: 163 additions & 0 deletions leveldb/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package leveldb

import (
"runtime"
"time"
)

// Config holds the configuration options for LevelDB database
type Config struct {
// Path is the filesystem path for the database
//
// Optional. Default is "./fiber.leveldb"
Path string

// CacheSize is the size of LevelDB's cache (in MB)
//
// Optional. Default is 8MB
CacheSize int

// BlockSize is the size of data blocks (in KB)
//
// Optional. Default is 4KB
BlockSize int

// WriteBuffer is the size of write buffer (in MB)
//
// Optional. Default is 4MB
WriteBuffer int

// CompactionL0Trigger is the number of level-0 tables that triggers compaction
//
// Optional. Default is 4
CompactionL0Trigger int

// WriteL0PauseTrigger is the number of level-0 tables that triggers write pause
//
// Optional. Default is 12
WriteL0PauseTrigger int

// WriteL0SlowdownTrigger is the number of level-0 tables that triggers write slowdown
//
// Optional. Default is 8
WriteL0SlowdownTrigger int

// MaxOpenFiles is the maximum number of open files that can be held
//
// Optional. Default is 200 on MacOS, 500 on others
MaxOpenFiles int

// CompactionTableSize is the size of compaction table (in MB)
//
// Optional. Default is 2MB
CompactionTableSize int

// BloomFilterBits is the number of bits used in bloom filter
//
// Optional. Default is 10 bits/key
BloomFilterBits int

// NoSync completely disables fsync
//
// Optional. Default is false
NoSync bool

// ReadOnly opens the database in read-only mode
//
// Optional. Default is false
ReadOnly bool

// ErrorIfMissing returns error if database doesn't exist
//
// Optional. Default is false
ErrorIfMissing bool

// ErrorIfExist returns error if database exists
//
// Optional. Default is false
ErrorIfExist bool

// GCInterval is the garbage collection interval
//
// Optional. Default is 10 minutes
GCInterval time.Duration
}

// ConfigDefault is the default config
var ConfigDefault = Config{
Path: "./fiber.leveldb",
CacheSize: 8, // 8 MB
BlockSize: 4, // 4 KB
WriteBuffer: 4, // 4 MB
CompactionL0Trigger: 4,
WriteL0PauseTrigger: 12,
WriteL0SlowdownTrigger: 8,
MaxOpenFiles: func() int {
if runtime.GOOS == "darwin" {
return 200 // MacOS
}
return 500 // Unix/Linux
}(),
CompactionTableSize: 2, // 2 MB
BloomFilterBits: 10, // 10 bits per key
NoSync: false,
ReadOnly: false,
ErrorIfMissing: false,
ErrorIfExist: false,
GCInterval: 10 * time.Minute,
}

// configDefault is a helper function to set default values for the config
func configDefault(config ...Config) Config {
if len(config) < 1 {
return ConfigDefault
}

cfg := config[0]

if cfg.Path == "" {
cfg.Path = ConfigDefault.Path
}

if cfg.CacheSize <= 0 {
cfg.CacheSize = ConfigDefault.CacheSize
}

if cfg.BlockSize <= 0 {
cfg.BlockSize = ConfigDefault.BlockSize
}

if cfg.WriteBuffer <= 0 {
cfg.WriteBuffer = ConfigDefault.WriteBuffer
}

if cfg.CompactionL0Trigger <= 0 {
cfg.CompactionL0Trigger = ConfigDefault.CompactionL0Trigger
}

if cfg.WriteL0PauseTrigger <= 0 {
cfg.WriteL0PauseTrigger = ConfigDefault.WriteL0PauseTrigger
}

if cfg.WriteL0SlowdownTrigger <= 0 {
cfg.WriteL0SlowdownTrigger = ConfigDefault.WriteL0SlowdownTrigger
}

if cfg.MaxOpenFiles <= 0 {
cfg.MaxOpenFiles = ConfigDefault.MaxOpenFiles
}

if cfg.CompactionTableSize <= 0 {
cfg.CompactionTableSize = ConfigDefault.CompactionTableSize
}

if cfg.BloomFilterBits <= 0 {
cfg.BloomFilterBits = ConfigDefault.BloomFilterBits
}

if cfg.GCInterval <= 0 {
cfg.GCInterval = ConfigDefault.GCInterval
}

return cfg
}
Loading