kunt

golang IRC bot
git clone git://git.2f30.org/kunt
Log | Files | Refs | LICENSE

mapfs.go (3734B)


      1 // Copyright 2013 TLH and dsp. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Simple fs backed up dictionary implementation
      6 package mapfs
      7 
      8 import (
      9 	"fmt"
     10 	"log"
     11 	"math/rand"
     12 	"os"
     13 	"path"
     14 	"path/filepath"
     15 	"strconv"
     16 	"sync"
     17 )
     18 
     19 type Mapfs struct {
     20 	name   string
     21 	path   string
     22 	prefix string
     23 	mapper Mapper
     24 	sync.Mutex
     25 }
     26 
     27 type Mapper interface {
     28 	rawRead(string) ([]byte, error)
     29 	rawWrite(string, []byte) error
     30 	get(int) ([]byte, error)
     31 	put(int, []byte) error
     32 	add([]byte) (int, error)
     33 	countMatches([]byte) int
     34 	virtSync() error
     35 	syncEntry(string, int) error
     36 	size() int
     37 	string() string
     38 }
     39 
     40 type MapIter func() (key int, data []byte, ok bool)
     41 
     42 func MakeMapIter(m *Mapfs) MapIter {
     43 	i := 0
     44 	return func() (key int, data []byte, ok bool) {
     45 		m.Lock()
     46 		defer m.Unlock()
     47 		for i < m.mapper.size() {
     48 			b, err := m.mapper.get(i)
     49 			if err == nil {
     50 				i++
     51 				return i - 1, b, true
     52 			}
     53 			i++
     54 		}
     55 		return -1, nil, false
     56 	}
     57 }
     58 
     59 func NewMapfs(m Mapper, name string, path string, prefix string) *Mapfs {
     60 	return &Mapfs{
     61 		name:   name,
     62 		path:   path,
     63 		prefix: prefix,
     64 		mapper: m,
     65 	}
     66 }
     67 
     68 func (m *Mapfs) rawRead(key int) ([]byte, error) {
     69 	path := fmt.Sprintf("%s/%s%d.txt", m.path, m.prefix, key)
     70 	return m.mapper.rawRead(path)
     71 }
     72 
     73 func (m *Mapfs) rawWrite(key int, buf []byte) error {
     74 	path := fmt.Sprintf("%s/%s%d.txt", m.path, m.prefix, key)
     75 	return m.mapper.rawWrite(path, buf)
     76 }
     77 
     78 func (m *Mapfs) Get(key int) ([]byte, error) {
     79 	m.Lock()
     80 	defer m.Unlock()
     81 	if m.mapper.size() == 0 {
     82 		return nil, fmt.Errorf("Empty map, can't fetch entry")
     83 	}
     84 	return m.mapper.get(key)
     85 }
     86 
     87 func (m *Mapfs) Put(key int, buf []byte) error {
     88 	m.Lock()
     89 	defer m.Unlock()
     90 	if key < 0 {
     91 		return fmt.Errorf("Invalid key: %d", key)
     92 	}
     93 	return m.mapper.put(key, buf)
     94 }
     95 
     96 func (m *Mapfs) Append(buf []byte) (int, error) {
     97 	m.Lock()
     98 	defer m.Unlock()
     99 	return m.mapper.add(buf)
    100 }
    101 
    102 func (m *Mapfs) CountMatches(buf []byte) int {
    103 	m.Lock()
    104 	defer m.Unlock()
    105 	return m.mapper.countMatches(buf)
    106 }
    107 
    108 func (m *Mapfs) Sync() error {
    109 	m.Lock()
    110 	defer m.Unlock()
    111 	for i := 0; i < m.mapper.size(); i++ {
    112 		_, err := m.mapper.get(i)
    113 		if err == nil {
    114 			path := fmt.Sprintf("%s/%s%d.txt",
    115 				m.path, m.prefix, i)
    116 			err = m.mapper.syncEntry(path, i)
    117 			if err != nil {
    118 				return err
    119 			}
    120 		}
    121 	}
    122 	return nil
    123 }
    124 
    125 func (m *Mapfs) virtSync() error {
    126 	m.Lock()
    127 	defer m.Unlock()
    128 	return m.mapper.virtSync()
    129 }
    130 
    131 func (m *Mapfs) Size() int {
    132 	m.Lock()
    133 	defer m.Unlock()
    134 	return m.mapper.size()
    135 }
    136 
    137 func (m *Mapfs) Empty() bool {
    138 	m.Lock()
    139 	defer m.Unlock()
    140 	if m.mapper.size() == 0 {
    141 		return true
    142 	}
    143 	return false
    144 }
    145 
    146 func (m *Mapfs) String() string {
    147 	m.Lock()
    148 	defer m.Unlock()
    149 	fmt.Printf("*** %s MAP DUMP ***\n", m.name)
    150 	return m.mapper.string()
    151 }
    152 
    153 func (m *Mapfs) Load() error {
    154 	_, err := os.Stat(m.path)
    155 	if err != nil {
    156 		// Just create the db if it does not exist
    157 		return os.MkdirAll(m.path, 0755)
    158 	}
    159 	walkFunc := func(p string, fi os.FileInfo, err error) error {
    160 		if fi.IsDir() {
    161 			return nil
    162 		}
    163 		if err != nil {
    164 			return err
    165 		}
    166 		base, ext := path.Base(p), path.Ext(p)
    167 		entry := base[len(m.prefix) : len(base)-len(ext)]
    168 		i, err := strconv.Atoi(entry)
    169 		if err != nil {
    170 			return err
    171 		}
    172 		b, err := m.rawRead(i)
    173 		if err != nil {
    174 			return err
    175 		}
    176 		err = m.Put(i, b)
    177 		if err != nil {
    178 			return err
    179 		}
    180 		return nil
    181 	}
    182 	err = filepath.Walk(m.path, walkFunc)
    183 	if err == nil {
    184 		m.virtSync()
    185 	}
    186 	return err
    187 }
    188 
    189 func (m *Mapfs) Rand() ([]byte, int) {
    190 	m.Lock()
    191 	defer m.Unlock()
    192 	idx := rand.Intn(m.mapper.size())
    193 	for i := 0; i < m.mapper.size(); i++ {
    194 		if i == idx {
    195 			b, err := m.mapper.get(i)
    196 			if err != nil {
    197 				log.Fatal(err)
    198 			}
    199 			return b, i
    200 		}
    201 	}
    202 	return nil, -1
    203 }