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 }