mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-06 16:45:55 +00:00
- lmdb as a backend (lmdb.go) (lmdb is the fastest known transactional storage backend) - per Tx call statics report enabled with PILOSA_CALLSTAT=true (stattx.go) - framework for per-shard db (dbshard.go) - txfactory handles any pair under blue-green testing (txfactory.go) - enable CGO in Dockerfiles for lmdb
191 lines
3.7 KiB
Go
191 lines
3.7 KiB
Go
// Copyright 2020 Pilosa Corp.
|
|
//
|
|
// 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 pilosa
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// types to support a database file per shard
|
|
|
|
type DBnode struct {
|
|
Holder map[string]*DBholder
|
|
}
|
|
type DBholder struct {
|
|
Index map[string]*DBindex
|
|
}
|
|
type DBindex struct {
|
|
Field map[string]*DBfield
|
|
}
|
|
type DBfield struct {
|
|
View map[string]*DBview
|
|
}
|
|
type DBview struct {
|
|
Shard map[uint64]*DBshard
|
|
}
|
|
|
|
type DBWrapper interface {
|
|
DeleteDBPath(path string) error
|
|
Close() error
|
|
}
|
|
|
|
type DBRegistry interface {
|
|
OpenDBWrapper(path string) (DBWrapper, error)
|
|
}
|
|
|
|
type DBshard struct {
|
|
Path string
|
|
ID DBID
|
|
Open bool
|
|
|
|
// With RWMutex, the
|
|
// writer who calls Lock() automatically gets priority over
|
|
// any reader who arrives later, even if the lock is held
|
|
// by a reader to start with.
|
|
RWMut sync.RWMutex
|
|
|
|
W DBWrapper
|
|
ParentDBview *DBview
|
|
}
|
|
|
|
type DBID struct {
|
|
Node string
|
|
Holder string
|
|
Index string
|
|
Field string
|
|
View string
|
|
Shard uint64
|
|
}
|
|
|
|
func (id *DBID) Path() (s string) {
|
|
s = id.Node + sep + id.Holder + sep + id.Index +
|
|
sep + id.Field + sep + id.View + sep + fmt.Sprintf("%04v", id.Shard)
|
|
return
|
|
}
|
|
|
|
type DBPerShard struct {
|
|
Mu sync.Mutex
|
|
|
|
Dir string
|
|
Node map[string]*DBnode
|
|
|
|
// just flat, not buried within the Node heirarchy.
|
|
// Easily see how many we have.
|
|
Flatmap map[*DBshard]struct{}
|
|
}
|
|
|
|
func NewDBPerShard(dir string) (d *DBPerShard) {
|
|
d = &DBPerShard{
|
|
Dir: dir,
|
|
Node: make(map[string]*DBnode),
|
|
Flatmap: make(map[*DBshard]struct{}),
|
|
}
|
|
return
|
|
}
|
|
|
|
func (per *DBPerShard) GetDBshard(registry DBRegistry, id DBID) (dbs *DBshard, err error) {
|
|
per.Mu.Lock()
|
|
defer per.Mu.Unlock()
|
|
|
|
dbn, ok := per.Node[id.Node]
|
|
if !ok {
|
|
dbn = &DBnode{
|
|
Holder: make(map[string]*DBholder),
|
|
}
|
|
per.Node[id.Node] = dbn
|
|
}
|
|
dbh, ok := dbn.Holder[id.Holder]
|
|
if !ok {
|
|
dbh = &DBholder{
|
|
Index: make(map[string]*DBindex),
|
|
}
|
|
dbn.Holder[id.Holder] = dbh
|
|
}
|
|
dbi, ok := dbh.Index[id.Index]
|
|
if !ok {
|
|
dbi = &DBindex{
|
|
Field: make(map[string]*DBfield),
|
|
}
|
|
dbh.Index[id.Index] = dbi
|
|
}
|
|
dbf, ok := dbi.Field[id.Field]
|
|
if !ok {
|
|
dbf = &DBfield{
|
|
View: make(map[string]*DBview),
|
|
}
|
|
dbi.Field[id.Field] = dbf
|
|
}
|
|
dbv, ok := dbf.View[id.View]
|
|
if !ok {
|
|
dbv = &DBview{
|
|
Shard: make(map[uint64]*DBshard),
|
|
}
|
|
dbf.View[id.View] = dbv
|
|
}
|
|
dbs, ok = dbv.Shard[id.Shard]
|
|
if !ok {
|
|
dbs = &DBshard{
|
|
ParentDBview: dbv,
|
|
ID: id,
|
|
Path: per.Dir + sep + id.Path(),
|
|
}
|
|
dbv.Shard[id.Shard] = dbs
|
|
}
|
|
if !dbs.Open {
|
|
dbs.W, err = registry.OpenDBWrapper(dbs.Path)
|
|
if dbs.W != nil {
|
|
per.Flatmap[dbs] = struct{}{}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (per *DBPerShard) Del(dbs *DBshard) (err error) {
|
|
per.Mu.Lock()
|
|
defer per.Mu.Unlock()
|
|
|
|
err = dbs.W.Close()
|
|
if err != nil {
|
|
return
|
|
}
|
|
panicOn(dbs.W.DeleteDBPath(dbs.Path))
|
|
delete(per.Flatmap, dbs)
|
|
|
|
// delete from the heirarchy
|
|
delete(dbs.ParentDBview.Shard, dbs.ID.Shard)
|
|
return
|
|
}
|
|
|
|
func (per *DBPerShard) Close() (err error) {
|
|
per.Mu.Lock()
|
|
defer per.Mu.Unlock()
|
|
|
|
for _, dbn := range per.Node {
|
|
for _, dbh := range dbn.Holder {
|
|
for _, dbi := range dbh.Index {
|
|
for _, dbf := range dbi.Field {
|
|
for _, dbv := range dbf.View {
|
|
for _, dbs := range dbv.Shard {
|
|
err = dbs.W.Close()
|
|
panicOn(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|