PageRenderTime 470ms CodeModel.GetById 70ms app.highlight 327ms RepoModel.GetById 58ms app.codeStats 1ms

/vt/vtsrv/examples/vtmm/vtmm.go

https://code.google.com/p/govt/
Go | 312 lines | 251 code | 53 blank | 8 comment | 43 complexity | 61a0128a7c27f6d508821588d838a5e9 MD5 | raw file
  1// Copyright 2010 The Govt Authors.  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// Based on Ron Minnich's idea.
  6
  7package main
  8
  9import (
 10	"code.google.com/p/govt/vt"
 11	"code.google.com/p/govt/vt/vtsrv"
 12	"crypto/sha1"
 13	"errors"
 14	"flag"
 15	"fmt"
 16	"hash"
 17	"os"
 18	"sync"
 19	"syscall"
 20	"time"
 21	"unsafe"
 22)
 23
 24const (
 25	Magic      = 0x28b4
 26	HeaderSize = 8 // magic[2] size[2] next[4]
 27)
 28
 29type File struct {
 30	sync.Mutex
 31	file    *os.File
 32	size    uint64
 33	synctip uint64
 34	tip     uint64
 35	lastip  uint64 // offset of the last block
 36
 37	chunksz uint64
 38	chunks  [][]byte
 39}
 40
 41type Vtmap struct {
 42	vtsrv.Srv
 43	sync.Mutex
 44
 45	f     *File
 46	htbl  map[string][]byte
 47	schan chan hash.Hash
 48}
 49
 50var addr = flag.String("addr", ":17034", "network address")
 51var debug = flag.Int("debug", 0, "print debug messages")
 52var align = flag.Int("align", 0, "block alignment")
 53
 54func (srv *Vtmap) init(fname string) (err error) {
 55	err = nil
 56	srv.htbl = make(map[string][]byte, 1<<12)
 57	srv.schan = make(chan hash.Hash, 32)
 58	srv.f, err = NewFile(fname)
 59	if err != nil {
 60		return
 61	}
 62
 63	err = srv.buildHash()
 64	return
 65}
 66
 67func NewFile(fname string) (f *File, err error) {
 68	var fi os.FileInfo
 69
 70	f = new(File)
 71	f.file, err = os.OpenFile(fname, os.O_RDWR, 0)
 72	if err != nil {
 73		return
 74	}
 75
 76	fi, err = f.file.Stat()
 77	if err != nil {
 78		return
 79	}
 80
 81	f.size = uint64(fi.Size())
 82	f.chunksz = 1 * 1024 * 1024 * 1024 // 1GB
 83	f.chunks = make([][]byte, f.size/f.chunksz+1)
 84	fd := f.file.Fd()
 85	for offset, i := uint64(0), 0; offset < f.size; i++ {
 86		n := f.chunksz
 87		if offset+uint64(n) > f.size {
 88			n = uint64(f.size - offset)
 89		}
 90
 91		f.chunks[i], err = syscall.Mmap(int(fd), int64(offset), int(n), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
 92		if err != nil {
 93			return nil, err
 94		}
 95
 96		offset += uint64(n)
 97	}
 98
 99	f.tip = 0
100	f.synctip = 0
101	f.lastip = ^uint64(0)
102
103	return f, nil
104}
105
106func (f *File) Sync() error {
107	f.Lock()
108	offset := f.synctip
109	count := f.tip - f.synctip
110	f.synctip = f.tip
111	f.Unlock()
112
113	for idx, off := int(offset/f.chunksz), int(offset%f.chunksz); count > 0; idx++ {
114		if idx > len(f.chunks) {
115			return errors.New("invalid sync range")
116		}
117
118		buf := f.chunks[idx]
119		n := len(buf) - off
120		if uint64(n) > count {
121			n = int(count)
122		}
123
124		start := uintptr(unsafe.Pointer(&buf[off])) &^ (0xfff) // start address needs to be page-aligned
125		end := uintptr(unsafe.Pointer(&buf[off+n-1]))
126		_, _, e1 := syscall.Syscall(syscall.SYS_MSYNC, start, end-start, uintptr(syscall.MS_SYNC))
127		if e1 != 0 {
128			return e1
129		}
130
131		count -= uint64(n)
132		off = 0
133	}
134
135	return nil
136}
137
138// updates the tip
139func (f *File) ReadBlock() ([]byte, error) {
140	var sz uint16
141	var next uint32
142
143	idx := int(f.tip / f.chunksz)
144	off := int(f.tip % f.chunksz)
145	buf := f.chunks[idx]
146
147	m, p := vt.Gint16(buf[off:])
148	sz, p = vt.Gint16(p)
149	next, p = vt.Gint32(p)
150
151	if m != Magic {
152		if m == 0 && sz == 0 {
153			// end of arena
154			return nil, nil
155		}
156
157		return nil, errors.New("magic not found")
158	}
159
160	f.lastip = f.tip
161	f.tip += uint64(next)
162
163	return p[0:sz], nil
164}
165
166func (f *File) WriteBlock(data []byte) (ndata []byte, err error) {
167	blksz := HeaderSize + len(data)
168	idx := int(f.tip / f.chunksz)
169	off := int(f.tip % f.chunksz)
170	buf := f.chunks[idx]
171	if off+blksz >= len(buf) {
172		idx++
173		if idx >= len(f.chunks) {
174			return nil, errors.New("arena full")
175		}
176
177		off = 0
178		buf = f.chunks[idx]
179		f.tip = uint64(idx) * f.chunksz
180		if off+blksz >= len(buf) {
181			return nil, errors.New("arena full")
182		}
183
184		// update the last block's next pointer
185		if f.lastip != ^uint64(0) {
186			b := f.chunks[f.lastip/f.chunksz]
187			_ = vt.Pint32(uint32(f.tip-f.lastip), b[(f.lastip%f.chunksz)+4:])
188			f.synctip = f.lastip
189		}
190	}
191
192	nextoff := f.tip + uint64(blksz)
193	if *align > 0 {
194		nextoff += uint64(*align) - nextoff%uint64(*align)
195	}
196
197	p := vt.Pint16(Magic, buf[off:])
198	p = vt.Pint16(uint16(len(data)), p)
199	p = vt.Pint32(uint32(nextoff-f.tip), p)
200	copy(p, data)
201	f.lastip = f.tip
202	f.tip = nextoff
203
204	return p[0:len(data)], nil
205}
206
207func (srv *Vtmap) buildHash() error {
208	nblk := 0
209	blksz := uint64(0)
210	stime := time.Now()
211	for {
212		blk, err := srv.f.ReadBlock()
213		if err != nil {
214			return err
215		}
216
217		if blk == nil {
218			break
219		}
220
221		score := srv.calcScore(blk)
222		srv.htbl[string([]byte(score))] = blk
223		nblk++
224		blksz += uint64(len(blk))
225	}
226	etime := time.Now()
227
228	srv.f.synctip = srv.f.tip
229	fmt.Printf("read %d blocks total %v bytes in %v ms\n", nblk, blksz, (etime.Sub(stime))/1000000)
230	fmt.Printf("total space used: %v bytes\n", srv.f.tip)
231	return nil
232}
233
234func (srv *Vtmap) calcScore(data []byte) (ret vt.Score) {
235	var s1 hash.Hash
236
237	select {
238	default:
239		s1 = sha1.New()
240	case s1 = <-srv.schan:
241		s1.Reset()
242	}
243
244	s1.Write(data)
245	ret = s1.Sum(nil)
246	select {
247	case srv.schan <- s1:
248		break
249	default:
250	}
251	return
252}
253
254func (srv *Vtmap) Hello(req *vtsrv.Req) {
255	req.RespondHello("anonymous", 0, 0)
256}
257
258func (srv *Vtmap) Read(req *vtsrv.Req) {
259	srv.Lock()
260	strscore := string([]byte(req.Tc.Score))
261	b := srv.htbl[strscore]
262	srv.Unlock()
263
264	if b == nil {
265		req.RespondError("not found")
266	} else {
267		req.RespondRead(b)
268	}
269}
270
271func (srv *Vtmap) Write(req *vtsrv.Req) {
272	score := srv.calcScore(req.Tc.Data)
273	strscore := string([]byte(score))
274	srv.Lock()
275	if srv.htbl[strscore] == nil {
276		block, err := srv.f.WriteBlock(req.Tc.Data)
277		if err != nil {
278			srv.Unlock()
279			req.RespondError(err.Error())
280			return
281		}
282
283		srv.htbl[strscore] = block
284	}
285	srv.Unlock()
286	req.RespondWrite(score)
287}
288
289func (srv *Vtmap) Sync(req *vtsrv.Req) {
290	srv.f.Sync()
291	req.RespondSync()
292}
293
294func main() {
295	flag.Parse()
296	if flag.NArg() != 1 {
297		fmt.Printf("expected file name\n")
298		return
299	}
300
301	srv := new(Vtmap)
302	err := srv.init(flag.Arg(0))
303	if err != nil {
304		fmt.Printf("Error: %v\n", err)
305		return
306	}
307
308	srv.Debuglevel = *debug
309	srv.Start(srv)
310	srv.StartStatsServer()
311	vtsrv.StartListener("tcp", *addr, &srv.Srv)
312}