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 }