modernc.org/ql@v1.4.7/file.go (about)

     1  // Copyright 2014 The ql 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  // Well known handles
     6  // 1: root
     7  // 2: id
     8  
     9  package ql // import "modernc.org/ql"
    10  
    11  import (
    12  	"bytes"
    13  	"crypto/sha1"
    14  	"fmt"
    15  	"io"
    16  	"io/ioutil"
    17  	"math/big"
    18  	"os"
    19  	"path/filepath"
    20  	"sync"
    21  	"time"
    22  
    23  	"modernc.org/lldb"
    24  	"modernc.org/mathutil"
    25  	"modernc.org/ql/vendored/github.com/camlistore/go4/lock"
    26  )
    27  
    28  const (
    29  	magic = "\x60\xdbql"
    30  )
    31  
    32  var (
    33  	_ btreeIndex    = (*fileIndex)(nil)
    34  	_ btreeIterator = (*fileBTreeIterator)(nil)
    35  	_ indexIterator = (*fileIndexIterator)(nil)
    36  	_ storage       = (*file)(nil)
    37  	_ temp          = (*fileTemp)(nil)
    38  )
    39  
    40  type chunk struct { // expanded to blob types lazily
    41  	f *file
    42  	b []byte
    43  }
    44  
    45  func (c chunk) expand() (v interface{}, err error) {
    46  	return c.f.loadChunks(c.b)
    47  }
    48  
    49  func expand1(data interface{}, e error) (v interface{}, err error) {
    50  	if e != nil {
    51  		return nil, e
    52  	}
    53  
    54  	c, ok := data.(chunk)
    55  	if !ok {
    56  		return data, nil
    57  	}
    58  
    59  	return c.expand()
    60  }
    61  
    62  func expand(data []interface{}) (err error) {
    63  	for i, v := range data {
    64  		if data[i], err = expand1(v, nil); err != nil {
    65  			return
    66  		}
    67  	}
    68  	return
    69  }
    70  
    71  // OpenFile returns a DB backed by a named file. The back end limits the size
    72  // of a record to about 64 kB.
    73  func OpenFile(name string, opt *Options) (db *DB, err error) {
    74  	var f lldb.OSFile
    75  	if f = opt.OSFile; f == nil {
    76  		f, err = os.OpenFile(name, os.O_RDWR, 0666)
    77  		if err != nil {
    78  			if !os.IsNotExist(err) {
    79  				return nil, err
    80  			}
    81  
    82  			if !opt.CanCreate {
    83  				return nil, err
    84  			}
    85  
    86  			switch opt.FileFormat {
    87  			case 0, 1, 2:
    88  				// ok
    89  			default:
    90  				return nil, fmt.Errorf("OpenFile: invalid option.FileFormat value: %v", opt.FileFormat)
    91  			}
    92  
    93  			f, err = os.OpenFile(name, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
    94  			if err != nil {
    95  				return nil, err
    96  			}
    97  		}
    98  	}
    99  
   100  	nfo, err := f.Stat()
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	var new bool
   106  	switch nfo.Size() {
   107  	case 0:
   108  		new = true
   109  		if opt.FileFormat == 2 {
   110  			return openFile2(name, f, opt, new)
   111  		}
   112  	default:
   113  		b := make([]byte, 16)
   114  		if _, err := f.ReadAt(b, 0); err != nil {
   115  			return nil, err
   116  		}
   117  
   118  		switch {
   119  		case bytes.Equal(b[:len(magic)], []byte(magic)):
   120  			// ok
   121  		case bytes.Equal(b[:len(magic2)], []byte(magic2)):
   122  			return openFile2(name, f, opt, new)
   123  		default:
   124  			return nil, fmt.Errorf("OpenFile: unrecognized file format")
   125  		}
   126  	}
   127  
   128  	fi, err := newFileFromOSFile(f, opt.Headroom, new)
   129  	if err != nil {
   130  		return
   131  	}
   132  
   133  	if fi.tempFile = opt.TempFile; fi.tempFile == nil {
   134  		fi.tempFile = func(dir, prefix string) (f lldb.OSFile, err error) {
   135  			f0, err := ioutil.TempFile(dir, prefix)
   136  			return f0, err
   137  		}
   138  	}
   139  
   140  	fi.removeEmptyWAL = opt.RemoveEmptyWAL
   141  
   142  	return newDB(fi)
   143  }
   144  
   145  // Options amend the behavior of OpenFile.
   146  //
   147  // CanCreate
   148  //
   149  // The CanCreate option enables OpenFile to create the DB file if it does not
   150  // exists.
   151  //
   152  // OSFile
   153  //
   154  // OSFile allows to pass an os.File like back end providing, for example,
   155  // encrypted storage. If this field is nil then OpenFile uses the file named by
   156  // the 'name' parameter instead.
   157  //
   158  // TempFile
   159  //
   160  // TempFile provides a temporary file used for evaluating the GROUP BY, ORDER
   161  // BY, ... clauses. The hook is intended to be used by encrypted DB back ends
   162  // to avoid leaks of unecrypted data to such temp files by providing temp files
   163  // which are encrypted as well. Note that *os.File satisfies the lldb.OSFile
   164  // interface.
   165  //
   166  // If TempFile is nil it defaults to ioutil.TempFile.
   167  //
   168  // Headroom
   169  //
   170  // Headroom selects the minimum size a WAL file will have. The "extra"
   171  // allocated file space serves as a headroom. Commits that fit into the
   172  // headroom should not fail due to 'not enough space on the volume' errors. The
   173  // headroom parameter is first rounded-up to a non negative multiple of the
   174  // size of the lldb.Allocator atom.
   175  //
   176  // RemoveEmptyWAL
   177  //
   178  // RemoveEmptyWAL controls whether empty WAL files should be deleted on
   179  // clean exit.
   180  //
   181  // FileVersion
   182  //
   183  // Select DB backend format when creating a new DB file.
   184  //
   185  // Supported values
   186  //
   187  //	0, 1	The original file format (version 1)
   188  //	2	File format version 2
   189  type Options struct {
   190  	CanCreate      bool
   191  	OSFile         lldb.OSFile
   192  	TempFile       func(dir, prefix string) (f lldb.OSFile, err error)
   193  	Headroom       int64
   194  	RemoveEmptyWAL bool
   195  	FileFormat     int
   196  }
   197  
   198  type fileBTreeIterator struct {
   199  	en *lldb.BTreeEnumerator
   200  	t  *fileTemp
   201  }
   202  
   203  func (it *fileBTreeIterator) Next() (k, v []interface{}, err error) {
   204  	bk, bv, err := it.en.Next()
   205  	if err != nil {
   206  		return
   207  	}
   208  
   209  	if k, err = lldb.DecodeScalars(bk); err != nil {
   210  		return
   211  	}
   212  
   213  	for i, val := range k {
   214  		b, ok := val.([]byte)
   215  		if !ok {
   216  			continue
   217  		}
   218  
   219  		c := chunk{it.t.file, b}
   220  		if k[i], err = c.expand(); err != nil {
   221  			return nil, nil, err
   222  		}
   223  	}
   224  
   225  	if err = enforce(k, it.t.colsK); err != nil {
   226  		return
   227  	}
   228  
   229  	if v, err = lldb.DecodeScalars(bv); err != nil {
   230  		return
   231  	}
   232  
   233  	for i, val := range v {
   234  		b, ok := val.([]byte)
   235  		if !ok {
   236  			continue
   237  		}
   238  
   239  		c := chunk{it.t.file, b}
   240  		if v[i], err = c.expand(); err != nil {
   241  			return nil, nil, err
   242  		}
   243  	}
   244  
   245  	err = enforce(v, it.t.colsV)
   246  	return
   247  }
   248  
   249  func enforce(val []interface{}, cols []*col) (err error) {
   250  	for i, v := range val {
   251  		if val[i], err = convert(v, cols[i].typ); err != nil {
   252  			return
   253  		}
   254  	}
   255  	return
   256  }
   257  
   258  //NTYPE
   259  func infer(from []interface{}, to *[]*col) {
   260  	if len(*to) == 0 {
   261  		*to = make([]*col, len(from))
   262  		for i := range *to {
   263  			(*to)[i] = &col{}
   264  		}
   265  	}
   266  	for i, c := range *to {
   267  		if f := from[i]; f != nil {
   268  			switch x := f.(type) {
   269  			//case nil:
   270  			case idealComplex:
   271  				c.typ = qComplex128
   272  				from[i] = complex128(x)
   273  			case idealFloat:
   274  				c.typ = qFloat64
   275  				from[i] = float64(x)
   276  			case idealInt:
   277  				c.typ = qInt64
   278  				from[i] = int64(x)
   279  			case idealRune:
   280  				c.typ = qInt32
   281  				from[i] = int32(x)
   282  			case idealUint:
   283  				c.typ = qUint64
   284  				from[i] = uint64(x)
   285  			case bool:
   286  				c.typ = qBool
   287  			case complex128:
   288  				c.typ = qComplex128
   289  			case complex64:
   290  				c.typ = qComplex64
   291  			case float64:
   292  				c.typ = qFloat64
   293  			case float32:
   294  				c.typ = qFloat32
   295  			case int8:
   296  				c.typ = qInt8
   297  			case int16:
   298  				c.typ = qInt16
   299  			case int32:
   300  				c.typ = qInt32
   301  			case int64:
   302  				c.typ = qInt64
   303  			case string:
   304  				c.typ = qString
   305  			case uint8:
   306  				c.typ = qUint8
   307  			case uint16:
   308  				c.typ = qUint16
   309  			case uint32:
   310  				c.typ = qUint32
   311  			case uint64:
   312  				c.typ = qUint64
   313  			case []byte:
   314  				c.typ = qBlob
   315  			case *big.Int:
   316  				c.typ = qBigInt
   317  			case *big.Rat:
   318  				c.typ = qBigRat
   319  			case time.Time:
   320  				c.typ = qTime
   321  			case time.Duration:
   322  				c.typ = qDuration
   323  			case chunk:
   324  				vals, err := lldb.DecodeScalars(x.b)
   325  				if err != nil {
   326  					panic(err)
   327  				}
   328  
   329  				if len(vals) == 0 {
   330  					panic("internal error 040")
   331  				}
   332  
   333  				i, ok := vals[0].(int64)
   334  				if !ok {
   335  					panic("internal error 041")
   336  				}
   337  
   338  				c.typ = int(i)
   339  			case map[string]interface{}: // map of ids of a cross join
   340  			default:
   341  				panic("internal error 042")
   342  			}
   343  		}
   344  	}
   345  }
   346  
   347  type fileTemp struct {
   348  	*file
   349  	colsK []*col
   350  	colsV []*col
   351  	t     *lldb.BTree
   352  }
   353  
   354  func (t *fileTemp) BeginTransaction() error { return nil }
   355  
   356  func (t *fileTemp) Get(k []interface{}) (v []interface{}, err error) {
   357  	if err = expand(k); err != nil {
   358  		return
   359  	}
   360  
   361  	if err = t.flatten(k); err != nil {
   362  		return nil, err
   363  	}
   364  
   365  	bk, err := lldb.EncodeScalars(k...)
   366  	if err != nil {
   367  		return
   368  	}
   369  
   370  	bv, err := t.t.Get(nil, bk)
   371  	if err != nil {
   372  		return
   373  	}
   374  
   375  	return lldb.DecodeScalars(bv)
   376  }
   377  
   378  func (t *fileTemp) Drop() (err error) {
   379  	if t.f0 == nil {
   380  		return
   381  	}
   382  
   383  	fn := t.f0.Name()
   384  	if err = t.f0.Close(); err != nil {
   385  		return
   386  	}
   387  
   388  	if fn == "" {
   389  		return
   390  	}
   391  
   392  	return os.Remove(fn)
   393  }
   394  
   395  func (t *fileTemp) SeekFirst() (it btreeIterator, err error) {
   396  	en, err := t.t.SeekFirst()
   397  	if err != nil {
   398  		return
   399  	}
   400  
   401  	return &fileBTreeIterator{t: t, en: en}, nil
   402  }
   403  
   404  func (t *fileTemp) Set(k, v []interface{}) (err error) {
   405  	if err = expand(k); err != nil {
   406  		return
   407  	}
   408  
   409  	if err = expand(v); err != nil {
   410  		return
   411  	}
   412  
   413  	infer(k, &t.colsK)
   414  	infer(v, &t.colsV)
   415  
   416  	if err = t.flatten(k); err != nil {
   417  		return
   418  	}
   419  
   420  	bk, err := lldb.EncodeScalars(k...)
   421  	if err != nil {
   422  		return
   423  	}
   424  
   425  	if err = t.flatten(v); err != nil {
   426  		return
   427  	}
   428  
   429  	bv, err := lldb.EncodeScalars(v...)
   430  	if err != nil {
   431  		return
   432  	}
   433  
   434  	return t.t.Set(bk, bv)
   435  }
   436  
   437  type file struct {
   438  	a              *lldb.Allocator
   439  	codec          *gobCoder
   440  	f              lldb.Filer
   441  	f0             lldb.OSFile
   442  	id             int64
   443  	lck            io.Closer
   444  	mu             sync.Mutex
   445  	name           string
   446  	tempFile       func(dir, prefix string) (f lldb.OSFile, err error)
   447  	wal            *os.File
   448  	removeEmptyWAL bool // Whether empty WAL files should be removed on close
   449  }
   450  
   451  func newFileFromOSFile(f lldb.OSFile, headroom int64, new bool) (fi *file, err error) {
   452  	nm := lockName(f.Name())
   453  	lck, err := lock.Lock(nm)
   454  	if err != nil {
   455  		if lck != nil {
   456  			lck.Close()
   457  		}
   458  		return nil, err
   459  	}
   460  
   461  	close := true
   462  	defer func() {
   463  		if close && lck != nil {
   464  			lck.Close()
   465  		}
   466  	}()
   467  
   468  	var w *os.File
   469  	closew := false
   470  	wn := WalName(f.Name())
   471  	w, err = os.OpenFile(wn, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
   472  	closew = true
   473  	defer func() {
   474  		if w != nil && closew {
   475  			nm := w.Name()
   476  			w.Close()
   477  			os.Remove(nm)
   478  			w = nil
   479  		}
   480  	}()
   481  
   482  	if err != nil {
   483  		if !os.IsExist(err) {
   484  			return nil, err
   485  		}
   486  
   487  		closew = false
   488  		w, err = os.OpenFile(wn, os.O_RDWR, 0666)
   489  		if err != nil {
   490  			return nil, err
   491  		}
   492  
   493  		closew = true
   494  		st, err := w.Stat()
   495  		if err != nil {
   496  			return nil, err
   497  		}
   498  
   499  		closew = st.Size() == 0
   500  	}
   501  
   502  	switch {
   503  	case new:
   504  		b := make([]byte, 16)
   505  		copy(b, []byte(magic))
   506  		if _, err := f.Write(b); err != nil {
   507  			return nil, err
   508  		}
   509  
   510  		filer := lldb.Filer(lldb.NewOSFiler(f))
   511  		filer = lldb.NewInnerFiler(filer, 16)
   512  		if filer, err = lldb.NewACIDFiler(filer, w, lldb.MinWAL(headroom)); err != nil {
   513  			return nil, err
   514  		}
   515  
   516  		a, err := lldb.NewAllocator(filer, &lldb.Options{})
   517  		if err != nil {
   518  			return nil, err
   519  		}
   520  
   521  		a.Compress = true
   522  		s := &file{
   523  			a:     a,
   524  			codec: newGobCoder(),
   525  			f0:    f,
   526  			f:     filer,
   527  			lck:   lck,
   528  			name:  f.Name(),
   529  			wal:   w,
   530  		}
   531  		if err = s.BeginTransaction(); err != nil {
   532  			return nil, err
   533  		}
   534  
   535  		h, err := s.Create()
   536  		if err != nil {
   537  			return nil, err
   538  		}
   539  
   540  		if h != 1 { // root
   541  			panic("internal error 043")
   542  		}
   543  
   544  		if h, err = s.a.Alloc(make([]byte, 8)); err != nil {
   545  			return nil, err
   546  		}
   547  
   548  		if h != 2 { // id
   549  			panic("internal error 044")
   550  		}
   551  
   552  		close, closew = false, false
   553  		return s, s.Commit()
   554  	default:
   555  		filer := lldb.Filer(lldb.NewOSFiler(f))
   556  		filer = lldb.NewInnerFiler(filer, 16)
   557  		if filer, err = lldb.NewACIDFiler(filer, w, lldb.MinWAL(headroom)); err != nil {
   558  			return nil, err
   559  		}
   560  
   561  		a, err := lldb.NewAllocator(filer, &lldb.Options{})
   562  		if err != nil {
   563  			return nil, err
   564  		}
   565  
   566  		bid, err := a.Get(nil, 2) // id
   567  		if err != nil {
   568  			return nil, err
   569  		}
   570  
   571  		if len(bid) != 8 {
   572  			return nil, fmt.Errorf("(file-003) corrupted DB: id |% x|", bid)
   573  		}
   574  
   575  		id := int64(0)
   576  		for _, v := range bid {
   577  			id = (id << 8) | int64(v)
   578  		}
   579  
   580  		a.Compress = true
   581  		s := &file{
   582  			a:     a,
   583  			codec: newGobCoder(),
   584  			f0:    f,
   585  			f:     filer,
   586  			id:    id,
   587  			lck:   lck,
   588  			name:  f.Name(),
   589  			wal:   w,
   590  		}
   591  
   592  		close, closew = false, false
   593  		return s, nil
   594  	}
   595  }
   596  
   597  func (s *file) OpenIndex(unique bool, handle int64) (btreeIndex, error) {
   598  	t, err := lldb.OpenBTree(s.a, s.collate, handle)
   599  	if err != nil {
   600  		return nil, err
   601  	}
   602  
   603  	return &fileIndex{s, handle, t, unique, newGobCoder()}, nil
   604  }
   605  
   606  func (s *file) CreateIndex(unique bool) ( /* handle */ int64, btreeIndex, error) {
   607  	t, h, err := lldb.CreateBTree(s.a, s.collate)
   608  	if err != nil {
   609  		return -1, nil, err
   610  	}
   611  
   612  	return h, &fileIndex{s, h, t, unique, newGobCoder()}, nil
   613  }
   614  
   615  func (s *file) Acid() bool { return s.wal != nil }
   616  
   617  func errSet(p *error, errs ...error) (err error) {
   618  	err = *p
   619  	for _, e := range errs {
   620  		if err != nil {
   621  			return
   622  		}
   623  		*p, err = e, e
   624  	}
   625  	return
   626  }
   627  
   628  func (s *file) lock() func() {
   629  	s.mu.Lock()
   630  	return s.mu.Unlock
   631  }
   632  
   633  func (s *file) Close() (err error) {
   634  	defer s.lock()()
   635  
   636  	es := s.f0.Sync()
   637  	ef := s.f0.Close()
   638  	var ew, estat, eremove error
   639  	if s.wal != nil {
   640  		remove := false
   641  		wn := s.wal.Name()
   642  		if s.removeEmptyWAL {
   643  			var stat os.FileInfo
   644  			stat, estat = s.wal.Stat()
   645  			remove = stat.Size() == 0
   646  		}
   647  		ew = s.wal.Close()
   648  		if remove {
   649  			eremove = os.Remove(wn)
   650  		}
   651  	}
   652  	el := s.lck.Close()
   653  	return errSet(&err, es, ef, ew, el, estat, eremove)
   654  }
   655  
   656  func (s *file) Name() string { return s.name }
   657  
   658  func (s *file) Verify() (allocs int64, err error) {
   659  	defer s.lock()()
   660  	var stat lldb.AllocStats
   661  	if err = s.a.Verify(lldb.NewMemFiler(), nil, &stat); err != nil {
   662  		return
   663  	}
   664  
   665  	allocs = stat.AllocAtoms
   666  	return
   667  }
   668  
   669  func (s *file) expandBytes(d []interface{}) (err error) {
   670  	for i, v := range d {
   671  		b, ok := v.([]byte)
   672  		if !ok {
   673  			continue
   674  		}
   675  
   676  		d[i], err = s.loadChunks(b)
   677  		if err != nil {
   678  			return
   679  		}
   680  	}
   681  	return
   682  }
   683  
   684  func (s *file) collate(a, b []byte) int { //TODO w/ error return
   685  	da, err := lldb.DecodeScalars(a)
   686  	if err != nil {
   687  		panic(err)
   688  	}
   689  
   690  	if err = s.expandBytes(da); err != nil {
   691  		panic(err)
   692  	}
   693  
   694  	db, err := lldb.DecodeScalars(b)
   695  	if err != nil {
   696  		panic(err)
   697  	}
   698  
   699  	if err = s.expandBytes(db); err != nil {
   700  		panic(err)
   701  	}
   702  
   703  	//dbg("da: %v, db: %v", da, db)
   704  	return collate(da, db)
   705  }
   706  
   707  func (s *file) CreateTemp(asc bool) (bt temp, err error) {
   708  	f, err := s.tempFile("", "ql-tmp-")
   709  	if err != nil {
   710  		return nil, err
   711  	}
   712  
   713  	fn := f.Name()
   714  	filer := lldb.NewOSFiler(f)
   715  	a, err := lldb.NewAllocator(filer, &lldb.Options{})
   716  	if err != nil {
   717  		f.Close()
   718  		os.Remove(fn)
   719  		return nil, err
   720  	}
   721  
   722  	k := 1
   723  	if !asc {
   724  		k = -1
   725  	}
   726  
   727  	t, _, err := lldb.CreateBTree(a, func(a, b []byte) int { //TODO w/ error return
   728  		return k * s.collate(a, b)
   729  	})
   730  	if err != nil {
   731  		f.Close()
   732  		if fn != "" {
   733  			os.Remove(fn)
   734  		}
   735  		return nil, err
   736  	}
   737  
   738  	x := &fileTemp{file: &file{
   739  		a:     a,
   740  		codec: newGobCoder(),
   741  		f0:    f,
   742  	},
   743  		t: t}
   744  	return x, nil
   745  }
   746  
   747  func (s *file) BeginTransaction() (err error) {
   748  	defer s.lock()()
   749  	return s.f.BeginUpdate()
   750  }
   751  
   752  func (s *file) Rollback() (err error) {
   753  	defer s.lock()()
   754  	return s.f.Rollback()
   755  }
   756  
   757  func (s *file) Commit() (err error) {
   758  	defer s.lock()()
   759  	return s.f.EndUpdate()
   760  }
   761  
   762  func (s *file) Create(data ...interface{}) (h int64, err error) {
   763  	if err = expand(data); err != nil {
   764  		return
   765  	}
   766  
   767  	if err = s.flatten(data); err != nil {
   768  		return
   769  	}
   770  
   771  	b, err := lldb.EncodeScalars(data...)
   772  	if err != nil {
   773  		return
   774  	}
   775  
   776  	defer s.lock()()
   777  	return s.a.Alloc(b)
   778  }
   779  
   780  func (s *file) Delete(h int64, blobCols ...*col) (err error) {
   781  	switch len(blobCols) {
   782  	case 0:
   783  		defer s.lock()()
   784  		return s.a.Free(h)
   785  	default:
   786  		return s.free(h, blobCols)
   787  	}
   788  }
   789  
   790  func (s *file) ResetID() (err error) {
   791  	s.id = 0
   792  	return
   793  }
   794  
   795  func (s *file) ID() (int64, error) {
   796  	defer s.lock()()
   797  
   798  	s.id++
   799  	b := make([]byte, 8)
   800  	id := s.id
   801  	for i := 7; i >= 0; i-- {
   802  		b[i] = byte(id)
   803  		id >>= 8
   804  	}
   805  
   806  	return s.id, s.a.Realloc(2, b)
   807  }
   808  
   809  func (s *file) free(h int64, blobCols []*col) (err error) {
   810  	b, err := s.a.Get(nil, h) //LATER +bufs
   811  	if err != nil {
   812  		return
   813  	}
   814  
   815  	rec, err := lldb.DecodeScalars(b)
   816  	if err != nil {
   817  		return
   818  	}
   819  
   820  	for _, col := range blobCols {
   821  		if col.index >= len(rec) {
   822  			return fmt.Errorf("(file-004) file.free: corrupted DB (record len)")
   823  		}
   824  		if col.index+2 >= len(rec) {
   825  			continue
   826  		}
   827  
   828  		switch x := rec[col.index+2].(type) {
   829  		case nil:
   830  			// nop
   831  		case []byte:
   832  			if err = s.freeChunks(x); err != nil {
   833  				return
   834  			}
   835  		}
   836  	}
   837  	defer s.lock()()
   838  	return s.a.Free(h)
   839  }
   840  
   841  func (s *file) Read(dst []interface{}, h int64, cols ...*col) (data []interface{}, err error) { //NTYPE
   842  	b, err := s.a.Get(nil, h) //LATER +bufs
   843  	if err != nil {
   844  		return
   845  	}
   846  
   847  	rec, err := lldb.DecodeScalars(b)
   848  	if err != nil {
   849  		return
   850  	}
   851  
   852  	for _, col := range cols {
   853  		i := col.index + 2
   854  		if i >= len(rec) || rec[i] == nil {
   855  			continue
   856  		}
   857  
   858  		switch col.typ {
   859  		case 0:
   860  		case qBool:
   861  		case qComplex64:
   862  			rec[i] = complex64(rec[i].(complex128))
   863  		case qComplex128:
   864  		case qFloat32:
   865  			rec[i] = float32(rec[i].(float64))
   866  		case qFloat64:
   867  		case qInt8:
   868  			rec[i] = int8(rec[i].(int64))
   869  		case qInt16:
   870  			rec[i] = int16(rec[i].(int64))
   871  		case qInt32:
   872  			rec[i] = int32(rec[i].(int64))
   873  		case qInt64:
   874  		case qString:
   875  		case qUint8:
   876  			rec[i] = uint8(rec[i].(uint64))
   877  		case qUint16:
   878  			rec[i] = uint16(rec[i].(uint64))
   879  		case qUint32:
   880  			rec[i] = uint32(rec[i].(uint64))
   881  		case qUint64:
   882  		case qBlob, qBigInt, qBigRat, qTime, qDuration:
   883  			switch x := rec[i].(type) {
   884  			case []byte:
   885  				rec[i] = chunk{f: s, b: x}
   886  			default:
   887  				return nil, fmt.Errorf("(file-006) corrupted DB: non nil chunk type is not []byte")
   888  			}
   889  		default:
   890  			panic("internal error 045")
   891  		}
   892  	}
   893  
   894  	if cols != nil {
   895  		for n, dn := len(cols)+2, len(rec); dn < n; dn++ {
   896  			rec = append(rec, nil)
   897  		}
   898  	}
   899  
   900  	return rec, nil
   901  }
   902  
   903  func (s *file) freeChunks(enc []byte) (err error) {
   904  	items, err := lldb.DecodeScalars(enc)
   905  	if err != nil {
   906  		return
   907  	}
   908  
   909  	var ok bool
   910  	var next int64
   911  	switch len(items) {
   912  	case 2:
   913  		return
   914  	case 3:
   915  		if next, ok = items[1].(int64); !ok || next == 0 {
   916  			return fmt.Errorf("(file-007) corrupted DB: first chunk link")
   917  		}
   918  	default:
   919  		return fmt.Errorf("(file-008) corrupted DB: first chunk")
   920  	}
   921  
   922  	for next != 0 {
   923  		b, err := s.a.Get(nil, next)
   924  		if err != nil {
   925  			return err
   926  		}
   927  
   928  		if items, err = lldb.DecodeScalars(b); err != nil {
   929  			return err
   930  		}
   931  
   932  		var h int64
   933  		switch len(items) {
   934  		case 1:
   935  			// nop
   936  		case 2:
   937  			if h, ok = items[0].(int64); !ok {
   938  				return fmt.Errorf("(file-009) corrupted DB: chunk link")
   939  			}
   940  
   941  		default:
   942  			return fmt.Errorf("(file-010) corrupted DB: chunk items %d (%v)", len(items), items)
   943  		}
   944  
   945  		s.mu.Lock()
   946  		if err = s.a.Free(next); err != nil {
   947  			s.mu.Unlock()
   948  			return err
   949  		}
   950  
   951  		s.mu.Unlock()
   952  		next = h
   953  	}
   954  	return
   955  }
   956  
   957  func (s *file) loadChunks(enc []byte) (v interface{}, err error) {
   958  	items, err := lldb.DecodeScalars(enc)
   959  	if err != nil {
   960  		return
   961  	}
   962  
   963  	var ok bool
   964  	var next int64
   965  	switch len(items) {
   966  	case 2:
   967  		// nop
   968  	case 3:
   969  		if next, ok = items[1].(int64); !ok || next == 0 {
   970  			return nil, fmt.Errorf("(file-011) corrupted DB: first chunk link")
   971  		}
   972  	default:
   973  		//fmt.Printf("%d: %#v\n", len(items), items)
   974  		return nil, fmt.Errorf("(file-012) corrupted DB: first chunk")
   975  	}
   976  
   977  	typ, ok := items[0].(int64)
   978  	if !ok {
   979  		return nil, fmt.Errorf("(file-013) corrupted DB: first chunk tag")
   980  	}
   981  
   982  	buf, ok := items[len(items)-1].([]byte)
   983  	if !ok {
   984  		return nil, fmt.Errorf("(file-014) corrupted DB: first chunk data")
   985  	}
   986  
   987  	for next != 0 {
   988  		b, err := s.a.Get(nil, next)
   989  		if err != nil {
   990  			return nil, err
   991  		}
   992  
   993  		if items, err = lldb.DecodeScalars(b); err != nil {
   994  			return nil, err
   995  		}
   996  
   997  		switch len(items) {
   998  		case 1:
   999  			next = 0
  1000  		case 2:
  1001  			if next, ok = items[0].(int64); !ok {
  1002  				return nil, fmt.Errorf("(file-015) corrupted DB: chunk link")
  1003  			}
  1004  
  1005  			items = items[1:]
  1006  		default:
  1007  			return nil, fmt.Errorf("(file-016) corrupted DB: chunk items %d (%v)", len(items), items)
  1008  		}
  1009  
  1010  		if b, ok = items[0].([]byte); !ok {
  1011  			return nil, fmt.Errorf("(file-017) corrupted DB: chunk data")
  1012  		}
  1013  
  1014  		buf = append(buf, b...)
  1015  	}
  1016  	return s.codec.decode(buf, int(typ))
  1017  }
  1018  
  1019  func (s *file) Update(h int64, data ...interface{}) (err error) {
  1020  	b, err := lldb.EncodeScalars(data...)
  1021  	if err != nil {
  1022  		return
  1023  	}
  1024  
  1025  	defer s.lock()()
  1026  	return s.a.Realloc(h, b)
  1027  }
  1028  
  1029  func (s *file) UpdateRow(h int64, blobCols []*col, data ...interface{}) (err error) {
  1030  	if len(blobCols) == 0 {
  1031  		return s.Update(h, data...)
  1032  	}
  1033  
  1034  	if err = expand(data); err != nil {
  1035  		return
  1036  	}
  1037  
  1038  	data0, err := s.Read(nil, h, blobCols...)
  1039  	if err != nil {
  1040  		return
  1041  	}
  1042  
  1043  	for _, c := range blobCols {
  1044  		if c.index+2 >= len(data0) {
  1045  			continue
  1046  		}
  1047  
  1048  		if x := data0[c.index+2]; x != nil {
  1049  			if err = s.freeChunks(x.(chunk).b); err != nil {
  1050  				return
  1051  			}
  1052  		}
  1053  	}
  1054  
  1055  	if err = s.flatten(data); err != nil {
  1056  		return
  1057  	}
  1058  
  1059  	return s.Update(h, data...)
  1060  }
  1061  
  1062  // []interface{}{qltype, ...}->[]interface{}{lldb scalar type, ...}
  1063  // + long blobs are (pre)written to a chain of chunks.
  1064  func (s *file) flatten(data []interface{}) (err error) {
  1065  	for i, v := range data {
  1066  		tag := 0
  1067  		var b []byte
  1068  		switch x := v.(type) {
  1069  		case []byte:
  1070  			tag = qBlob
  1071  			b = x
  1072  		case *big.Int:
  1073  			tag = qBigInt
  1074  			b, err = s.codec.encode(x)
  1075  		case *big.Rat:
  1076  			tag = qBigRat
  1077  			b, err = s.codec.encode(x)
  1078  		case time.Time:
  1079  			tag = qTime
  1080  			b, err = s.codec.encode(x)
  1081  		case time.Duration:
  1082  			tag = qDuration
  1083  			b, err = s.codec.encode(x)
  1084  		default:
  1085  			continue
  1086  		}
  1087  		if err != nil {
  1088  			return
  1089  		}
  1090  
  1091  		const chunk = 1 << 16
  1092  		chunks := 0
  1093  		var next int64
  1094  		var buf []byte
  1095  		for rem := len(b); rem > shortBlob; {
  1096  			n := mathutil.Min(rem, chunk)
  1097  			part := b[rem-n:]
  1098  			b = b[:rem-n]
  1099  			rem -= n
  1100  			switch next {
  1101  			case 0: // last chunk
  1102  				buf, err = lldb.EncodeScalars([]interface{}{part}...)
  1103  			default: // middle chunk
  1104  				buf, err = lldb.EncodeScalars([]interface{}{next, part}...)
  1105  			}
  1106  			if err != nil {
  1107  				return
  1108  			}
  1109  
  1110  			s.mu.Lock()
  1111  			h, err := s.a.Alloc(buf)
  1112  			s.mu.Unlock()
  1113  			if err != nil {
  1114  				return err
  1115  			}
  1116  
  1117  			next = h
  1118  			chunks++
  1119  		}
  1120  
  1121  		switch next {
  1122  		case 0: // single chunk
  1123  			buf, err = lldb.EncodeScalars([]interface{}{tag, b}...)
  1124  		default: // multi chunks
  1125  			buf, err = lldb.EncodeScalars([]interface{}{tag, next, b}...)
  1126  		}
  1127  		if err != nil {
  1128  			return
  1129  		}
  1130  
  1131  		data[i] = buf
  1132  	}
  1133  	return
  1134  }
  1135  
  1136  func lockName(dbname string) string {
  1137  	base := filepath.Base(filepath.Clean(dbname)) + "lockfile"
  1138  	h := sha1.New()
  1139  	io.WriteString(h, base)
  1140  	return filepath.Join(filepath.Dir(dbname), fmt.Sprintf(".%x", h.Sum(nil)))
  1141  }
  1142  
  1143  // WalName computes the WAL name for dbname. The results are different for
  1144  // relative vs absolute paths.
  1145  func WalName(dbname string) (r string) {
  1146  	base := filepath.Base(filepath.Clean(dbname))
  1147  	h := sha1.New()
  1148  	io.WriteString(h, base)
  1149  	return filepath.Join(filepath.Dir(dbname), fmt.Sprintf(".%x", h.Sum(nil)))
  1150  }
  1151  
  1152  type fileIndex struct {
  1153  	f      *file
  1154  	h      int64
  1155  	t      *lldb.BTree
  1156  	unique bool
  1157  	codec  *gobCoder
  1158  }
  1159  
  1160  func (x *fileIndex) Clear() error {
  1161  	return x.t.Clear()
  1162  }
  1163  
  1164  var gbZeroInt64 []byte
  1165  
  1166  func init() {
  1167  	var err error
  1168  	if gbZeroInt64, err = lldb.EncodeScalars(int64(0)); err != nil {
  1169  		panic(err)
  1170  	}
  1171  }
  1172  
  1173  func isIndexNull(data []interface{}) bool {
  1174  	for _, v := range data {
  1175  		if v != nil {
  1176  			return false
  1177  		}
  1178  	}
  1179  	return true
  1180  }
  1181  
  1182  func (x *fileIndex) Exists(indexedValues []interface{}) (bool, error) {
  1183  	for i, indexedValue := range indexedValues {
  1184  		chunk, ok := indexedValue.(chunk)
  1185  		if ok {
  1186  			indexedValues[i] = chunk.b
  1187  		}
  1188  	}
  1189  
  1190  	t := x.t
  1191  	switch {
  1192  	case !x.unique:
  1193  		return false, nil
  1194  	case isIndexNull(indexedValues): // unique, NULL
  1195  		return false, nil
  1196  	default: // unique, non NULL
  1197  		k, err := lldb.EncodeScalars(append(indexedValues, int64(0))...)
  1198  		if err != nil {
  1199  			return false, err
  1200  		}
  1201  
  1202  		v, err := t.Get(nil, k)
  1203  		return v != nil, err
  1204  	}
  1205  }
  1206  
  1207  // The []byte version of the key in the BTree shares chunks, if any, with
  1208  // the value stored in the record.
  1209  func (x *fileIndex) Create(indexedValues []interface{}, h int64) error {
  1210  	for i, indexedValue := range indexedValues {
  1211  		chunk, ok := indexedValue.(chunk)
  1212  		if ok {
  1213  			indexedValues[i] = chunk.b
  1214  		}
  1215  	}
  1216  
  1217  	t := x.t
  1218  	switch {
  1219  	case !x.unique:
  1220  		k, err := lldb.EncodeScalars(append(indexedValues, h)...)
  1221  		if err != nil {
  1222  			return err
  1223  		}
  1224  
  1225  		return t.Set(k, gbZeroInt64)
  1226  	case isIndexNull(indexedValues): // unique, NULL
  1227  		k, err := lldb.EncodeScalars(nil, h)
  1228  		if err != nil {
  1229  			return err
  1230  		}
  1231  
  1232  		return t.Set(k, gbZeroInt64)
  1233  	default: // unique, non NULL
  1234  		k, err := lldb.EncodeScalars(append(indexedValues, int64(0))...)
  1235  		if err != nil {
  1236  			return err
  1237  		}
  1238  
  1239  		v, err := lldb.EncodeScalars(h)
  1240  		if err != nil {
  1241  			return err
  1242  		}
  1243  
  1244  		_, _, err = t.Put(nil, k, func(key, old []byte) (new []byte, write bool, err error) {
  1245  			if old == nil {
  1246  				return v, true, nil
  1247  			}
  1248  
  1249  			return nil, false, errDuplicateUniqueIndex(indexedValues)
  1250  		})
  1251  		return err
  1252  	}
  1253  }
  1254  
  1255  func (x *fileIndex) Delete(indexedValues []interface{}, h int64) error {
  1256  	for i, indexedValue := range indexedValues {
  1257  		chunk, ok := indexedValue.(chunk)
  1258  		if ok {
  1259  			indexedValues[i] = chunk.b
  1260  		}
  1261  	}
  1262  
  1263  	t := x.t
  1264  	var k []byte
  1265  	var err error
  1266  	switch {
  1267  	case !x.unique:
  1268  		k, err = lldb.EncodeScalars(append(indexedValues, h)...)
  1269  	case isIndexNull(indexedValues): // unique, NULL
  1270  		k, err = lldb.EncodeScalars(nil, h)
  1271  	default: // unique, non NULL
  1272  		k, err = lldb.EncodeScalars(append(indexedValues, int64(0))...)
  1273  	}
  1274  	if err != nil {
  1275  		return err
  1276  	}
  1277  
  1278  	return t.Delete(k)
  1279  }
  1280  
  1281  func (x *fileIndex) Drop() error {
  1282  	if err := x.Clear(); err != nil {
  1283  		return err
  1284  	}
  1285  
  1286  	return x.f.a.Free(x.h)
  1287  }
  1288  
  1289  // []interface{}{qltype, ...}->[]interface{}{lldb scalar type, ...}
  1290  func (x *fileIndex) flatten(data []interface{}) (err error) {
  1291  	for i, v := range data {
  1292  		tag := 0
  1293  		var b []byte
  1294  		switch xx := v.(type) {
  1295  		case []byte:
  1296  			tag = qBlob
  1297  			b = xx
  1298  		case *big.Int:
  1299  			tag = qBigInt
  1300  			b, err = x.codec.encode(xx)
  1301  		case *big.Rat:
  1302  			tag = qBigRat
  1303  			b, err = x.codec.encode(xx)
  1304  		case time.Time:
  1305  			tag = qTime
  1306  			b, err = x.codec.encode(xx)
  1307  		case time.Duration:
  1308  			tag = qDuration
  1309  			b, err = x.codec.encode(xx)
  1310  		default:
  1311  			continue
  1312  		}
  1313  		if err != nil {
  1314  			return
  1315  		}
  1316  
  1317  		var buf []byte
  1318  		if buf, err = lldb.EncodeScalars([]interface{}{tag, b}...); err != nil {
  1319  			return
  1320  		}
  1321  
  1322  		data[i] = buf
  1323  	}
  1324  	return
  1325  }
  1326  
  1327  func (x *fileIndex) Seek(indexedValues []interface{}) (indexIterator, bool, error) {
  1328  	data := append(indexedValues, 0)
  1329  	if err := x.flatten(data); err != nil {
  1330  		return nil, false, err
  1331  	}
  1332  
  1333  	k, err := lldb.EncodeScalars(data...)
  1334  	if err != nil {
  1335  		return nil, false, err
  1336  	}
  1337  
  1338  	en, hit, err := x.t.Seek(k)
  1339  	if err != nil {
  1340  		return nil, false, err
  1341  	}
  1342  
  1343  	return &fileIndexIterator{x.f, en, x.unique}, hit, nil
  1344  }
  1345  
  1346  func (x *fileIndex) SeekFirst() (iter indexIterator, err error) {
  1347  	en, err := x.t.SeekFirst()
  1348  	return &fileIndexIterator{x.f, en, x.unique}, err
  1349  }
  1350  
  1351  func (x *fileIndex) SeekLast() (iter indexIterator, err error) {
  1352  	en, err := x.t.SeekLast()
  1353  	return &fileIndexIterator{x.f, en, x.unique}, err
  1354  }
  1355  
  1356  type fileIndexIterator struct {
  1357  	f      *file
  1358  	en     *lldb.BTreeEnumerator
  1359  	unique bool
  1360  }
  1361  
  1362  func (i *fileIndexIterator) nextPrev(f func() ([]byte, []byte, error)) ([]interface{}, int64, error) { //TODO(indices) blobs: +test
  1363  	bk, bv, err := f()
  1364  	if err != nil {
  1365  		return nil, -1, err
  1366  	}
  1367  
  1368  	dk, err := lldb.DecodeScalars(bk)
  1369  	if err != nil {
  1370  		return nil, -1, err
  1371  	}
  1372  
  1373  	b, ok := dk[0].([]byte)
  1374  	if ok {
  1375  		dk[0] = chunk{i.f, b}
  1376  		if expand(dk[:1]); err != nil {
  1377  			return nil, -1, err
  1378  		}
  1379  	}
  1380  
  1381  	var k indexKey
  1382  	k.value = dk[:len(dk)-1]
  1383  	switch i.unique {
  1384  	case true:
  1385  		if isIndexNull(k.value) {
  1386  			return nil, dk[len(dk)-1].(int64), nil
  1387  		}
  1388  
  1389  		dv, err := lldb.DecodeScalars(bv)
  1390  		if err != nil {
  1391  			return nil, -1, err
  1392  		}
  1393  
  1394  		return k.value, dv[0].(int64), nil
  1395  	default:
  1396  		return k.value, dk[len(dk)-1].(int64), nil
  1397  	}
  1398  }
  1399  
  1400  func (i *fileIndexIterator) Next() ([]interface{}, int64, error) { //TODO(indices) blobs: +test
  1401  	return i.nextPrev(i.en.Next)
  1402  }
  1403  
  1404  func (i *fileIndexIterator) Prev() ([]interface{}, int64, error) { //TODO(indices) blobs: +test
  1405  	return i.nextPrev(i.en.Prev)
  1406  }