file.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // Copyright 2016 The Internal 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. // Package file provides an os.File-like interface of a memory mapped file.
  5. package file
  6. import (
  7. "fmt"
  8. "io"
  9. "os"
  10. "time"
  11. "github.com/cznic/fileutil"
  12. "github.com/cznic/internal/buffer"
  13. "github.com/cznic/mathutil"
  14. "github.com/edsrzf/mmap-go"
  15. )
  16. const copyBufSize = 1 << 20 // 1 MB.
  17. var (
  18. _ Interface = (*mem)(nil)
  19. _ Interface = (*file)(nil)
  20. _ os.FileInfo = stat{}
  21. sysPage = os.Getpagesize()
  22. )
  23. // Interface is a os.File-like entity.
  24. type Interface interface {
  25. io.ReaderAt
  26. io.ReaderFrom
  27. io.WriterAt
  28. io.WriterTo
  29. Close() error
  30. Stat() (os.FileInfo, error)
  31. Sync() error
  32. Truncate(int64) error
  33. }
  34. // Open returns a new Interface backed by f, or an error, if any.
  35. func Open(f *os.File) (Interface, error) { return newFile(f, 1<<30, 20) }
  36. // OpenMem returns a new Interface, or an error, if any. The Interface content
  37. // is volatile, it's backed only by process' memory.
  38. func OpenMem(name string) (Interface, error) { return newMem(name, 18), nil }
  39. type memMap map[int64]*[]byte
  40. type mem struct {
  41. m memMap
  42. modTime time.Time
  43. name string
  44. pgBits uint
  45. pgMask int
  46. pgSize int
  47. size int64
  48. }
  49. func newMem(name string, pgBits uint) *mem {
  50. pgSize := 1 << pgBits
  51. return &mem{
  52. m: memMap{},
  53. modTime: time.Now(),
  54. name: name,
  55. pgBits: pgBits,
  56. pgMask: pgSize - 1,
  57. pgSize: pgSize,
  58. }
  59. }
  60. func (f *mem) IsDir() bool { return false }
  61. func (f *mem) Mode() os.FileMode { return os.ModeTemporary + 0600 }
  62. func (f *mem) ModTime() time.Time { return f.modTime }
  63. func (f *mem) Name() string { return f.name }
  64. func (f *mem) ReadFrom(r io.Reader) (n int64, err error) { return readFrom(f, r) }
  65. func (f *mem) Size() (n int64) { return f.size }
  66. func (f *mem) Stat() (os.FileInfo, error) { return f, nil }
  67. func (f *mem) Sync() error { return nil }
  68. func (f *mem) Sys() interface{} { return nil }
  69. func (f *mem) WriteTo(w io.Writer) (n int64, err error) { return writeTo(f, w) }
  70. func (f *mem) Close() error {
  71. f.Truncate(0)
  72. f.m = nil
  73. return nil
  74. }
  75. func (f *mem) ReadAt(b []byte, off int64) (n int, err error) {
  76. avail := f.size - off
  77. pi := off >> f.pgBits
  78. po := int(off) & f.pgMask
  79. rem := len(b)
  80. if int64(rem) >= avail {
  81. rem = int(avail)
  82. err = io.EOF
  83. }
  84. var zeroPage *[]byte
  85. for rem != 0 && avail > 0 {
  86. pg := f.m[pi]
  87. if pg == nil {
  88. if zeroPage == nil {
  89. zeroPage = buffer.CGet(f.pgSize)
  90. defer buffer.Put(zeroPage)
  91. }
  92. pg = zeroPage
  93. }
  94. nc := copy(b[:mathutil.Min(rem, f.pgSize)], (*pg)[po:])
  95. pi++
  96. po = 0
  97. rem -= nc
  98. n += nc
  99. b = b[nc:]
  100. }
  101. return n, err
  102. }
  103. func (f *mem) Truncate(size int64) (err error) {
  104. if size < 0 {
  105. return fmt.Errorf("invalid truncate size: %d", size)
  106. }
  107. first := size >> f.pgBits
  108. if size&int64(f.pgMask) != 0 {
  109. first++
  110. }
  111. last := f.size >> f.pgBits
  112. if f.size&int64(f.pgMask) != 0 {
  113. last++
  114. }
  115. for ; first <= last; first++ {
  116. if p := f.m[first]; p != nil {
  117. buffer.Put(p)
  118. }
  119. delete(f.m, first)
  120. }
  121. f.size = size
  122. return nil
  123. }
  124. func (f *mem) WriteAt(b []byte, off int64) (n int, err error) {
  125. pi := off >> f.pgBits
  126. po := int(off) & f.pgMask
  127. n = len(b)
  128. rem := n
  129. var nc int
  130. for rem != 0 {
  131. pg := f.m[pi]
  132. if pg == nil {
  133. pg = buffer.CGet(f.pgSize)
  134. f.m[pi] = pg
  135. }
  136. nc = copy((*pg)[po:], b)
  137. pi++
  138. po = 0
  139. rem -= nc
  140. b = b[nc:]
  141. }
  142. f.size = mathutil.MaxInt64(f.size, off+int64(n))
  143. return n, nil
  144. }
  145. type stat struct {
  146. os.FileInfo
  147. size int64
  148. }
  149. func (s stat) Size() int64 { return s.size }
  150. type fileMap map[int64]mmap.MMap
  151. type file struct {
  152. f *os.File
  153. m fileMap
  154. maxPages int
  155. pgBits uint
  156. pgMask int
  157. pgSize int
  158. size int64
  159. fsize int64
  160. }
  161. func newFile(f *os.File, maxSize int64, pgBits uint) (*file, error) {
  162. if maxSize < 0 {
  163. panic("internal error")
  164. }
  165. pgSize := 1 << pgBits
  166. switch {
  167. case sysPage > pgSize:
  168. pgBits = uint(mathutil.Log2Uint64(uint64(sysPage)))
  169. default:
  170. pgBits = uint(mathutil.Log2Uint64(uint64(pgSize / sysPage * sysPage)))
  171. }
  172. pgSize = 1 << pgBits
  173. fi := &file{
  174. f: f,
  175. m: fileMap{},
  176. maxPages: int(mathutil.MinInt64(
  177. 1024,
  178. mathutil.MaxInt64(maxSize/int64(pgSize), 1)),
  179. ),
  180. pgBits: pgBits,
  181. pgMask: pgSize - 1,
  182. pgSize: pgSize,
  183. }
  184. info, err := f.Stat()
  185. if err != nil {
  186. return nil, err
  187. }
  188. if err = fi.Truncate(info.Size()); err != nil {
  189. return nil, err
  190. }
  191. return fi, nil
  192. }
  193. func (f *file) ReadFrom(r io.Reader) (n int64, err error) { return readFrom(f, r) }
  194. func (f *file) Sync() (err error) { return f.f.Sync() }
  195. func (f *file) WriteTo(w io.Writer) (n int64, err error) { return writeTo(f, w) }
  196. func (f *file) Close() (err error) {
  197. for _, p := range f.m {
  198. if err = p.Unmap(); err != nil {
  199. return err
  200. }
  201. }
  202. if err = f.f.Truncate(f.size); err != nil {
  203. return err
  204. }
  205. if err = f.f.Sync(); err != nil {
  206. return err
  207. }
  208. if err = f.f.Close(); err != nil {
  209. return err
  210. }
  211. f.m = nil
  212. f.f = nil
  213. return nil
  214. }
  215. func (f *file) page(index int64) (mmap.MMap, error) {
  216. if len(f.m) == f.maxPages {
  217. for i, p := range f.m {
  218. if err := p.Unmap(); err != nil {
  219. return nil, err
  220. }
  221. delete(f.m, i)
  222. break
  223. }
  224. }
  225. off := index << f.pgBits
  226. fsize := off + int64(f.pgSize)
  227. if fsize > f.fsize {
  228. if err := f.f.Truncate(fsize); err != nil {
  229. return nil, err
  230. }
  231. f.fsize = fsize
  232. }
  233. p, err := mmap.MapRegion(f.f, f.pgSize, mmap.RDWR, 0, off)
  234. if err != nil {
  235. return nil, err
  236. }
  237. f.m[index] = p
  238. return p, nil
  239. }
  240. func (f *file) ReadAt(b []byte, off int64) (n int, err error) {
  241. avail := f.size - off
  242. pi := off >> f.pgBits
  243. po := int(off) & f.pgMask
  244. rem := len(b)
  245. if int64(rem) >= avail {
  246. rem = int(avail)
  247. err = io.EOF
  248. }
  249. for rem != 0 && avail > 0 {
  250. pg := f.m[pi]
  251. if pg == nil {
  252. if pg, err = f.page(pi); err != nil {
  253. return n, err
  254. }
  255. }
  256. nc := copy(b[:mathutil.Min(rem, f.pgSize)], pg[po:])
  257. pi++
  258. po = 0
  259. rem -= nc
  260. n += nc
  261. b = b[nc:]
  262. }
  263. return n, err
  264. }
  265. func (f *file) Stat() (os.FileInfo, error) {
  266. fi, err := f.f.Stat()
  267. if err != nil {
  268. return nil, err
  269. }
  270. return stat{fi, f.size}, nil
  271. }
  272. func (f *file) Truncate(size int64) (err error) {
  273. if size < 0 {
  274. return fmt.Errorf("invalid truncate size: %d", size)
  275. }
  276. first := size >> f.pgBits
  277. if size&int64(f.pgMask) != 0 {
  278. first++
  279. }
  280. last := f.size >> f.pgBits
  281. if f.size&int64(f.pgMask) != 0 {
  282. last++
  283. }
  284. for ; first <= last; first++ {
  285. if p := f.m[first]; p != nil {
  286. if err := p.Unmap(); err != nil {
  287. return err
  288. }
  289. }
  290. delete(f.m, first)
  291. }
  292. f.size = size
  293. fsize := (size + int64(f.pgSize) - 1) &^ int64(f.pgMask)
  294. if fsize != f.fsize {
  295. if err := f.f.Truncate(fsize); err != nil {
  296. return err
  297. }
  298. }
  299. f.fsize = fsize
  300. return nil
  301. }
  302. func (f *file) WriteAt(b []byte, off int64) (n int, err error) {
  303. pi := off >> f.pgBits
  304. po := int(off) & f.pgMask
  305. n = len(b)
  306. rem := n
  307. var nc int
  308. for rem != 0 {
  309. pg := f.m[pi]
  310. if pg == nil {
  311. pg, err = f.page(pi)
  312. if err != nil {
  313. return n, err
  314. }
  315. }
  316. nc = copy(pg[po:], b)
  317. pi++
  318. po = 0
  319. rem -= nc
  320. b = b[nc:]
  321. }
  322. f.size = mathutil.MaxInt64(f.size, off+int64(n))
  323. return n, nil
  324. }
  325. // ----------------------------------------------------------------------------
  326. func readFrom(f Interface, r io.Reader) (n int64, err error) {
  327. f.Truncate(0)
  328. p := buffer.Get(copyBufSize)
  329. b := *p
  330. defer buffer.Put(p)
  331. var off int64
  332. var werr error
  333. for {
  334. rn, rerr := r.Read(b)
  335. if rn != 0 {
  336. _, werr = f.WriteAt(b[:rn], off)
  337. n += int64(rn)
  338. off += int64(rn)
  339. }
  340. if rerr != nil {
  341. if !fileutil.IsEOF(rerr) {
  342. err = rerr
  343. }
  344. break
  345. }
  346. if werr != nil {
  347. err = werr
  348. break
  349. }
  350. }
  351. return n, err
  352. }
  353. func writeTo(f Interface, w io.Writer) (n int64, err error) {
  354. p := buffer.Get(copyBufSize)
  355. b := *p
  356. defer buffer.Put(p)
  357. var off int64
  358. var werr error
  359. for {
  360. rn, rerr := f.ReadAt(b, off)
  361. if rn != 0 {
  362. _, werr = w.Write(b[:rn])
  363. n += int64(rn)
  364. off += int64(rn)
  365. }
  366. if rerr != nil {
  367. if !fileutil.IsEOF(rerr) {
  368. err = rerr
  369. }
  370. break
  371. }
  372. if werr != nil {
  373. err = werr
  374. break
  375. }
  376. }
  377. return n, err
  378. }