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  }