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

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