github.com/ndau/noms@v1.0.5/go/nbs/file_table_persister.go (about) 1 // Copyright 2016 Attic Labs, Inc. All rights reserved. 2 // Licensed under the Apache License, version 2.0: 3 // http://www.apache.org/licenses/LICENSE-2.0 4 5 package nbs 6 7 import ( 8 "bytes" 9 "io" 10 "io/ioutil" 11 "os" 12 "path/filepath" 13 14 "github.com/ndau/noms/go/d" 15 ) 16 17 const tempTablePrefix = "nbs_table_" 18 19 func newFSTablePersister(dir string, fc *fdCache, indexCache *indexCache) tablePersister { 20 d.PanicIfTrue(fc == nil) 21 return &fsTablePersister{dir, fc, indexCache} 22 } 23 24 type fsTablePersister struct { 25 dir string 26 fc *fdCache 27 indexCache *indexCache 28 } 29 30 func (ftp *fsTablePersister) Open(name addr, chunkCount uint32, stats *Stats) chunkSource { 31 return newMmapTableReader(ftp.dir, name, chunkCount, ftp.indexCache, ftp.fc) 32 } 33 34 func (ftp *fsTablePersister) Persist(mt *memTable, haver chunkReader, stats *Stats) chunkSource { 35 name, data, chunkCount := mt.write(haver, stats) 36 return ftp.persistTable(name, data, chunkCount, stats) 37 } 38 39 func (ftp *fsTablePersister) persistTable(name addr, data []byte, chunkCount uint32, stats *Stats) chunkSource { 40 if chunkCount == 0 { 41 return emptyChunkSource{} 42 } 43 tempName := func() string { 44 temp, err := ioutil.TempFile(ftp.dir, tempTablePrefix) 45 d.PanicIfError(err) 46 defer checkClose(temp) 47 io.Copy(temp, bytes.NewReader(data)) 48 index := parseTableIndex(data) 49 if ftp.indexCache != nil { 50 ftp.indexCache.lockEntry(name) 51 defer ftp.indexCache.unlockEntry(name) 52 ftp.indexCache.put(name, index) 53 } 54 return temp.Name() 55 }() 56 err := os.Rename(tempName, filepath.Join(ftp.dir, name.String())) 57 d.PanicIfError(err) 58 return ftp.Open(name, chunkCount, stats) 59 } 60 61 func (ftp *fsTablePersister) ConjoinAll(sources chunkSources, stats *Stats) chunkSource { 62 plan := planConjoin(sources, stats) 63 64 if plan.chunkCount == 0 { 65 return emptyChunkSource{} 66 } 67 68 name := nameFromSuffixes(plan.suffixes()) 69 tempName := func() string { 70 temp, err := ioutil.TempFile(ftp.dir, tempTablePrefix) 71 d.PanicIfError(err) 72 defer checkClose(temp) 73 74 for _, sws := range plan.sources { 75 r := sws.source.reader() 76 n, err := io.CopyN(temp, r, int64(sws.dataLen)) 77 d.PanicIfError(err) 78 d.PanicIfFalse(uint64(n) == sws.dataLen) 79 } 80 _, err = temp.Write(plan.mergedIndex) 81 d.PanicIfError(err) 82 83 index := parseTableIndex(plan.mergedIndex) 84 if ftp.indexCache != nil { 85 ftp.indexCache.put(name, index) 86 } 87 return temp.Name() 88 }() 89 90 err := os.Rename(tempName, filepath.Join(ftp.dir, name.String())) 91 d.PanicIfError(err) 92 93 return ftp.Open(name, plan.chunkCount, stats) 94 }