mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-09 14:50:56 +00:00
vendor: Update golang.org/cznic/...
This commit is contained in:
parent
9bf6917ae8
commit
58cbd19742
44
vendor/github.com/cznic/b/doc.go
generated
vendored
44
vendor/github.com/cznic/b/doc.go
generated
vendored
@ -6,10 +6,30 @@
|
||||
//
|
||||
// Changelog
|
||||
//
|
||||
// 2016-07-16: Update benchmark results to newer Go version. Add a note on
|
||||
// concurrency.
|
||||
//
|
||||
// 2014-06-26: Lower GC presure by recycling things.
|
||||
//
|
||||
// 2014-04-18: Added new method Put.
|
||||
//
|
||||
// Concurrency considerations
|
||||
//
|
||||
// Tree.{Clear,Delete,Put,Set} mutate the tree. One can use eg. a
|
||||
// sync.Mutex.Lock/Unlock (or sync.RWMutex.Lock/Unlock) to wrap those calls if
|
||||
// they are to be invoked concurrently.
|
||||
//
|
||||
// Tree.{First,Get,Last,Len,Seek,SeekFirst,SekLast} read but do not mutate the
|
||||
// tree. One can use eg. a sync.RWMutex.RLock/RUnlock to wrap those calls if
|
||||
// they are to be invoked concurrently with any of the tree mutating methods.
|
||||
//
|
||||
// Enumerator.{Next,Prev} mutate the enumerator and read but not mutate the
|
||||
// tree. One can use eg. a sync.RWMutex.RLock/RUnlock to wrap those calls if
|
||||
// they are to be invoked concurrently with any of the tree mutating methods. A
|
||||
// separate mutex for the enumerator, or the whole tree in a simplified
|
||||
// variant, is necessary if the enumerator's Next/Prev methods per se are to
|
||||
// be invoked concurrently.
|
||||
//
|
||||
// Generic types
|
||||
//
|
||||
// Keys and their associated values are interface{} typed, similar to all of
|
||||
@ -34,20 +54,20 @@
|
||||
// No other changes to int.go are necessary, it compiles just fine.
|
||||
//
|
||||
// Running the benchmarks for 1000 keys on a machine with Intel i5-4670 CPU @
|
||||
// 3.4GHz, Go release 1.4.2.
|
||||
// 3.4GHz, Go 1.7rc1.
|
||||
//
|
||||
// $ go test -bench 1e3 example/all_test.go example/int.go
|
||||
// BenchmarkSetSeq1e3-4 20000 78265 ns/op
|
||||
// BenchmarkGetSeq1e3-4 20000 67980 ns/op
|
||||
// BenchmarkSetRnd1e3-4 10000 172720 ns/op
|
||||
// BenchmarkGetRnd1e3-4 20000 89539 ns/op
|
||||
// BenchmarkDelSeq1e3-4 20000 87863 ns/op
|
||||
// BenchmarkDelRnd1e3-4 10000 130891 ns/op
|
||||
// BenchmarkSeekSeq1e3-4 10000 100118 ns/op
|
||||
// BenchmarkSeekRnd1e3-4 10000 121684 ns/op
|
||||
// BenchmarkNext1e3-4 200000 6330 ns/op
|
||||
// BenchmarkPrev1e3-4 200000 9066 ns/op
|
||||
// PASS
|
||||
// BenchmarkSetSeq1e3 10000 151620 ns/op
|
||||
// BenchmarkGetSeq1e3 10000 115354 ns/op
|
||||
// BenchmarkSetRnd1e3 5000 255865 ns/op
|
||||
// BenchmarkGetRnd1e3 10000 140466 ns/op
|
||||
// BenchmarkDelSeq1e3 10000 143860 ns/op
|
||||
// BenchmarkDelRnd1e3 10000 188228 ns/op
|
||||
// BenchmarkSeekSeq1e3 10000 156448 ns/op
|
||||
// BenchmarkSeekRnd1e3 10000 190587 ns/op
|
||||
// BenchmarkNext1e3 200000 9407 ns/op
|
||||
// BenchmarkPrev1e3 200000 9306 ns/op
|
||||
// ok command-line-arguments 26.369s
|
||||
// ok command-line-arguments 42.531s
|
||||
// $
|
||||
package b
|
||||
|
2
vendor/github.com/cznic/mathutil/mathutil.go
generated
vendored
2
vendor/github.com/cznic/mathutil/mathutil.go
generated
vendored
@ -500,7 +500,7 @@ http://en.wikipedia.org/wiki/Miller-Rabin_primality_test#Algorithm_and_running_t
|
||||
return composite
|
||||
return probably prime
|
||||
|
||||
... this function behaves like passing 1 for 'k' and additionaly a
|
||||
... this function behaves like passing 1 for 'k' and additionally a
|
||||
fixed/non-random 'a'. Otherwise it's the same algorithm.
|
||||
|
||||
See also: http://mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html
|
||||
|
6
vendor/github.com/cznic/ql/design/doc.go
generated
vendored
6
vendor/github.com/cznic/ql/design/doc.go
generated
vendored
@ -285,9 +285,9 @@ Links
|
||||
|
||||
Referenced from above:
|
||||
|
||||
[0]: http://godoc.org/github.com/cznic/exp/lldb#hdr-Block_handles
|
||||
[1]: http://godoc.org/github.com/cznic/exp/lldb#EncodeScalars
|
||||
[2]: http://godoc.org/github.com/cznic/exp/lldb#BTree
|
||||
[0]: http://godoc.org/github.com/cznic/lldb#hdr-Block_handles
|
||||
[1]: http://godoc.org/github.com/cznic/lldb#EncodeScalars
|
||||
[2]: http://godoc.org/github.com/cznic/lldb#BTree
|
||||
|
||||
Rationale
|
||||
|
||||
|
20
vendor/github.com/cznic/ql/doc.go
generated
vendored
20
vendor/github.com/cznic/ql/doc.go
generated
vendored
@ -14,6 +14,20 @@
|
||||
//
|
||||
// Change list
|
||||
//
|
||||
// 2016-07-29: Release v1.0.6 enables alternatively using = instead of == for
|
||||
// equality oparation.
|
||||
//
|
||||
// https://github.com/cznic/ql/issues/131
|
||||
//
|
||||
// 2016-07-11: Release v1.0.5 undoes vendoring of lldb. QL now uses stable lldb
|
||||
// (github.com/cznic/lldb).
|
||||
//
|
||||
// https://github.com/cznic/ql/issues/128
|
||||
//
|
||||
// 2016-07-06: Release v1.0.4 fixes a panic when closing the WAL file.
|
||||
//
|
||||
// https://github.com/cznic/ql/pull/127
|
||||
//
|
||||
// 2016-04-03: Release v1.0.3 fixes a data race.
|
||||
//
|
||||
// https://github.com/cznic/ql/issues/126
|
||||
@ -299,7 +313,7 @@
|
||||
// andnot = "&^" .
|
||||
// lsh = "<<" .
|
||||
// le = "<=" .
|
||||
// eq = "==" .
|
||||
// eq = "==" | "=" .
|
||||
// ge = ">=" .
|
||||
// neq = "!=" .
|
||||
// oror = "||" .
|
||||
@ -800,7 +814,7 @@
|
||||
//
|
||||
// expr1 LIKE expr2
|
||||
//
|
||||
// yeild a boolean value true if expr2, a regular expression, matches expr1
|
||||
// yield a boolean value true if expr2, a regular expression, matches expr1
|
||||
// (see also [6]). Both expression must be of type string. If any one of the
|
||||
// expressions is NULL the result is NULL.
|
||||
//
|
||||
@ -887,7 +901,7 @@
|
||||
//
|
||||
// expr IS NOT NULL // case B
|
||||
//
|
||||
// yeild a boolean value true if expr does not have a specific type (case A) or
|
||||
// yield a boolean value true if expr does not have a specific type (case A) or
|
||||
// if expr has a specific type (case B). In other cases the result is a boolean
|
||||
// value false.
|
||||
//
|
||||
|
33
vendor/github.com/cznic/ql/etc.go
generated
vendored
33
vendor/github.com/cznic/ql/etc.go
generated
vendored
@ -10,7 +10,6 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -2764,38 +2763,6 @@ var isSystemName = map[string]bool{
|
||||
"__Table": true,
|
||||
}
|
||||
|
||||
func qualifier(s string) string {
|
||||
if pos := strings.IndexByte(s, '.'); pos >= 0 {
|
||||
s = s[:pos]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func mustQualifier(s string) string {
|
||||
q := qualifier(s)
|
||||
if q == s {
|
||||
panic("internal error 068")
|
||||
}
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
func selector(s string) string {
|
||||
if pos := strings.IndexByte(s, '.'); pos >= 0 {
|
||||
s = s[pos+1:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func mustSelector(s string) string {
|
||||
q := selector(s)
|
||||
if q == s {
|
||||
panic("internal error 053")
|
||||
}
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
func qnames(l []string) []string {
|
||||
r := make([]string, len(l))
|
||||
for i, v := range l {
|
||||
|
25
vendor/github.com/cznic/ql/expr.go
generated
vendored
25
vendor/github.com/cznic/ql/expr.go
generated
vendored
@ -135,12 +135,6 @@ func mentionedColumns(e expression) map[string]struct{} {
|
||||
return m
|
||||
}
|
||||
|
||||
func mentionedQColumns(e expression) map[string]struct{} {
|
||||
m := map[string]struct{}{}
|
||||
mentionedColumns0(e, true, false, m)
|
||||
return m
|
||||
}
|
||||
|
||||
func staticExpr(e expression) (expression, error) {
|
||||
if e.isStatic() {
|
||||
v, err := e.eval(nil, nil)
|
||||
@ -166,11 +160,6 @@ type (
|
||||
idealUint uint64
|
||||
)
|
||||
|
||||
type exprTab struct {
|
||||
expr expression
|
||||
table string
|
||||
}
|
||||
|
||||
type pexpr struct {
|
||||
expr expression
|
||||
}
|
||||
@ -3397,20 +3386,6 @@ func (u *unaryOperation) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// !ident
|
||||
func (u *unaryOperation) isNotQIdent() (bool, string, expression) {
|
||||
if u.op != '!' {
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
id, ok := u.v.(*ident)
|
||||
if ok && id.isQualified() {
|
||||
return true, mustQualifier(id.s), &unaryOperation{'!', &ident{mustSelector(id.s)}}
|
||||
}
|
||||
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
func (u *unaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (r interface{}, err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
|
4
vendor/github.com/cznic/ql/file.go
generated
vendored
4
vendor/github.com/cznic/ql/file.go
generated
vendored
@ -19,9 +19,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cznic/lldb"
|
||||
"github.com/cznic/mathutil"
|
||||
"github.com/cznic/ql/vendored/github.com/camlistore/go4/lock"
|
||||
"github.com/cznic/ql/vendored/github.com/cznic/exp/lldb"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -409,7 +409,7 @@ func newFileFromOSFile(f lldb.OSFile) (fi *file, err error) {
|
||||
w, err = os.OpenFile(wn, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
|
||||
closew = true
|
||||
defer func() {
|
||||
if closew {
|
||||
if w != nil && closew {
|
||||
nm := w.Name()
|
||||
w.Close()
|
||||
os.Remove(nm)
|
||||
|
5
vendor/github.com/cznic/ql/httpfs.go
generated
vendored
5
vendor/github.com/cznic/ql/httpfs.go
generated
vendored
@ -42,7 +42,6 @@ type HTTPFile struct {
|
||||
isFile bool
|
||||
name string
|
||||
off int
|
||||
sz int
|
||||
}
|
||||
|
||||
// Close implements http.File.
|
||||
@ -212,7 +211,7 @@ func (db *DB) NewHTTPFS(query string) (*HTTPFS, error) {
|
||||
// The elements in a file path are separated by slash ('/', U+002F) characters,
|
||||
// regardless of host operating system convention.
|
||||
func (f *HTTPFS) Open(name string) (http.File, error) {
|
||||
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
|
||||
if filepath.Separator != '/' && strings.Contains(name, string(filepath.Separator)) ||
|
||||
strings.Contains(name, "\x00") {
|
||||
return nil, fmt.Errorf("invalid character in file path: %q", name)
|
||||
}
|
||||
@ -264,7 +263,7 @@ func (f *HTTPFS) Open(name string) (http.File, error) {
|
||||
n++
|
||||
switch name := data[0].(type) {
|
||||
case string:
|
||||
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
|
||||
if filepath.Separator != '/' && strings.Contains(name, string(filepath.Separator)) ||
|
||||
strings.Contains(name, "\x00") {
|
||||
return false, fmt.Errorf("invalid character in file path: %q", name)
|
||||
}
|
||||
|
2021
vendor/github.com/cznic/ql/parser.go
generated
vendored
2021
vendor/github.com/cznic/ql/parser.go
generated
vendored
File diff suppressed because it is too large
Load Diff
22
vendor/github.com/cznic/ql/ql.go
generated
vendored
22
vendor/github.com/cznic/ql/ql.go
generated
vendored
@ -144,8 +144,8 @@ func (l List) String() string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// IsExplainStmt reports whether l is a single EXPLAIN statment or a single EXPLAIN
|
||||
// statment enclosed in a transaction.
|
||||
// IsExplainStmt reports whether l is a single EXPLAIN statement or a single EXPLAIN
|
||||
// statement enclosed in a transaction.
|
||||
func (l List) IsExplainStmt() bool {
|
||||
switch len(l.l) {
|
||||
case 1:
|
||||
@ -209,10 +209,10 @@ type TCtx struct {
|
||||
|
||||
// NewRWCtx returns a new read/write transaction context. NewRWCtx is safe for
|
||||
// concurrent use by multiple goroutines, every one of them will get a new,
|
||||
// unique conext.
|
||||
// unique context.
|
||||
func NewRWCtx() *TCtx { return &TCtx{} }
|
||||
|
||||
// Recordset is a result of a select statment. It can call a user function for
|
||||
// Recordset is a result of a select statement. It can call a user function for
|
||||
// every row (record) in the set using the Do method.
|
||||
//
|
||||
// Recordsets can be safely reused. Evaluation of the rows is performed lazily.
|
||||
@ -672,16 +672,6 @@ func (r tableRset) plan(ctx *execCtx) (plan, error) {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
func findFldIndex(fields []*fld, name string) int {
|
||||
for i, f := range fields {
|
||||
if f.name == name {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func findFld(fields []*fld, name string) (f *fld) {
|
||||
for _, f = range fields {
|
||||
if f.name == name {
|
||||
@ -1276,7 +1266,7 @@ func (db *DB) run1(pc *TCtx, s stmt, arg ...interface{}) (rs Recordset, tnla, tn
|
||||
}
|
||||
|
||||
if pc != db.cc {
|
||||
for db.rw == true {
|
||||
for db.rw {
|
||||
db.mu.Unlock() // Transaction isolation
|
||||
db.mu.Lock()
|
||||
}
|
||||
@ -1501,7 +1491,7 @@ type IndexInfo struct {
|
||||
Name string // Index name
|
||||
Table string // Table name.
|
||||
Column string // Column name.
|
||||
Unique bool // Wheter the index is unique.
|
||||
Unique bool // Whether the index is unique.
|
||||
ExpressionList []string // Index expression list.
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/cznic/ql/stmt.go
generated
vendored
2
vendor/github.com/cznic/ql/stmt.go
generated
vendored
@ -8,7 +8,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/cznic/strutil"
|
||||
)
|
||||
@ -716,7 +715,6 @@ type selectStmt struct {
|
||||
group *groupByRset
|
||||
hasAggregates bool
|
||||
limit *limitRset
|
||||
mu sync.Mutex
|
||||
offset *offsetRset
|
||||
order *orderByRset
|
||||
where *whereRset
|
||||
|
19
vendor/github.com/cznic/ql/storage.go
generated
vendored
19
vendor/github.com/cznic/ql/storage.go
generated
vendored
@ -137,8 +137,7 @@ type table struct {
|
||||
defaults []expression
|
||||
}
|
||||
|
||||
func (t *table) hasIndices() bool { return len(t.indices) != 0 || len(t.indices2) != 0 }
|
||||
func (t *table) hasIndices2() bool { return len(t.indices2) != 0 }
|
||||
func (t *table) hasIndices() bool { return len(t.indices) != 0 || len(t.indices2) != 0 }
|
||||
|
||||
func (t *table) constraintsAndDefaults(ctx *execCtx) error {
|
||||
if isSystemName[t.name] {
|
||||
@ -747,14 +746,6 @@ func (t *table) addRecord(execCtx *execCtx, r []interface{}) (id int64, err erro
|
||||
return
|
||||
}
|
||||
|
||||
func (t *table) flds() (r []*fld) {
|
||||
r = make([]*fld, len(t.cols))
|
||||
for i, v := range t.cols {
|
||||
r[i] = &fld{expr: &ident{v.name}, name: v.name}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *table) fieldNames() []string {
|
||||
r := make([]string, len(t.cols))
|
||||
for i, v := range t.cols {
|
||||
@ -802,10 +793,10 @@ type root struct {
|
||||
head int64 // Single linked table list
|
||||
lastInsertID int64
|
||||
parent *root
|
||||
rowsAffected int64 //LATER implement
|
||||
store storage
|
||||
tables map[string]*table
|
||||
thead *table
|
||||
//rowsAffected int64 //LATER implement
|
||||
store storage
|
||||
tables map[string]*table
|
||||
thead *table
|
||||
}
|
||||
|
||||
func newRoot(store storage) (r *root, err error) {
|
||||
|
324
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/2pc.go
generated
vendored
324
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/2pc.go
generated
vendored
@ -1,324 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Two Phase Commit & Structural ACID
|
||||
|
||||
package lldb
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/cznic/fileutil"
|
||||
"github.com/cznic/mathutil"
|
||||
)
|
||||
|
||||
var _ Filer = &ACIDFiler0{} // Ensure ACIDFiler0 is a Filer
|
||||
|
||||
type acidWrite struct {
|
||||
b []byte
|
||||
off int64
|
||||
}
|
||||
|
||||
type acidWriter0 ACIDFiler0
|
||||
|
||||
func (a *acidWriter0) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
f := (*ACIDFiler0)(a)
|
||||
if f.bwal == nil { // new epoch
|
||||
f.data = f.data[:0]
|
||||
f.bwal = bufio.NewWriter(f.wal)
|
||||
if err = a.writePacket([]interface{}{wpt00Header, walTypeACIDFiler0, ""}); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = a.writePacket([]interface{}{wpt00WriteData, b, off}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f.data = append(f.data, acidWrite{b, off})
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (a *acidWriter0) writePacket(items []interface{}) (err error) {
|
||||
f := (*ACIDFiler0)(a)
|
||||
b, err := EncodeScalars(items...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var b4 [4]byte
|
||||
binary.BigEndian.PutUint32(b4[:], uint32(len(b)))
|
||||
if _, err = f.bwal.Write(b4[:]); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = f.bwal.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if m := (4 + len(b)) % 16; m != 0 {
|
||||
var pad [15]byte
|
||||
_, err = f.bwal.Write(pad[:16-m])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// WAL Packet Tags
|
||||
const (
|
||||
wpt00Header = iota
|
||||
wpt00WriteData
|
||||
wpt00Checkpoint
|
||||
)
|
||||
|
||||
const (
|
||||
walTypeACIDFiler0 = iota
|
||||
)
|
||||
|
||||
// ACIDFiler0 is a very simple, synchronous implementation of 2PC. It uses a
|
||||
// single write ahead log file to provide the structural atomicity
|
||||
// (BeginUpdate/EndUpdate/Rollback) and durability (DB can be recovered from
|
||||
// WAL if a crash occurred).
|
||||
//
|
||||
// ACIDFiler0 is a Filer.
|
||||
//
|
||||
// NOTE: Durable synchronous 2PC involves three fsyncs in this implementation
|
||||
// (WAL, DB, zero truncated WAL). Where possible, it's recommended to collect
|
||||
// transactions for, say one second before performing the two phase commit as
|
||||
// the typical performance for rotational hard disks is about few tens of
|
||||
// fsyncs per second atmost. For an example of such collective transaction
|
||||
// approach please see the colecting FSM STT in Dbm's documentation[1].
|
||||
//
|
||||
// [1]: http://godoc.org/github.com/cznic/exp/dbm
|
||||
type ACIDFiler0 struct {
|
||||
*RollbackFiler
|
||||
wal *os.File
|
||||
bwal *bufio.Writer
|
||||
data []acidWrite
|
||||
testHook bool // keeps WAL untruncated (once)
|
||||
peakWal int64 // tracks WAL maximum used size
|
||||
peakBitFilerPages int // track maximum transaction memory
|
||||
}
|
||||
|
||||
// NewACIDFiler0 returns a newly created ACIDFiler0 with WAL in wal.
|
||||
//
|
||||
// If the WAL is zero sized then a previous clean shutdown of db is taken for
|
||||
// granted and no recovery procedure is taken.
|
||||
//
|
||||
// If the WAL is of non zero size then it is checked for having a
|
||||
// commited/fully finished transaction not yet been reflected in db. If such
|
||||
// transaction exists it's committed to db. If the recovery process finishes
|
||||
// successfully, the WAL is truncated to zero size and fsync'ed prior to return
|
||||
// from NewACIDFiler0.
|
||||
func NewACIDFiler(db Filer, wal *os.File) (r *ACIDFiler0, err error) {
|
||||
fi, err := wal.Stat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r = &ACIDFiler0{wal: wal}
|
||||
|
||||
if fi.Size() != 0 {
|
||||
if err = r.recoverDb(db); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
acidWriter := (*acidWriter0)(r)
|
||||
|
||||
if r.RollbackFiler, err = NewRollbackFiler(
|
||||
db,
|
||||
func(sz int64) (err error) {
|
||||
// Checkpoint
|
||||
if err = acidWriter.writePacket([]interface{}{wpt00Checkpoint, sz}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = r.bwal.Flush(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.bwal = nil
|
||||
|
||||
if err = r.wal.Sync(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
wfi, err := r.wal.Stat()
|
||||
switch err != nil {
|
||||
case true:
|
||||
// unexpected, but ignored
|
||||
case false:
|
||||
r.peakWal = mathutil.MaxInt64(wfi.Size(), r.peakWal)
|
||||
}
|
||||
|
||||
// Phase 1 commit complete
|
||||
|
||||
for _, v := range r.data {
|
||||
if _, err := db.WriteAt(v.b, v.off); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = db.Truncate(sz); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = db.Sync(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Phase 2 commit complete
|
||||
|
||||
if !r.testHook {
|
||||
if err = r.wal.Truncate(0); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = r.wal.Seek(0, 0); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
r.testHook = false
|
||||
return r.wal.Sync()
|
||||
|
||||
},
|
||||
acidWriter,
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// PeakWALSize reports the maximum size WAL has ever used.
|
||||
func (a ACIDFiler0) PeakWALSize() int64 {
|
||||
return a.peakWal
|
||||
}
|
||||
|
||||
func (a *ACIDFiler0) readPacket(f *bufio.Reader) (items []interface{}, err error) {
|
||||
var b4 [4]byte
|
||||
n, err := io.ReadAtLeast(f, b4[:], 4)
|
||||
if n != 4 {
|
||||
return
|
||||
}
|
||||
|
||||
ln := int(binary.BigEndian.Uint32(b4[:]))
|
||||
m := (4 + ln) % 16
|
||||
padd := (16 - m) % 16
|
||||
b := make([]byte, ln+padd)
|
||||
if n, err = io.ReadAtLeast(f, b, len(b)); n != len(b) {
|
||||
return
|
||||
}
|
||||
|
||||
return DecodeScalars(b[:ln])
|
||||
}
|
||||
|
||||
func (a *ACIDFiler0) recoverDb(db Filer) (err error) {
|
||||
fi, err := a.wal.Stat()
|
||||
if err != nil {
|
||||
return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: err}
|
||||
}
|
||||
|
||||
if sz := fi.Size(); sz%16 != 0 {
|
||||
return &ErrILSEQ{Type: ErrFileSize, Name: a.wal.Name(), Arg: sz}
|
||||
}
|
||||
|
||||
f := bufio.NewReader(a.wal)
|
||||
items, err := a.readPacket(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(items) != 3 || items[0] != int64(wpt00Header) || items[1] != int64(walTypeACIDFiler0) {
|
||||
return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("invalid packet items %#v", items)}
|
||||
}
|
||||
|
||||
tr := NewBTree(nil)
|
||||
|
||||
for {
|
||||
items, err = a.readPacket(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(items) < 2 {
|
||||
return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("too few packet items %#v", items)}
|
||||
}
|
||||
|
||||
switch items[0] {
|
||||
case int64(wpt00WriteData):
|
||||
if len(items) != 3 {
|
||||
return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("invalid data packet items %#v", items)}
|
||||
}
|
||||
|
||||
b, off := items[1].([]byte), items[2].(int64)
|
||||
var key [8]byte
|
||||
binary.BigEndian.PutUint64(key[:], uint64(off))
|
||||
if err = tr.Set(key[:], b); err != nil {
|
||||
return
|
||||
}
|
||||
case int64(wpt00Checkpoint):
|
||||
var b1 [1]byte
|
||||
if n, err := f.Read(b1[:]); n != 0 || err == nil {
|
||||
return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("checkpoint n %d, err %v", n, err)}
|
||||
}
|
||||
|
||||
if len(items) != 2 {
|
||||
return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("checkpoint packet invalid items %#v", items)}
|
||||
}
|
||||
|
||||
sz := items[1].(int64)
|
||||
enum, err := tr.seekFirst()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
k, v, err := enum.current()
|
||||
if err != nil {
|
||||
if fileutil.IsEOF(err) {
|
||||
break
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = db.WriteAt(v, int64(binary.BigEndian.Uint64(k))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = enum.next(); err != nil {
|
||||
if fileutil.IsEOF(err) {
|
||||
break
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = db.Truncate(sz); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = db.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Recovery complete
|
||||
|
||||
if err = a.wal.Truncate(0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return a.wal.Sync()
|
||||
default:
|
||||
return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("packet tag %v", items[0])}
|
||||
}
|
||||
}
|
||||
}
|
44
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/2pc_docs.go
generated
vendored
44
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/2pc_docs.go
generated
vendored
@ -1,44 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Anatomy of a WAL file
|
||||
|
||||
WAL file
|
||||
A sequence of packets
|
||||
|
||||
WAL packet, parts in slice notation
|
||||
[0:4], 4 bytes: N uint32 // network byte order
|
||||
[4:4+N], N bytes: payload []byte // gb encoded scalars
|
||||
|
||||
Packets, including the 4 byte 'size' prefix, MUST BE padded to size == 0 (mod
|
||||
16). The values of the padding bytes MUST BE zero.
|
||||
|
||||
Encoded scalars first item is a packet type number (packet tag). The meaning of
|
||||
any other item(s) of the payload depends on the packet tag.
|
||||
|
||||
Packet definitions
|
||||
|
||||
{wpt00Header int, typ int, s string}
|
||||
typ: Must be zero (ACIDFiler0 file).
|
||||
s: Any comment string, empty string is okay.
|
||||
|
||||
This packet must be present only once - as the first packet of
|
||||
a WAL file.
|
||||
|
||||
{wpt00WriteData int, b []byte, off int64}
|
||||
Write data (WriteAt(b, off)).
|
||||
|
||||
{wpt00Checkpoint int, sz int64}
|
||||
Checkpoint (Truncate(sz)).
|
||||
|
||||
This packet must be present only once - as the last packet of
|
||||
a WAL file.
|
||||
|
||||
*/
|
||||
|
||||
package lldb
|
||||
|
||||
//TODO optimize bitfiler/wal/2pc data above final size
|
2320
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/btree.go
generated
vendored
2320
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/btree.go
generated
vendored
File diff suppressed because it is too large
Load Diff
170
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/errors.go
generated
vendored
170
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/errors.go
generated
vendored
@ -1,170 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Some errors returned by this package.
|
||||
//
|
||||
// Note that this package can return more errors than declared here, for
|
||||
// example io.EOF from Filer.ReadAt().
|
||||
|
||||
package lldb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ErrDecodeScalars is possibly returned from DecodeScalars
|
||||
type ErrDecodeScalars struct {
|
||||
B []byte // Data being decoded
|
||||
I int // offending offset
|
||||
}
|
||||
|
||||
// Error implements the built in error type.
|
||||
func (e *ErrDecodeScalars) Error() string {
|
||||
return fmt.Sprintf("DecodeScalars: corrupted data @ %d/%d", e.I, len(e.B))
|
||||
}
|
||||
|
||||
// ErrINVAL reports invalid values passed as parameters, for example negative
|
||||
// offsets where only non-negative ones are allowed or read from the DB.
|
||||
type ErrINVAL struct {
|
||||
Src string
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
// Error implements the built in error type.
|
||||
func (e *ErrINVAL) Error() string {
|
||||
return fmt.Sprintf("%s: %+v", e.Src, e.Val)
|
||||
}
|
||||
|
||||
// ErrPERM is for example reported when a Filer is closed while BeginUpdate(s)
|
||||
// are not balanced with EndUpdate(s)/Rollback(s) or when EndUpdate or Rollback
|
||||
// is invoked which is not paired with a BeginUpdate.
|
||||
type ErrPERM struct {
|
||||
Src string
|
||||
}
|
||||
|
||||
// Error implements the built in error type.
|
||||
func (e *ErrPERM) Error() string {
|
||||
return fmt.Sprintf("%s: Operation not permitted", string(e.Src))
|
||||
}
|
||||
|
||||
// ErrTag represents an ErrILSEQ kind.
|
||||
type ErrType int
|
||||
|
||||
// ErrILSEQ types
|
||||
const (
|
||||
ErrOther ErrType = iota
|
||||
|
||||
ErrAdjacentFree // Adjacent free blocks (.Off and .Arg)
|
||||
ErrDecompress // Used compressed block: corrupted compression
|
||||
ErrExpFreeTag // Expected a free block tag, got .Arg
|
||||
ErrExpUsedTag // Expected a used block tag, got .Arg
|
||||
ErrFLT // Free block is invalid or referenced multiple times
|
||||
ErrFLTLoad // FLT truncated to .Off, need size >= .Arg
|
||||
ErrFLTSize // Free block size (.Arg) doesn't belong to its list min size: .Arg2
|
||||
ErrFileSize // File .Name size (.Arg) != 0 (mod 16)
|
||||
ErrFreeChaining // Free block, .prev.next doesn't point back to this block
|
||||
ErrFreeTailBlock // Last block is free
|
||||
ErrHead // Head of a free block list has non zero Prev (.Arg)
|
||||
ErrInvalidRelocTarget // Reloc doesn't target (.Arg) a short or long used block
|
||||
ErrInvalidWAL // Corrupted write ahead log. .Name: file name, .More: more
|
||||
ErrLongFreeBlkTooLong // Long free block spans beyond EOF, size .Arg
|
||||
ErrLongFreeBlkTooShort // Long free block must have at least 2 atoms, got only .Arg
|
||||
ErrLongFreeNextBeyondEOF // Long free block .Next (.Arg) spans beyond EOF
|
||||
ErrLongFreePrevBeyondEOF // Long free block .Prev (.Arg) spans beyond EOF
|
||||
ErrLongFreeTailTag // Expected a long free block tail tag, got .Arg
|
||||
ErrLostFreeBlock // Free block is not in any FLT list
|
||||
ErrNullReloc // Used reloc block with nil target
|
||||
ErrRelocBeyondEOF // Used reloc points (.Arg) beyond EOF
|
||||
ErrShortFreeTailTag // Expected a short free block tail tag, got .Arg
|
||||
ErrSmall // Request for a free block (.Arg) returned a too small one (.Arg2) at .Off
|
||||
ErrTailTag // Block at .Off has invalid tail CC (compression code) tag, got .Arg
|
||||
ErrUnexpReloc // Unexpected reloc block referred to from reloc block .Arg
|
||||
ErrVerifyPadding // Used block has nonzero padding
|
||||
ErrVerifyTailSize // Long free block size .Arg but tail size .Arg2
|
||||
ErrVerifyUsedSpan // Used block size (.Arg) spans beyond EOF
|
||||
)
|
||||
|
||||
// ErrILSEQ reports a corrupted file format. Details in fields according to Type.
|
||||
type ErrILSEQ struct {
|
||||
Type ErrType
|
||||
Off int64
|
||||
Arg int64
|
||||
Arg2 int64
|
||||
Arg3 int64
|
||||
Name string
|
||||
More interface{}
|
||||
}
|
||||
|
||||
// Error implements the built in error type.
|
||||
func (e *ErrILSEQ) Error() string {
|
||||
switch e.Type {
|
||||
case ErrAdjacentFree:
|
||||
return fmt.Sprintf("Adjacent free blocks at offset %#x and %#x", e.Off, e.Arg)
|
||||
case ErrDecompress:
|
||||
return fmt.Sprintf("Compressed block at offset %#x: Corrupted compressed content", e.Off)
|
||||
case ErrExpFreeTag:
|
||||
return fmt.Sprintf("Block at offset %#x: Expected a free block tag, got %#2x", e.Off, e.Arg)
|
||||
case ErrExpUsedTag:
|
||||
return fmt.Sprintf("Block at ofset %#x: Expected a used block tag, got %#2x", e.Off, e.Arg)
|
||||
case ErrFLT:
|
||||
return fmt.Sprintf("Free block at offset %#x is invalid or referenced multiple times", e.Off)
|
||||
case ErrFLTLoad:
|
||||
return fmt.Sprintf("FLT truncated to size %d, expected at least %d", e.Off, e.Arg)
|
||||
case ErrFLTSize:
|
||||
return fmt.Sprintf("Free block at offset %#x has size (%#x) should be at least (%#x)", e.Off, e.Arg, e.Arg2)
|
||||
case ErrFileSize:
|
||||
return fmt.Sprintf("File %q size (%#x) != 0 (mod 16)", e.Name, e.Arg)
|
||||
case ErrFreeChaining:
|
||||
return fmt.Sprintf("Free block at offset %#x: .prev.next doesn point back here.", e.Off)
|
||||
case ErrFreeTailBlock:
|
||||
return fmt.Sprintf("Free block at offset %#x: Cannot be last file block", e.Off)
|
||||
case ErrHead:
|
||||
return fmt.Sprintf("Block at offset %#x: Head of free block list has non zero .prev %#x", e.Off, e.Arg)
|
||||
case ErrInvalidRelocTarget:
|
||||
return fmt.Sprintf("Used reloc block at offset %#x: Target (%#x) is not a short or long used block", e.Off, e.Arg)
|
||||
case ErrInvalidWAL:
|
||||
return fmt.Sprintf("Corrupted write ahead log file: %q %v", e.Name, e.More)
|
||||
case ErrLongFreeBlkTooLong:
|
||||
return fmt.Sprintf("Long free block at offset %#x: Size (%#x) beyond EOF", e.Off, e.Arg)
|
||||
case ErrLongFreeBlkTooShort:
|
||||
return fmt.Sprintf("Long free block at offset %#x: Size (%#x) too small", e.Off, e.Arg)
|
||||
case ErrLongFreeNextBeyondEOF:
|
||||
return fmt.Sprintf("Long free block at offset %#x: Next (%#x) points beyond EOF", e.Off, e.Arg)
|
||||
case ErrLongFreePrevBeyondEOF:
|
||||
return fmt.Sprintf("Long free block at offset %#x: Prev (%#x) points beyond EOF", e.Off, e.Arg)
|
||||
case ErrLongFreeTailTag:
|
||||
return fmt.Sprintf("Block at offset %#x: Expected long free tail tag, got %#2x", e.Off, e.Arg)
|
||||
case ErrLostFreeBlock:
|
||||
return fmt.Sprintf("Free block at offset %#x: not in any FLT list", e.Off)
|
||||
case ErrNullReloc:
|
||||
return fmt.Sprintf("Used reloc block at offset %#x: Nil target", e.Off)
|
||||
case ErrRelocBeyondEOF:
|
||||
return fmt.Sprintf("Used reloc block at offset %#x: Link (%#x) points beyond EOF", e.Off, e.Arg)
|
||||
case ErrShortFreeTailTag:
|
||||
return fmt.Sprintf("Block at offset %#x: Expected short free tail tag, got %#2x", e.Off, e.Arg)
|
||||
case ErrSmall:
|
||||
return fmt.Sprintf("Request for of free block of size %d returned a too small (%d) one at offset %#x", e.Arg, e.Arg2, e.Off)
|
||||
case ErrTailTag:
|
||||
return fmt.Sprintf("Block at offset %#x: Invalid tail CC tag, got %#2x", e.Off, e.Arg)
|
||||
case ErrUnexpReloc:
|
||||
return fmt.Sprintf("Block at offset %#x: Unexpected reloc block. Referred to from reloc block at offset %#x", e.Off, e.Arg)
|
||||
case ErrVerifyPadding:
|
||||
return fmt.Sprintf("Used block at offset %#x: Nonzero padding", e.Off)
|
||||
case ErrVerifyTailSize:
|
||||
return fmt.Sprintf("Long free block at offset %#x: Size %#x, but tail size %#x", e.Off, e.Arg, e.Arg2)
|
||||
case ErrVerifyUsedSpan:
|
||||
return fmt.Sprintf("Used block at offset %#x: Size %#x spans beyond EOF", e.Off, e.Arg)
|
||||
}
|
||||
|
||||
more := ""
|
||||
if e.More != nil {
|
||||
more = fmt.Sprintf(", %v", e.More)
|
||||
}
|
||||
off := ""
|
||||
if e.Off != 0 {
|
||||
off = fmt.Sprintf(", off: %#x", e.Off)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Error%s%s", off, more)
|
||||
}
|
1981
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/falloc.go
generated
vendored
1981
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/falloc.go
generated
vendored
File diff suppressed because it is too large
Load Diff
192
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/filer.go
generated
vendored
192
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/filer.go
generated
vendored
@ -1,192 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// An abstraction of file like (persistent) storage with optional (abstracted)
|
||||
// support for structural integrity.
|
||||
|
||||
package lldb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cznic/mathutil"
|
||||
)
|
||||
|
||||
func doubleTrouble(first, second error) error {
|
||||
return fmt.Errorf("%q. Additionally, while attempting to recover (rollback): %q", first, second)
|
||||
}
|
||||
|
||||
// A Filer is a []byte-like model of a file or similar entity. It may
|
||||
// optionally implement support for structural transaction safety. In contrast
|
||||
// to a file stream, a Filer is not sequentially accessible. ReadAt and WriteAt
|
||||
// are always "addressed" by an offset and are assumed to perform atomically.
|
||||
// A Filer is not safe for concurrent access, it's designed for consumption by
|
||||
// the other objects in package, which should use a Filer from one goroutine
|
||||
// only or via a mutex. BeginUpdate, EndUpdate and Rollback must be either all
|
||||
// implemented by a Filer for structural integrity - or they should be all
|
||||
// no-ops; where/if that requirement is relaxed.
|
||||
//
|
||||
// If a Filer wraps another Filer implementation, it usually invokes the same
|
||||
// methods on the "inner" one, after some possible argument translations etc.
|
||||
// If a Filer implements the structural transactions handling methods
|
||||
// (BeginUpdate, EndUpdate and Rollback) as no-ops _and_ wraps another Filer:
|
||||
// it then still MUST invoke those methods on the inner Filer. This is
|
||||
// important for the case where a RollbackFiler exists somewhere down the
|
||||
// chain. It's also important for an Allocator - to know when it must
|
||||
// invalidate its FLT cache.
|
||||
type Filer interface {
|
||||
// BeginUpdate increments the "nesting" counter (initially zero). Every
|
||||
// call to BeginUpdate must be eventually "balanced" by exactly one of
|
||||
// EndUpdate or Rollback. Calls to BeginUpdate may nest.
|
||||
BeginUpdate() error
|
||||
|
||||
// Analogous to os.File.Close().
|
||||
Close() error
|
||||
|
||||
// EndUpdate decrements the "nesting" counter. If it's zero after that
|
||||
// then assume the "storage" has reached structural integrity (after a
|
||||
// batch of partial updates). If a Filer implements some support for
|
||||
// that (write ahead log, journal, etc.) then the appropriate actions
|
||||
// are to be taken for nesting == 0. Invocation of an unbalanced
|
||||
// EndUpdate is an error.
|
||||
EndUpdate() error
|
||||
|
||||
// Analogous to os.File.Name().
|
||||
Name() string
|
||||
|
||||
// PunchHole deallocates space inside a "file" in the byte range
|
||||
// starting at off and continuing for size bytes. The actual hole
|
||||
// created by PunchHole may be smaller than requested. The Filer size
|
||||
// (as reported by `Size()` does not change when hole punching, even
|
||||
// when punching the end of a file off. In contrast to the Linux
|
||||
// implementation of FALLOC_FL_PUNCH_HOLE in `fallocate`(2); a Filer is
|
||||
// free not only to ignore `PunchHole()` (implement it as a nop), but
|
||||
// additionally no guarantees about the content of the hole, when
|
||||
// eventually read back, are required, i.e. any data, not only zeros,
|
||||
// can be read from the "hole", including just anything what was left
|
||||
// there - with all of the possible security problems.
|
||||
PunchHole(off, size int64) error
|
||||
|
||||
// As os.File.ReadAt. Note: `off` is an absolute "file pointer"
|
||||
// address and cannot be negative even when a Filer is a InnerFiler.
|
||||
ReadAt(b []byte, off int64) (n int, err error)
|
||||
|
||||
// Rollback cancels and undoes the innermost pending update level.
|
||||
// Rollback decrements the "nesting" counter. If a Filer implements
|
||||
// some support for keeping structural integrity (write ahead log,
|
||||
// journal, etc.) then the appropriate actions are to be taken.
|
||||
// Invocation of an unbalanced Rollback is an error.
|
||||
Rollback() error
|
||||
|
||||
// Analogous to os.File.FileInfo().Size().
|
||||
Size() (int64, error)
|
||||
|
||||
// Analogous to os.Sync().
|
||||
Sync() (err error)
|
||||
|
||||
// Analogous to os.File.Truncate().
|
||||
Truncate(size int64) error
|
||||
|
||||
// Analogous to os.File.WriteAt(). Note: `off` is an absolute "file
|
||||
// pointer" address and cannot be negative even when a Filer is a
|
||||
// InnerFiler.
|
||||
WriteAt(b []byte, off int64) (n int, err error)
|
||||
}
|
||||
|
||||
var _ Filer = &InnerFiler{} // Ensure InnerFiler is a Filer.
|
||||
|
||||
// A InnerFiler is a Filer with added addressing/size translation.
|
||||
type InnerFiler struct {
|
||||
outer Filer
|
||||
off int64
|
||||
}
|
||||
|
||||
// NewInnerFiler returns a new InnerFiler wrapped by `outer` in a way which
|
||||
// adds `off` to every access.
|
||||
//
|
||||
// For example, considering:
|
||||
//
|
||||
// inner := NewInnerFiler(outer, 10)
|
||||
//
|
||||
// then
|
||||
//
|
||||
// inner.WriteAt([]byte{42}, 4)
|
||||
//
|
||||
// translates to
|
||||
//
|
||||
// outer.WriteAt([]byte{42}, 14)
|
||||
//
|
||||
// But an attempt to emulate
|
||||
//
|
||||
// outer.WriteAt([]byte{17}, 9)
|
||||
//
|
||||
// by
|
||||
//
|
||||
// inner.WriteAt([]byte{17}, -1)
|
||||
//
|
||||
// will fail as the `off` parameter can never be < 0. Also note that
|
||||
//
|
||||
// inner.Size() == outer.Size() - off,
|
||||
//
|
||||
// i.e. `inner` pretends no `outer` exists. Finally, after e.g.
|
||||
//
|
||||
// inner.Truncate(7)
|
||||
// outer.Size() == 17
|
||||
//
|
||||
// will be true.
|
||||
func NewInnerFiler(outer Filer, off int64) *InnerFiler { return &InnerFiler{outer, off} }
|
||||
|
||||
// BeginUpdate implements Filer.
|
||||
func (f *InnerFiler) BeginUpdate() error { return f.outer.BeginUpdate() }
|
||||
|
||||
// Close implements Filer.
|
||||
func (f *InnerFiler) Close() (err error) { return f.outer.Close() }
|
||||
|
||||
// EndUpdate implements Filer.
|
||||
func (f *InnerFiler) EndUpdate() error { return f.outer.EndUpdate() }
|
||||
|
||||
// Name implements Filer.
|
||||
func (f *InnerFiler) Name() string { return f.outer.Name() }
|
||||
|
||||
// PunchHole implements Filer. `off`, `size` must be >= 0.
|
||||
func (f *InnerFiler) PunchHole(off, size int64) error { return f.outer.PunchHole(f.off+off, size) }
|
||||
|
||||
// ReadAt implements Filer. `off` must be >= 0.
|
||||
func (f *InnerFiler) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
if off < 0 {
|
||||
return 0, &ErrINVAL{f.outer.Name() + ":ReadAt invalid off", off}
|
||||
}
|
||||
|
||||
return f.outer.ReadAt(b, f.off+off)
|
||||
}
|
||||
|
||||
// Rollback implements Filer.
|
||||
func (f *InnerFiler) Rollback() error { return f.outer.Rollback() }
|
||||
|
||||
// Size implements Filer.
|
||||
func (f *InnerFiler) Size() (int64, error) {
|
||||
sz, err := f.outer.Size()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return mathutil.MaxInt64(sz-f.off, 0), nil
|
||||
}
|
||||
|
||||
// Sync() implements Filer.
|
||||
func (f *InnerFiler) Sync() (err error) {
|
||||
return f.outer.Sync()
|
||||
}
|
||||
|
||||
// Truncate implements Filer.
|
||||
func (f *InnerFiler) Truncate(size int64) error { return f.outer.Truncate(size + f.off) }
|
||||
|
||||
// WriteAt implements Filer. `off` must be >= 0.
|
||||
func (f *InnerFiler) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
if off < 0 {
|
||||
return 0, &ErrINVAL{f.outer.Name() + ":WriteAt invalid off", off}
|
||||
}
|
||||
|
||||
return f.outer.WriteAt(b, f.off+off)
|
||||
}
|
812
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/gb.go
generated
vendored
812
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/gb.go
generated
vendored
@ -1,812 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Utilities to encode/decode and collate Go predeclared scalar types (and the
|
||||
// typeless nil and []byte). The encoding format is a variation of the one
|
||||
// used by the "encoding/gob" package.
|
||||
|
||||
package lldb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/cznic/mathutil"
|
||||
)
|
||||
|
||||
const (
|
||||
gbNull = iota // 0x00
|
||||
gbFalse // 0x01
|
||||
gbTrue // 0x02
|
||||
gbFloat0 // 0x03
|
||||
gbFloat1 // 0x04
|
||||
gbFloat2 // 0x05
|
||||
gbFloat3 // 0x06
|
||||
gbFloat4 // 0x07
|
||||
gbFloat5 // 0x08
|
||||
gbFloat6 // 0x09
|
||||
gbFloat7 // 0x0a
|
||||
gbFloat8 // 0x0b
|
||||
gbComplex0 // 0x0c
|
||||
gbComplex1 // 0x0d
|
||||
gbComplex2 // 0x0e
|
||||
gbComplex3 // 0x0f
|
||||
gbComplex4 // 0x10
|
||||
gbComplex5 // 0x11
|
||||
gbComplex6 // 0x12
|
||||
gbComplex7 // 0x13
|
||||
gbComplex8 // 0x14
|
||||
gbBytes00 // 0x15
|
||||
gbBytes01 // 0x16
|
||||
gbBytes02 // 0x17
|
||||
gbBytes03 // 0x18
|
||||
gbBytes04 // 0x19
|
||||
gbBytes05 // 0x1a
|
||||
gbBytes06 // 0x1b
|
||||
gbBytes07 // 0x1c
|
||||
gbBytes08 // 0x1d
|
||||
gbBytes09 // 0x1e
|
||||
gbBytes10 // 0x1f
|
||||
gbBytes11 // 0x20
|
||||
gbBytes12 // 0x21
|
||||
gbBytes13 // 0x22
|
||||
gbBytes14 // 0x23
|
||||
gbBytes15 // 0x24
|
||||
gbBytes16 // 0x25
|
||||
gbBytes17 // Ox26
|
||||
gbBytes1 // 0x27
|
||||
gbBytes2 // 0x28: Offset by one to allow 64kB sized []byte.
|
||||
gbString00 // 0x29
|
||||
gbString01 // 0x2a
|
||||
gbString02 // 0x2b
|
||||
gbString03 // 0x2c
|
||||
gbString04 // 0x2d
|
||||
gbString05 // 0x2e
|
||||
gbString06 // 0x2f
|
||||
gbString07 // 0x30
|
||||
gbString08 // 0x31
|
||||
gbString09 // 0x32
|
||||
gbString10 // 0x33
|
||||
gbString11 // 0x34
|
||||
gbString12 // 0x35
|
||||
gbString13 // 0x36
|
||||
gbString14 // 0x37
|
||||
gbString15 // 0x38
|
||||
gbString16 // 0x39
|
||||
gbString17 // 0x3a
|
||||
gbString1 // 0x3b
|
||||
gbString2 // 0x3c
|
||||
gbUintP1 // 0x3d
|
||||
gbUintP2 // 0x3e
|
||||
gbUintP3 // 0x3f
|
||||
gbUintP4 // 0x40
|
||||
gbUintP5 // 0x41
|
||||
gbUintP6 // 0x42
|
||||
gbUintP7 // 0x43
|
||||
gbUintP8 // 0x44
|
||||
gbIntM8 // 0x45
|
||||
gbIntM7 // 0x46
|
||||
gbIntM6 // 0x47
|
||||
gbIntM5 // 0x48
|
||||
gbIntM4 // 0x49
|
||||
gbIntM3 // 0x4a
|
||||
gbIntM2 // 0x4b
|
||||
gbIntM1 // 0x4c
|
||||
gbIntP1 // 0x4d
|
||||
gbIntP2 // 0x4e
|
||||
gbIntP3 // 0x4f
|
||||
gbIntP4 // 0x50
|
||||
gbIntP5 // 0x51
|
||||
gbIntP6 // 0x52
|
||||
gbIntP7 // 0x53
|
||||
gbIntP8 // 0x54
|
||||
gbInt0 // 0x55
|
||||
|
||||
gbIntMax = 255 - gbInt0 // 0xff == 170
|
||||
)
|
||||
|
||||
// EncodeScalars encodes a vector of predeclared scalar type values to a
|
||||
// []byte, making it suitable to store it as a "record" in a DB or to use it as
|
||||
// a key of a BTree.
|
||||
func EncodeScalars(scalars ...interface{}) (b []byte, err error) {
|
||||
for _, scalar := range scalars {
|
||||
switch x := scalar.(type) {
|
||||
default:
|
||||
return nil, &ErrINVAL{"EncodeScalars: unsupported type", fmt.Sprintf("%T in `%#v`", x, scalars)}
|
||||
|
||||
case nil:
|
||||
b = append(b, gbNull)
|
||||
|
||||
case bool:
|
||||
switch x {
|
||||
case false:
|
||||
b = append(b, gbFalse)
|
||||
case true:
|
||||
b = append(b, gbTrue)
|
||||
}
|
||||
|
||||
case float32:
|
||||
encFloat(float64(x), &b)
|
||||
case float64:
|
||||
encFloat(x, &b)
|
||||
|
||||
case complex64:
|
||||
encComplex(complex128(x), &b)
|
||||
case complex128:
|
||||
encComplex(x, &b)
|
||||
|
||||
case string:
|
||||
n := len(x)
|
||||
if n <= 17 {
|
||||
b = append(b, byte(gbString00+n))
|
||||
b = append(b, []byte(x)...)
|
||||
break
|
||||
}
|
||||
|
||||
if n > 65535 {
|
||||
return nil, fmt.Errorf("EncodeScalars: cannot encode string of length %d (limit 65536)", n)
|
||||
}
|
||||
|
||||
pref := byte(gbString1)
|
||||
if n > 255 {
|
||||
pref++
|
||||
}
|
||||
b = append(b, pref)
|
||||
encUint0(uint64(n), &b)
|
||||
b = append(b, []byte(x)...)
|
||||
|
||||
case int8:
|
||||
encInt(int64(x), &b)
|
||||
case int16:
|
||||
encInt(int64(x), &b)
|
||||
case int32:
|
||||
encInt(int64(x), &b)
|
||||
case int64:
|
||||
encInt(x, &b)
|
||||
case int:
|
||||
encInt(int64(x), &b)
|
||||
|
||||
case uint8:
|
||||
encUint(uint64(x), &b)
|
||||
case uint16:
|
||||
encUint(uint64(x), &b)
|
||||
case uint32:
|
||||
encUint(uint64(x), &b)
|
||||
case uint64:
|
||||
encUint(x, &b)
|
||||
case uint:
|
||||
encUint(uint64(x), &b)
|
||||
case []byte:
|
||||
n := len(x)
|
||||
if n <= 17 {
|
||||
b = append(b, byte(gbBytes00+n))
|
||||
b = append(b, []byte(x)...)
|
||||
break
|
||||
}
|
||||
|
||||
if n > 655356 {
|
||||
return nil, fmt.Errorf("EncodeScalars: cannot encode []byte of length %d (limit 65536)", n)
|
||||
}
|
||||
|
||||
pref := byte(gbBytes1)
|
||||
if n > 255 {
|
||||
pref++
|
||||
}
|
||||
b = append(b, pref)
|
||||
if n <= 255 {
|
||||
b = append(b, byte(n))
|
||||
} else {
|
||||
n--
|
||||
b = append(b, byte(n>>8), byte(n))
|
||||
}
|
||||
b = append(b, x...)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func encComplex(f complex128, b *[]byte) {
|
||||
encFloatPrefix(gbComplex0, real(f), b)
|
||||
encFloatPrefix(gbComplex0, imag(f), b)
|
||||
}
|
||||
|
||||
func encFloatPrefix(prefix byte, f float64, b *[]byte) {
|
||||
u := math.Float64bits(f)
|
||||
var n uint64
|
||||
for i := 0; i < 8; i++ {
|
||||
n <<= 8
|
||||
n |= u & 0xFF
|
||||
u >>= 8
|
||||
}
|
||||
bits := mathutil.BitLenUint64(n)
|
||||
if bits == 0 {
|
||||
*b = append(*b, prefix)
|
||||
return
|
||||
}
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
// . 1 1 1 1 1 1 1 1 2
|
||||
encUintPrefix(prefix+1+byte((bits-1)>>3), n, b)
|
||||
}
|
||||
|
||||
func encFloat(f float64, b *[]byte) {
|
||||
encFloatPrefix(gbFloat0, f, b)
|
||||
}
|
||||
|
||||
func encUint0(n uint64, b *[]byte) {
|
||||
switch {
|
||||
case n <= 0xff:
|
||||
*b = append(*b, byte(n))
|
||||
case n <= 0xffff:
|
||||
*b = append(*b, byte(n>>8), byte(n))
|
||||
case n <= 0xffffff:
|
||||
*b = append(*b, byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffff:
|
||||
*b = append(*b, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffffff:
|
||||
*b = append(*b, byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffffffff:
|
||||
*b = append(*b, byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffffffffff:
|
||||
*b = append(*b, byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= math.MaxUint64:
|
||||
*b = append(*b, byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
}
|
||||
}
|
||||
|
||||
func encUintPrefix(prefix byte, n uint64, b *[]byte) {
|
||||
*b = append(*b, prefix)
|
||||
encUint0(n, b)
|
||||
}
|
||||
|
||||
func encUint(n uint64, b *[]byte) {
|
||||
bits := mathutil.Max(1, mathutil.BitLenUint64(n))
|
||||
encUintPrefix(gbUintP1+byte((bits-1)>>3), n, b)
|
||||
}
|
||||
|
||||
func encInt(n int64, b *[]byte) {
|
||||
switch {
|
||||
case n < -0x100000000000000:
|
||||
*b = append(*b, byte(gbIntM8), byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n < -0x1000000000000:
|
||||
*b = append(*b, byte(gbIntM7), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n < -0x10000000000:
|
||||
*b = append(*b, byte(gbIntM6), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n < -0x100000000:
|
||||
*b = append(*b, byte(gbIntM5), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n < -0x1000000:
|
||||
*b = append(*b, byte(gbIntM4), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n < -0x10000:
|
||||
*b = append(*b, byte(gbIntM3), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n < -0x100:
|
||||
*b = append(*b, byte(gbIntM2), byte(n>>8), byte(n))
|
||||
case n < 0:
|
||||
*b = append(*b, byte(gbIntM1), byte(n))
|
||||
case n <= gbIntMax:
|
||||
*b = append(*b, byte(gbInt0+n))
|
||||
case n <= 0xff:
|
||||
*b = append(*b, gbIntP1, byte(n))
|
||||
case n <= 0xffff:
|
||||
*b = append(*b, gbIntP2, byte(n>>8), byte(n))
|
||||
case n <= 0xffffff:
|
||||
*b = append(*b, gbIntP3, byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffff:
|
||||
*b = append(*b, gbIntP4, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffffff:
|
||||
*b = append(*b, gbIntP5, byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffffffff:
|
||||
*b = append(*b, gbIntP6, byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0xffffffffffffff:
|
||||
*b = append(*b, gbIntP7, byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
case n <= 0x7fffffffffffffff:
|
||||
*b = append(*b, gbIntP8, byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||
}
|
||||
}
|
||||
|
||||
func decodeFloat(b []byte) float64 {
|
||||
var u uint64
|
||||
for i, v := range b {
|
||||
u |= uint64(v) << uint((i+8-len(b))*8)
|
||||
}
|
||||
return math.Float64frombits(u)
|
||||
}
|
||||
|
||||
// DecodeScalars decodes a []byte produced by EncodeScalars.
|
||||
func DecodeScalars(b []byte) (scalars []interface{}, err error) {
|
||||
b0 := b
|
||||
for len(b) != 0 {
|
||||
switch tag := b[0]; tag {
|
||||
//default:
|
||||
//return nil, fmt.Errorf("tag %d(%#x) not supported", b[0], b[0])
|
||||
case gbNull:
|
||||
scalars = append(scalars, nil)
|
||||
b = b[1:]
|
||||
case gbFalse:
|
||||
scalars = append(scalars, false)
|
||||
b = b[1:]
|
||||
case gbTrue:
|
||||
scalars = append(scalars, true)
|
||||
b = b[1:]
|
||||
case gbFloat0:
|
||||
scalars = append(scalars, 0.0)
|
||||
b = b[1:]
|
||||
case gbFloat1, gbFloat2, gbFloat3, gbFloat4, gbFloat5, gbFloat6, gbFloat7, gbFloat8:
|
||||
n := 1 + int(tag) - gbFloat0
|
||||
if len(b) < n-1 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, decodeFloat(b[1:n]))
|
||||
b = b[n:]
|
||||
case gbComplex0, gbComplex1, gbComplex2, gbComplex3, gbComplex4, gbComplex5, gbComplex6, gbComplex7, gbComplex8:
|
||||
n := 1 + int(tag) - gbComplex0
|
||||
if len(b) < n-1 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
re := decodeFloat(b[1:n])
|
||||
b = b[n:]
|
||||
|
||||
if len(b) == 0 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
tag = b[0]
|
||||
if tag < gbComplex0 || tag > gbComplex8 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
n = 1 + int(tag) - gbComplex0
|
||||
if len(b) < n-1 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, complex(re, decodeFloat(b[1:n])))
|
||||
b = b[n:]
|
||||
case gbBytes00, gbBytes01, gbBytes02, gbBytes03, gbBytes04,
|
||||
gbBytes05, gbBytes06, gbBytes07, gbBytes08, gbBytes09,
|
||||
gbBytes10, gbBytes11, gbBytes12, gbBytes13, gbBytes14,
|
||||
gbBytes15, gbBytes16, gbBytes17:
|
||||
n := int(tag - gbBytes00)
|
||||
if len(b) < n+1 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, append([]byte(nil), b[1:n+1]...))
|
||||
b = b[n+1:]
|
||||
case gbBytes1:
|
||||
if len(b) < 2 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
n := int(b[1])
|
||||
b = b[2:]
|
||||
if len(b) < n {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, append([]byte(nil), b[:n]...))
|
||||
b = b[n:]
|
||||
case gbBytes2:
|
||||
if len(b) < 3 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
n := int(b[1])<<8 | int(b[2]) + 1
|
||||
b = b[3:]
|
||||
if len(b) < n {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, append([]byte(nil), b[:n]...))
|
||||
b = b[n:]
|
||||
case gbString00, gbString01, gbString02, gbString03, gbString04,
|
||||
gbString05, gbString06, gbString07, gbString08, gbString09,
|
||||
gbString10, gbString11, gbString12, gbString13, gbString14,
|
||||
gbString15, gbString16, gbString17:
|
||||
n := int(tag - gbString00)
|
||||
if len(b) < n+1 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, string(b[1:n+1]))
|
||||
b = b[n+1:]
|
||||
case gbString1:
|
||||
if len(b) < 2 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
n := int(b[1])
|
||||
b = b[2:]
|
||||
if len(b) < n {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, string(b[:n]))
|
||||
b = b[n:]
|
||||
case gbString2:
|
||||
if len(b) < 3 {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
n := int(b[1])<<8 | int(b[2])
|
||||
b = b[3:]
|
||||
if len(b) < n {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
scalars = append(scalars, string(b[:n]))
|
||||
b = b[n:]
|
||||
case gbUintP1, gbUintP2, gbUintP3, gbUintP4, gbUintP5, gbUintP6, gbUintP7, gbUintP8:
|
||||
b = b[1:]
|
||||
n := 1 + int(tag) - gbUintP1
|
||||
if len(b) < n {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
var u uint64
|
||||
for _, v := range b[:n] {
|
||||
u = u<<8 | uint64(v)
|
||||
}
|
||||
scalars = append(scalars, u)
|
||||
b = b[n:]
|
||||
case gbIntM8, gbIntM7, gbIntM6, gbIntM5, gbIntM4, gbIntM3, gbIntM2, gbIntM1:
|
||||
b = b[1:]
|
||||
n := 8 - (int(tag) - gbIntM8)
|
||||
if len(b) < n {
|
||||
goto corrupted
|
||||
}
|
||||
u := uint64(math.MaxUint64)
|
||||
for _, v := range b[:n] {
|
||||
u = u<<8 | uint64(v)
|
||||
}
|
||||
scalars = append(scalars, int64(u))
|
||||
b = b[n:]
|
||||
case gbIntP1, gbIntP2, gbIntP3, gbIntP4, gbIntP5, gbIntP6, gbIntP7, gbIntP8:
|
||||
b = b[1:]
|
||||
n := 1 + int(tag) - gbIntP1
|
||||
if len(b) < n {
|
||||
goto corrupted
|
||||
}
|
||||
|
||||
i := int64(0)
|
||||
for _, v := range b[:n] {
|
||||
i = i<<8 | int64(v)
|
||||
}
|
||||
scalars = append(scalars, i)
|
||||
b = b[n:]
|
||||
default:
|
||||
scalars = append(scalars, int64(b[0])-gbInt0)
|
||||
b = b[1:]
|
||||
}
|
||||
}
|
||||
return append([]interface{}(nil), scalars...), nil
|
||||
|
||||
corrupted:
|
||||
return nil, &ErrDecodeScalars{append([]byte(nil), b0...), len(b0) - len(b)}
|
||||
}
|
||||
|
||||
func collateComplex(x, y complex128) int {
|
||||
switch rx, ry := real(x), real(y); {
|
||||
case rx < ry:
|
||||
return -1
|
||||
case rx == ry:
|
||||
switch ix, iy := imag(x), imag(y); {
|
||||
case ix < iy:
|
||||
return -1
|
||||
case ix == iy:
|
||||
return 0
|
||||
case ix > iy:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
//case rx > ry:
|
||||
return 1
|
||||
}
|
||||
|
||||
func collateFloat(x, y float64) int {
|
||||
switch {
|
||||
case x < y:
|
||||
return -1
|
||||
case x == y:
|
||||
return 0
|
||||
}
|
||||
//case x > y:
|
||||
return 1
|
||||
}
|
||||
|
||||
func collateInt(x, y int64) int {
|
||||
switch {
|
||||
case x < y:
|
||||
return -1
|
||||
case x == y:
|
||||
return 0
|
||||
}
|
||||
//case x > y:
|
||||
return 1
|
||||
}
|
||||
|
||||
func collateUint(x, y uint64) int {
|
||||
switch {
|
||||
case x < y:
|
||||
return -1
|
||||
case x == y:
|
||||
return 0
|
||||
}
|
||||
//case x > y:
|
||||
return 1
|
||||
}
|
||||
|
||||
func collateIntUint(x int64, y uint64) int {
|
||||
if y > math.MaxInt64 {
|
||||
return -1
|
||||
}
|
||||
|
||||
return collateInt(x, int64(y))
|
||||
}
|
||||
|
||||
func collateUintInt(x uint64, y int64) int {
|
||||
return -collateIntUint(y, x)
|
||||
}
|
||||
|
||||
func collateType(i interface{}) (r interface{}, err error) {
|
||||
switch x := i.(type) {
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid collate type %T", x)
|
||||
case nil:
|
||||
return i, nil
|
||||
case bool:
|
||||
return i, nil
|
||||
case int8:
|
||||
return int64(x), nil
|
||||
case int16:
|
||||
return int64(x), nil
|
||||
case int32:
|
||||
return int64(x), nil
|
||||
case int64:
|
||||
return i, nil
|
||||
case int:
|
||||
return int64(x), nil
|
||||
case uint8:
|
||||
return uint64(x), nil
|
||||
case uint16:
|
||||
return uint64(x), nil
|
||||
case uint32:
|
||||
return uint64(x), nil
|
||||
case uint64:
|
||||
return i, nil
|
||||
case uint:
|
||||
return uint64(x), nil
|
||||
case float32:
|
||||
return float64(x), nil
|
||||
case float64:
|
||||
return i, nil
|
||||
case complex64:
|
||||
return complex128(x), nil
|
||||
case complex128:
|
||||
return i, nil
|
||||
case []byte:
|
||||
return i, nil
|
||||
case string:
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Collate collates two arrays of Go predeclared scalar types (and the typeless
|
||||
// nil or []byte). If any other type appears in x or y, Collate will return a
|
||||
// non nil error. String items are collated using strCollate or lexically
|
||||
// byte-wise (as when using Go comparison operators) when strCollate is nil.
|
||||
// []byte items are collated using bytes.Compare.
|
||||
//
|
||||
// Collate returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
//
|
||||
// The same value as defined above must be returned from strCollate.
|
||||
//
|
||||
// The "outer" ordering is: nil, bool, number, []byte, string. IOW, nil is
|
||||
// "smaller" than anything else except other nil, numbers collate before
|
||||
// []byte, []byte collate before strings, etc.
|
||||
//
|
||||
// Integers and real numbers collate as expected in math. However, complex
|
||||
// numbers are not ordered in Go. Here the ordering is defined: Complex numbers
|
||||
// are in comparison considered first only by their real part. Iff the result
|
||||
// is equality then the imaginary part is used to determine the ordering. In
|
||||
// this "second order" comparing, integers and real numbers are considered as
|
||||
// complex numbers with a zero imaginary part.
|
||||
func Collate(x, y []interface{}, strCollate func(string, string) int) (r int, err error) {
|
||||
nx, ny := len(x), len(y)
|
||||
|
||||
switch {
|
||||
case nx == 0 && ny != 0:
|
||||
return -1, nil
|
||||
case nx == 0 && ny == 0:
|
||||
return 0, nil
|
||||
case nx != 0 && ny == 0:
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
r = 1
|
||||
if nx > ny {
|
||||
x, y, r = y, x, -r
|
||||
}
|
||||
|
||||
var c int
|
||||
for i, xi0 := range x {
|
||||
yi0 := y[i]
|
||||
xi, err := collateType(xi0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
yi, err := collateType(yi0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch x := xi.(type) {
|
||||
default:
|
||||
panic(fmt.Errorf("internal error: %T", x))
|
||||
|
||||
case nil:
|
||||
switch yi.(type) {
|
||||
case nil:
|
||||
// nop
|
||||
default:
|
||||
return -r, nil
|
||||
}
|
||||
|
||||
case bool:
|
||||
switch y := yi.(type) {
|
||||
case nil:
|
||||
return r, nil
|
||||
case bool:
|
||||
switch {
|
||||
case !x && y:
|
||||
return -r, nil
|
||||
case x == y:
|
||||
// nop
|
||||
case x && !y:
|
||||
return r, nil
|
||||
}
|
||||
default:
|
||||
return -r, nil
|
||||
}
|
||||
|
||||
case int64:
|
||||
switch y := yi.(type) {
|
||||
case nil, bool:
|
||||
return r, nil
|
||||
case int64:
|
||||
c = collateInt(x, y)
|
||||
case uint64:
|
||||
c = collateIntUint(x, y)
|
||||
case float64:
|
||||
c = collateFloat(float64(x), y)
|
||||
case complex128:
|
||||
c = collateComplex(complex(float64(x), 0), y)
|
||||
case []byte:
|
||||
return -r, nil
|
||||
case string:
|
||||
return -r, nil
|
||||
}
|
||||
|
||||
if c != 0 {
|
||||
return c * r, nil
|
||||
}
|
||||
|
||||
case uint64:
|
||||
switch y := yi.(type) {
|
||||
case nil, bool:
|
||||
return r, nil
|
||||
case int64:
|
||||
c = collateUintInt(x, y)
|
||||
case uint64:
|
||||
c = collateUint(x, y)
|
||||
case float64:
|
||||
c = collateFloat(float64(x), y)
|
||||
case complex128:
|
||||
c = collateComplex(complex(float64(x), 0), y)
|
||||
case []byte:
|
||||
return -r, nil
|
||||
case string:
|
||||
return -r, nil
|
||||
}
|
||||
|
||||
if c != 0 {
|
||||
return c * r, nil
|
||||
}
|
||||
|
||||
case float64:
|
||||
switch y := yi.(type) {
|
||||
case nil, bool:
|
||||
return r, nil
|
||||
case int64:
|
||||
c = collateFloat(x, float64(y))
|
||||
case uint64:
|
||||
c = collateFloat(x, float64(y))
|
||||
case float64:
|
||||
c = collateFloat(x, y)
|
||||
case complex128:
|
||||
c = collateComplex(complex(x, 0), y)
|
||||
case []byte:
|
||||
return -r, nil
|
||||
case string:
|
||||
return -r, nil
|
||||
}
|
||||
|
||||
if c != 0 {
|
||||
return c * r, nil
|
||||
}
|
||||
|
||||
case complex128:
|
||||
switch y := yi.(type) {
|
||||
case nil, bool:
|
||||
return r, nil
|
||||
case int64:
|
||||
c = collateComplex(x, complex(float64(y), 0))
|
||||
case uint64:
|
||||
c = collateComplex(x, complex(float64(y), 0))
|
||||
case float64:
|
||||
c = collateComplex(x, complex(y, 0))
|
||||
case complex128:
|
||||
c = collateComplex(x, y)
|
||||
case []byte:
|
||||
return -r, nil
|
||||
case string:
|
||||
return -r, nil
|
||||
}
|
||||
|
||||
if c != 0 {
|
||||
return c * r, nil
|
||||
}
|
||||
|
||||
case []byte:
|
||||
switch y := yi.(type) {
|
||||
case nil, bool, int64, uint64, float64, complex128:
|
||||
return r, nil
|
||||
case []byte:
|
||||
c = bytes.Compare(x, y)
|
||||
case string:
|
||||
return -r, nil
|
||||
}
|
||||
|
||||
if c != 0 {
|
||||
return c * r, nil
|
||||
}
|
||||
|
||||
case string:
|
||||
switch y := yi.(type) {
|
||||
case nil, bool, int64, uint64, float64, complex128:
|
||||
return r, nil
|
||||
case []byte:
|
||||
return r, nil
|
||||
case string:
|
||||
switch {
|
||||
case strCollate != nil:
|
||||
c = strCollate(x, y)
|
||||
case x < y:
|
||||
return -r, nil
|
||||
case x == y:
|
||||
c = 0
|
||||
case x > y:
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
|
||||
if c != 0 {
|
||||
return c * r, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nx == ny {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return -r, nil
|
||||
}
|
155
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/lldb.go
generated
vendored
155
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/lldb.go
generated
vendored
@ -1,155 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package lldb (WIP) implements a low level database engine. The database
|
||||
// model used could be considered a specific implementation of some small(est)
|
||||
// intersection of models listed in [1]. As a settled term is lacking, it'll be
|
||||
// called here a 'Virtual memory model' (VMM).
|
||||
//
|
||||
// Experimental release notes
|
||||
//
|
||||
// This is an experimental release. Don't open a DB from two applications or
|
||||
// two instances of an application - it will get corrupted (no file locking is
|
||||
// implemented and this task is delegated to lldb's clients).
|
||||
//
|
||||
// WARNING: THE LLDB API IS SUBJECT TO CHANGE.
|
||||
//
|
||||
// Filers
|
||||
//
|
||||
// A Filer is an abstraction of storage. A Filer may be a part of some process'
|
||||
// virtual address space, an OS file, a networked, remote file etc. Persistence
|
||||
// of the storage is optional, opaque to VMM and it is specific to a concrete
|
||||
// Filer implementation.
|
||||
//
|
||||
// Space management
|
||||
//
|
||||
// Mechanism to allocate, reallocate (resize), deallocate (and later reclaim
|
||||
// the unused) contiguous parts of a Filer, called blocks. Blocks are
|
||||
// identified and referred to by a handle, an int64.
|
||||
//
|
||||
// BTrees
|
||||
//
|
||||
// In addition to the VMM like services, lldb provides volatile and
|
||||
// non-volatile BTrees. Keys and values of a BTree are limited in size to 64kB
|
||||
// each (a bit more actually). Support for larger keys/values, if desired, can
|
||||
// be built atop a BTree to certain limits.
|
||||
//
|
||||
// Handles vs pointers
|
||||
//
|
||||
// A handle is the abstracted storage counterpart of a memory address. There
|
||||
// is one fundamental difference, though. Resizing a block never results in a
|
||||
// change to the handle which refers to the resized block, so a handle is more
|
||||
// akin to an unique numeric id/key. Yet it shares one property of pointers -
|
||||
// handles can be associated again with blocks after the original handle block
|
||||
// was deallocated. In other words, a handle uniqueness domain is the state of
|
||||
// the database and is not something comparable to e.g. an ever growing
|
||||
// numbering sequence.
|
||||
//
|
||||
// Also, as with memory pointers, dangling handles can be created and blocks
|
||||
// overwritten when such handles are used. Using a zero handle to refer to a
|
||||
// block will not panic; however, the resulting error is effectively the same
|
||||
// exceptional situation as dereferencing a nil pointer.
|
||||
//
|
||||
// Blocks
|
||||
//
|
||||
// Allocated/used blocks, are limited in size to only a little bit more than
|
||||
// 64kB. Bigger semantic entities/structures must be built in lldb's client
|
||||
// code. The content of a block has no semantics attached, it's only a fully
|
||||
// opaque `[]byte`.
|
||||
//
|
||||
// Scalars
|
||||
//
|
||||
// Use of "scalars" applies to EncodeScalars, DecodeScalars and Collate. Those
|
||||
// first two "to bytes" and "from bytes" functions are suggested for handling
|
||||
// multi-valued Allocator content items and/or keys/values of BTrees (using
|
||||
// Collate for keys). Types called "scalar" are:
|
||||
//
|
||||
// nil (the typeless one)
|
||||
// bool
|
||||
// all integral types: [u]int8, [u]int16, [u]int32, [u]int, [u]int64
|
||||
// all floating point types: float32, float64
|
||||
// all complex types: complex64, complex128
|
||||
// []byte (64kB max)
|
||||
// string (64kb max)
|
||||
//
|
||||
// Specific implementations
|
||||
//
|
||||
// Included are concrete implementations of some of the VMM interfaces included
|
||||
// to ease serving simple client code or for testing and possibly as an
|
||||
// example. More details in the documentation of such implementations.
|
||||
//
|
||||
// [1]: http://en.wikipedia.org/wiki/Database_model
|
||||
package lldb
|
||||
|
||||
const (
|
||||
fltSz = 0x70 // size of the FLT
|
||||
maxShort = 251
|
||||
maxRq = 65787
|
||||
maxFLTRq = 4112
|
||||
maxHandle = 1<<56 - 1
|
||||
atomLen = 16
|
||||
tagUsedLong = 0xfc
|
||||
tagUsedRelocated = 0xfd
|
||||
tagFreeShort = 0xfe
|
||||
tagFreeLong = 0xff
|
||||
tagNotCompressed = 0
|
||||
tagCompressed = 1
|
||||
)
|
||||
|
||||
// Content size n -> blocksize in atoms.
|
||||
func n2atoms(n int) int {
|
||||
if n > maxShort {
|
||||
n += 2
|
||||
}
|
||||
return (n+1)/16 + 1
|
||||
}
|
||||
|
||||
// Content size n -> number of padding zeros.
|
||||
func n2padding(n int) int {
|
||||
if n > maxShort {
|
||||
n += 2
|
||||
}
|
||||
return 15 - (n+1)&15
|
||||
}
|
||||
|
||||
// Handle <-> offset
|
||||
func h2off(h int64) int64 { return (h + 6) * 16 }
|
||||
func off2h(off int64) int64 { return off/16 - 6 }
|
||||
|
||||
// Get a 7B int64 from b
|
||||
func b2h(b []byte) (h int64) {
|
||||
for _, v := range b[:7] {
|
||||
h = h<<8 | int64(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Put a 7B int64 into b
|
||||
func h2b(b []byte, h int64) []byte {
|
||||
for i := range b[:7] {
|
||||
b[i], h = byte(h>>48), h<<8
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Content length N (must be in [252, 65787]) to long used block M field.
|
||||
func n2m(n int) (m int) {
|
||||
return n % 0x10000
|
||||
}
|
||||
|
||||
// Long used block M (must be in [0, 65535]) field to content length N.
|
||||
func m2n(m int) (n int) {
|
||||
if m <= maxShort {
|
||||
m += 0x10000
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func bpack(a []byte) []byte {
|
||||
if cap(a) > len(a) {
|
||||
return append([]byte(nil), a...)
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
344
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/memfiler.go
generated
vendored
344
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/memfiler.go
generated
vendored
@ -1,344 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// A memory-only implementation of Filer.
|
||||
|
||||
/*
|
||||
|
||||
pgBits: 8
|
||||
BenchmarkMemFilerWrSeq 100000 19430 ns/op 1646.93 MB/s
|
||||
BenchmarkMemFilerRdSeq 100000 17390 ns/op 1840.13 MB/s
|
||||
BenchmarkMemFilerWrRand 1000000 1903 ns/op 133.94 MB/s
|
||||
BenchmarkMemFilerRdRand 1000000 1153 ns/op 221.16 MB/s
|
||||
|
||||
pgBits: 9
|
||||
BenchmarkMemFilerWrSeq 100000 16195 ns/op 1975.80 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 13011 ns/op 2459.39 MB/s
|
||||
BenchmarkMemFilerWrRand 1000000 2248 ns/op 227.28 MB/s
|
||||
BenchmarkMemFilerRdRand 1000000 1177 ns/op 433.94 MB/s
|
||||
|
||||
pgBits: 10
|
||||
BenchmarkMemFilerWrSeq 100000 16169 ns/op 1979.04 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 12673 ns/op 2524.91 MB/s
|
||||
BenchmarkMemFilerWrRand 1000000 5550 ns/op 184.30 MB/s
|
||||
BenchmarkMemFilerRdRand 1000000 1699 ns/op 601.79 MB/s
|
||||
|
||||
pgBits: 11
|
||||
BenchmarkMemFilerWrSeq 100000 13449 ns/op 2379.31 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 12058 ns/op 2653.80 MB/s
|
||||
BenchmarkMemFilerWrRand 500000 4335 ns/op 471.47 MB/s
|
||||
BenchmarkMemFilerRdRand 1000000 2843 ns/op 719.47 MB/s
|
||||
|
||||
pgBits: 12
|
||||
BenchmarkMemFilerWrSeq 200000 11976 ns/op 2672.00 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 12255 ns/op 2611.06 MB/s
|
||||
BenchmarkMemFilerWrRand 200000 8058 ns/op 507.14 MB/s
|
||||
BenchmarkMemFilerRdRand 500000 4365 ns/op 936.15 MB/s
|
||||
|
||||
pgBits: 13
|
||||
BenchmarkMemFilerWrSeq 200000 10852 ns/op 2948.69 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 11561 ns/op 2767.77 MB/s
|
||||
BenchmarkMemFilerWrRand 200000 9748 ns/op 840.15 MB/s
|
||||
BenchmarkMemFilerRdRand 500000 7236 ns/op 1131.59 MB/s
|
||||
|
||||
pgBits: 14
|
||||
BenchmarkMemFilerWrSeq 200000 10328 ns/op 3098.12 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 11292 ns/op 2833.66 MB/s
|
||||
BenchmarkMemFilerWrRand 100000 16768 ns/op 978.75 MB/s
|
||||
BenchmarkMemFilerRdRand 200000 13033 ns/op 1258.43 MB/s
|
||||
|
||||
pgBits: 15
|
||||
BenchmarkMemFilerWrSeq 200000 10309 ns/op 3103.93 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 11126 ns/op 2876.12 MB/s
|
||||
BenchmarkMemFilerWrRand 50000 31985 ns/op 1021.74 MB/s
|
||||
BenchmarkMemFilerRdRand 100000 25217 ns/op 1297.65 MB/s
|
||||
|
||||
pgBits: 16
|
||||
BenchmarkMemFilerWrSeq 200000 10324 ns/op 3099.45 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 11201 ns/op 2856.80 MB/s
|
||||
BenchmarkMemFilerWrRand 20000 55226 ns/op 1184.76 MB/s
|
||||
BenchmarkMemFilerRdRand 50000 48316 ns/op 1355.16 MB/s
|
||||
|
||||
pgBits: 17
|
||||
BenchmarkMemFilerWrSeq 200000 10377 ns/op 3083.53 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 11018 ns/op 2904.18 MB/s
|
||||
BenchmarkMemFilerWrRand 10000 143425 ns/op 913.12 MB/s
|
||||
BenchmarkMemFilerRdRand 20000 95267 ns/op 1376.99 MB/s
|
||||
|
||||
pgBits: 18
|
||||
BenchmarkMemFilerWrSeq 200000 10312 ns/op 3102.96 MB/s
|
||||
BenchmarkMemFilerRdSeq 200000 11069 ns/op 2890.84 MB/s
|
||||
BenchmarkMemFilerWrRand 5000 280910 ns/op 934.14 MB/s
|
||||
BenchmarkMemFilerRdRand 10000 188500 ns/op 1388.17 MB/s
|
||||
|
||||
*/
|
||||
|
||||
package lldb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/cznic/fileutil"
|
||||
"github.com/cznic/mathutil"
|
||||
)
|
||||
|
||||
const (
|
||||
pgBits = 16
|
||||
pgSize = 1 << pgBits
|
||||
pgMask = pgSize - 1
|
||||
)
|
||||
|
||||
var _ Filer = &MemFiler{} // Ensure MemFiler is a Filer.
|
||||
|
||||
type memFilerMap map[int64]*[pgSize]byte
|
||||
|
||||
// MemFiler is a memory backed Filer. It implements BeginUpdate, EndUpdate and
|
||||
// Rollback as no-ops. MemFiler is not automatically persistent, but it has
|
||||
// ReadFrom and WriteTo methods.
|
||||
type MemFiler struct {
|
||||
m memFilerMap
|
||||
nest int
|
||||
size int64
|
||||
}
|
||||
|
||||
// NewMemFiler returns a new MemFiler.
|
||||
func NewMemFiler() *MemFiler {
|
||||
return &MemFiler{m: memFilerMap{}}
|
||||
}
|
||||
|
||||
// BeginUpdate implements Filer.
|
||||
func (f *MemFiler) BeginUpdate() error {
|
||||
f.nest++
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements Filer.
|
||||
func (f *MemFiler) Close() (err error) {
|
||||
if f.nest != 0 {
|
||||
return &ErrPERM{(f.Name() + ":Close")}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// EndUpdate implements Filer.
|
||||
func (f *MemFiler) EndUpdate() (err error) {
|
||||
if f.nest == 0 {
|
||||
return &ErrPERM{(f.Name() + ": EndUpdate")}
|
||||
}
|
||||
|
||||
f.nest--
|
||||
return
|
||||
}
|
||||
|
||||
// Name implements Filer.
|
||||
func (f *MemFiler) Name() string {
|
||||
return fmt.Sprintf("%p.memfiler", f)
|
||||
}
|
||||
|
||||
// PunchHole implements Filer.
|
||||
func (f *MemFiler) PunchHole(off, size int64) (err error) {
|
||||
if off < 0 {
|
||||
return &ErrINVAL{f.Name() + ": PunchHole off", off}
|
||||
}
|
||||
|
||||
if size < 0 || off+size > f.size {
|
||||
return &ErrINVAL{f.Name() + ": PunchHole size", size}
|
||||
}
|
||||
|
||||
first := off >> pgBits
|
||||
if off&pgMask != 0 {
|
||||
first++
|
||||
}
|
||||
off += size - 1
|
||||
last := off >> pgBits
|
||||
if off&pgMask != 0 {
|
||||
last--
|
||||
}
|
||||
if limit := f.size >> pgBits; last > limit {
|
||||
last = limit
|
||||
}
|
||||
for pg := first; pg <= last; pg++ {
|
||||
delete(f.m, pg)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var zeroPage [pgSize]byte
|
||||
|
||||
// ReadAt implements Filer.
|
||||
func (f *MemFiler) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
avail := f.size - off
|
||||
pgI := off >> pgBits
|
||||
pgO := int(off & pgMask)
|
||||
rem := len(b)
|
||||
if int64(rem) >= avail {
|
||||
rem = int(avail)
|
||||
err = io.EOF
|
||||
}
|
||||
for rem != 0 && avail > 0 {
|
||||
pg := f.m[pgI]
|
||||
if pg == nil {
|
||||
pg = &zeroPage
|
||||
}
|
||||
nc := copy(b[:mathutil.Min(rem, pgSize)], pg[pgO:])
|
||||
pgI++
|
||||
pgO = 0
|
||||
rem -= nc
|
||||
n += nc
|
||||
b = b[nc:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ReadFrom is a helper to populate MemFiler's content from r. 'n' reports the
|
||||
// number of bytes read from 'r'.
|
||||
func (f *MemFiler) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if err = f.Truncate(0); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
b [pgSize]byte
|
||||
rn int
|
||||
off int64
|
||||
)
|
||||
|
||||
var rerr error
|
||||
for rerr == nil {
|
||||
if rn, rerr = r.Read(b[:]); rn != 0 {
|
||||
f.WriteAt(b[:rn], off)
|
||||
off += int64(rn)
|
||||
n += int64(rn)
|
||||
}
|
||||
}
|
||||
if !fileutil.IsEOF(rerr) {
|
||||
err = rerr
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Rollback implements Filer.
|
||||
func (f *MemFiler) Rollback() (err error) { return }
|
||||
|
||||
// Size implements Filer.
|
||||
func (f *MemFiler) Size() (int64, error) {
|
||||
return f.size, nil
|
||||
}
|
||||
|
||||
// Sync implements Filer.
|
||||
func (f *MemFiler) Sync() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Truncate implements Filer.
|
||||
func (f *MemFiler) Truncate(size int64) (err error) {
|
||||
switch {
|
||||
case size < 0:
|
||||
return &ErrINVAL{"Truncate size", size}
|
||||
case size == 0:
|
||||
f.m = memFilerMap{}
|
||||
f.size = 0
|
||||
return
|
||||
}
|
||||
|
||||
first := size >> pgBits
|
||||
if size&pgMask != 0 {
|
||||
first++
|
||||
}
|
||||
last := f.size >> pgBits
|
||||
if f.size&pgMask != 0 {
|
||||
last++
|
||||
}
|
||||
for ; first < last; first++ {
|
||||
delete(f.m, first)
|
||||
}
|
||||
|
||||
f.size = size
|
||||
return
|
||||
}
|
||||
|
||||
// WriteAt implements Filer.
|
||||
func (f *MemFiler) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
pgI := off >> pgBits
|
||||
pgO := int(off & pgMask)
|
||||
n = len(b)
|
||||
rem := n
|
||||
var nc int
|
||||
for rem != 0 {
|
||||
if pgO == 0 && rem >= pgSize && bytes.Equal(b[:pgSize], zeroPage[:]) {
|
||||
delete(f.m, pgI)
|
||||
nc = pgSize
|
||||
} else {
|
||||
pg := f.m[pgI]
|
||||
if pg == nil {
|
||||
pg = new([pgSize]byte)
|
||||
f.m[pgI] = pg
|
||||
}
|
||||
nc = copy((*pg)[pgO:], b)
|
||||
}
|
||||
pgI++
|
||||
pgO = 0
|
||||
rem -= nc
|
||||
b = b[nc:]
|
||||
}
|
||||
f.size = mathutil.MaxInt64(f.size, off+int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
// WriteTo is a helper to copy/persist MemFiler's content to w. If w is also
|
||||
// an io.WriterAt then WriteTo may attempt to _not_ write any big, for some
|
||||
// value of big, runs of zeros, i.e. it will attempt to punch holes, where
|
||||
// possible, in `w` if that happens to be a freshly created or to zero length
|
||||
// truncated OS file. 'n' reports the number of bytes written to 'w'.
|
||||
func (f *MemFiler) WriteTo(w io.Writer) (n int64, err error) {
|
||||
var (
|
||||
b [pgSize]byte
|
||||
wn, rn int
|
||||
off int64
|
||||
rerr error
|
||||
)
|
||||
|
||||
if wa, ok := w.(io.WriterAt); ok {
|
||||
lastPgI := f.size >> pgBits
|
||||
for pgI := int64(0); pgI <= lastPgI; pgI++ {
|
||||
sz := pgSize
|
||||
if pgI == lastPgI {
|
||||
sz = int(f.size & pgMask)
|
||||
}
|
||||
pg := f.m[pgI]
|
||||
if pg != nil {
|
||||
wn, err = wa.WriteAt(pg[:sz], off)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
n += int64(wn)
|
||||
off += int64(sz)
|
||||
if wn != sz {
|
||||
return n, io.ErrShortWrite
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var werr error
|
||||
for rerr == nil {
|
||||
if rn, rerr = f.ReadAt(b[:], off); rn != 0 {
|
||||
off += int64(rn)
|
||||
if wn, werr = w.Write(b[:rn]); werr != nil {
|
||||
return n, werr
|
||||
}
|
||||
|
||||
n += int64(wn)
|
||||
}
|
||||
}
|
||||
if !fileutil.IsEOF(rerr) {
|
||||
err = rerr
|
||||
}
|
||||
return
|
||||
}
|
130
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/osfiler.go
generated
vendored
130
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/osfiler.go
generated
vendored
@ -1,130 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package lldb
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/cznic/mathutil"
|
||||
)
|
||||
|
||||
var _ Filer = (*OSFiler)(nil)
|
||||
|
||||
// OSFile is an os.File like minimal set of methods allowing to construct a
|
||||
// Filer.
|
||||
type OSFile interface {
|
||||
Name() string
|
||||
Stat() (fi os.FileInfo, err error)
|
||||
Sync() (err error)
|
||||
Truncate(size int64) (err error)
|
||||
io.Closer
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
io.Writer
|
||||
io.WriterAt
|
||||
}
|
||||
|
||||
// OSFiler is like a SimpleFileFiler but based on an OSFile.
|
||||
type OSFiler struct {
|
||||
f OSFile
|
||||
nest int
|
||||
size int64 // not set if < 0
|
||||
}
|
||||
|
||||
// NewOSFiler returns a Filer from an OSFile. This Filer is like the
|
||||
// SimpleFileFiler, it does not implement the transaction related methods.
|
||||
func NewOSFiler(f OSFile) (r *OSFiler) {
|
||||
return &OSFiler{
|
||||
f: f,
|
||||
size: -1,
|
||||
}
|
||||
}
|
||||
|
||||
// BeginUpdate implements Filer.
|
||||
func (f *OSFiler) BeginUpdate() (err error) {
|
||||
f.nest++
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements Filer.
|
||||
func (f *OSFiler) Close() (err error) {
|
||||
if f.nest != 0 {
|
||||
return &ErrPERM{(f.Name() + ":Close")}
|
||||
}
|
||||
|
||||
return f.f.Close()
|
||||
}
|
||||
|
||||
// EndUpdate implements Filer.
|
||||
func (f *OSFiler) EndUpdate() (err error) {
|
||||
if f.nest == 0 {
|
||||
return &ErrPERM{(f.Name() + ":EndUpdate")}
|
||||
}
|
||||
|
||||
f.nest--
|
||||
return
|
||||
}
|
||||
|
||||
// Name implements Filer.
|
||||
func (f *OSFiler) Name() string {
|
||||
return f.f.Name()
|
||||
}
|
||||
|
||||
// PunchHole implements Filer.
|
||||
func (f *OSFiler) PunchHole(off, size int64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// ReadAt implements Filer.
|
||||
func (f *OSFiler) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
return f.f.ReadAt(b, off)
|
||||
}
|
||||
|
||||
// Rollback implements Filer.
|
||||
func (f *OSFiler) Rollback() (err error) { return }
|
||||
|
||||
// Size implements Filer.
|
||||
func (f *OSFiler) Size() (n int64, err error) {
|
||||
if f.size < 0 { // boot
|
||||
fi, err := f.f.Stat()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
f.size = fi.Size()
|
||||
}
|
||||
return f.size, nil
|
||||
}
|
||||
|
||||
// Sync implements Filer.
|
||||
func (f *OSFiler) Sync() (err error) {
|
||||
return f.f.Sync()
|
||||
}
|
||||
|
||||
// Truncate implements Filer.
|
||||
func (f *OSFiler) Truncate(size int64) (err error) {
|
||||
if size < 0 {
|
||||
return &ErrINVAL{"Truncate size", size}
|
||||
}
|
||||
|
||||
f.size = size
|
||||
return f.f.Truncate(size)
|
||||
}
|
||||
|
||||
// WriteAt implements Filer.
|
||||
func (f *OSFiler) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
if f.size < 0 { // boot
|
||||
fi, err := os.Stat(f.f.Name())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
f.size = fi.Size()
|
||||
}
|
||||
f.size = mathutil.MaxInt64(f.size, int64(len(b))+off)
|
||||
return f.f.WriteAt(b, off)
|
||||
}
|
123
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/simplefilefiler.go
generated
vendored
123
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/simplefilefiler.go
generated
vendored
@ -1,123 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// A basic os.File backed Filer.
|
||||
|
||||
package lldb
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/cznic/fileutil"
|
||||
"github.com/cznic/mathutil"
|
||||
)
|
||||
|
||||
var _ Filer = &SimpleFileFiler{} // Ensure SimpleFileFiler is a Filer.
|
||||
|
||||
// SimpleFileFiler is an os.File backed Filer intended for use where structural
|
||||
// consistency can be reached by other means (SimpleFileFiler is for example
|
||||
// wrapped in eg. an RollbackFiler or ACIDFiler0) or where persistence is not
|
||||
// required (temporary/working data sets).
|
||||
//
|
||||
// SimpleFileFiler is the most simple os.File backed Filer implementation as it
|
||||
// does not really implement BeginUpdate and EndUpdate/Rollback in any way
|
||||
// which would protect the structural integrity of data. If misused e.g. as a
|
||||
// real database storage w/o other measures, it can easily cause data loss
|
||||
// when, for example, a power outage occurs or the updating process terminates
|
||||
// abruptly.
|
||||
type SimpleFileFiler struct {
|
||||
file *os.File
|
||||
nest int
|
||||
size int64 // not set if < 0
|
||||
}
|
||||
|
||||
// NewSimpleFileFiler returns a new SimpleFileFiler.
|
||||
func NewSimpleFileFiler(f *os.File) *SimpleFileFiler {
|
||||
return &SimpleFileFiler{file: f, size: -1}
|
||||
}
|
||||
|
||||
// BeginUpdate implements Filer.
|
||||
func (f *SimpleFileFiler) BeginUpdate() error {
|
||||
f.nest++
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements Filer.
|
||||
func (f *SimpleFileFiler) Close() (err error) {
|
||||
if f.nest != 0 {
|
||||
return &ErrPERM{(f.Name() + ":Close")}
|
||||
}
|
||||
|
||||
return f.file.Close()
|
||||
}
|
||||
|
||||
// EndUpdate implements Filer.
|
||||
func (f *SimpleFileFiler) EndUpdate() (err error) {
|
||||
if f.nest == 0 {
|
||||
return &ErrPERM{(f.Name() + ":EndUpdate")}
|
||||
}
|
||||
|
||||
f.nest--
|
||||
return
|
||||
}
|
||||
|
||||
// Name implements Filer.
|
||||
func (f *SimpleFileFiler) Name() string {
|
||||
return f.file.Name()
|
||||
}
|
||||
|
||||
// PunchHole implements Filer.
|
||||
func (f *SimpleFileFiler) PunchHole(off, size int64) (err error) {
|
||||
return fileutil.PunchHole(f.file, off, size)
|
||||
}
|
||||
|
||||
// ReadAt implements Filer.
|
||||
func (f *SimpleFileFiler) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
return f.file.ReadAt(b, off)
|
||||
}
|
||||
|
||||
// Rollback implements Filer.
|
||||
func (f *SimpleFileFiler) Rollback() (err error) { return }
|
||||
|
||||
// Size implements Filer.
|
||||
func (f *SimpleFileFiler) Size() (int64, error) {
|
||||
if f.size < 0 { // boot
|
||||
fi, err := os.Stat(f.file.Name())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
f.size = fi.Size()
|
||||
}
|
||||
return f.size, nil
|
||||
}
|
||||
|
||||
// Sync implements Filer.
|
||||
func (f *SimpleFileFiler) Sync() error {
|
||||
return f.file.Sync()
|
||||
}
|
||||
|
||||
// Truncate implements Filer.
|
||||
func (f *SimpleFileFiler) Truncate(size int64) (err error) {
|
||||
if size < 0 {
|
||||
return &ErrINVAL{"Truncate size", size}
|
||||
}
|
||||
|
||||
f.size = size
|
||||
return f.file.Truncate(size)
|
||||
}
|
||||
|
||||
// WriteAt implements Filer.
|
||||
func (f *SimpleFileFiler) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
if f.size < 0 { // boot
|
||||
fi, err := os.Stat(f.file.Name())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
f.size = fi.Size()
|
||||
}
|
||||
f.size = mathutil.MaxInt64(f.size, int64(len(b))+off)
|
||||
return f.file.WriteAt(b, off)
|
||||
}
|
642
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/xact.go
generated
vendored
642
vendor/github.com/cznic/ql/vendored/github.com/cznic/exp/lldb/xact.go
generated
vendored
@ -1,642 +0,0 @@
|
||||
// Copyright 2014 The lldb Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Structural transactions.
|
||||
|
||||
package lldb
|
||||
|
||||
//DONE+ TransactionalMemoryFiler
|
||||
// ----
|
||||
// Use NewRollbackFiler(myMemFiler, ...)
|
||||
|
||||
/*
|
||||
|
||||
bfBits: 3
|
||||
BenchmarkRollbackFiler 20000000 102 ns/op 9.73 MB/s
|
||||
|
||||
bfBits: 4
|
||||
BenchmarkRollbackFiler 50000000 55.7 ns/op 17.95 MB/s
|
||||
|
||||
bfBits: 5
|
||||
BenchmarkRollbackFiler 100000000 32.2 ns/op 31.06 MB/s
|
||||
|
||||
bfBits: 6
|
||||
BenchmarkRollbackFiler 100000000 20.6 ns/op 48.46 MB/s
|
||||
|
||||
bfBits: 7
|
||||
BenchmarkRollbackFiler 100000000 15.1 ns/op 66.12 MB/s
|
||||
|
||||
bfBits: 8
|
||||
BenchmarkRollbackFiler 100000000 10.5 ns/op 95.66 MB/s
|
||||
|
||||
bfBits: 9
|
||||
BenchmarkRollbackFiler 200000000 8.02 ns/op 124.74 MB/s
|
||||
|
||||
bfBits: 10
|
||||
BenchmarkRollbackFiler 200000000 9.25 ns/op 108.09 MB/s
|
||||
|
||||
bfBits: 11
|
||||
BenchmarkRollbackFiler 100000000 11.7 ns/op 85.47 MB/s
|
||||
|
||||
bfBits: 12
|
||||
BenchmarkRollbackFiler 100000000 17.2 ns/op 57.99 MB/s
|
||||
|
||||
bfBits: 13
|
||||
BenchmarkRollbackFiler 100000000 32.7 ns/op 30.58 MB/s
|
||||
|
||||
bfBits: 14
|
||||
BenchmarkRollbackFiler 50000000 39.6 ns/op 25.27 MB/s
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/cznic/fileutil"
|
||||
"github.com/cznic/mathutil"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Filer = &bitFiler{} // Ensure bitFiler is a Filer.
|
||||
_ Filer = &RollbackFiler{} // ditto
|
||||
)
|
||||
|
||||
const (
|
||||
bfBits = 9
|
||||
bfSize = 1 << bfBits
|
||||
bfMask = bfSize - 1
|
||||
)
|
||||
|
||||
var (
|
||||
bitmask = [8]byte{1, 2, 4, 8, 16, 32, 64, 128}
|
||||
bitZeroPage bitPage
|
||||
allDirtyFlags [bfSize >> 3]byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := range allDirtyFlags {
|
||||
allDirtyFlags[i] = 0xff
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
bitPage struct {
|
||||
prev, next *bitPage
|
||||
data [bfSize]byte
|
||||
flags [bfSize >> 3]byte
|
||||
dirty bool
|
||||
}
|
||||
|
||||
bitFilerMap map[int64]*bitPage
|
||||
|
||||
bitFiler struct {
|
||||
parent Filer
|
||||
m bitFilerMap
|
||||
size int64
|
||||
sync.Mutex
|
||||
}
|
||||
)
|
||||
|
||||
func newBitFiler(parent Filer) (f *bitFiler, err error) {
|
||||
sz, err := parent.Size()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &bitFiler{parent: parent, m: bitFilerMap{}, size: sz}, nil
|
||||
}
|
||||
|
||||
func (f *bitFiler) BeginUpdate() error { panic("internal error") }
|
||||
func (f *bitFiler) EndUpdate() error { panic("internal error") }
|
||||
func (f *bitFiler) Rollback() error { panic("internal error") }
|
||||
func (f *bitFiler) Sync() error { panic("internal error") }
|
||||
|
||||
func (f *bitFiler) Close() (err error) { return }
|
||||
func (f *bitFiler) Name() string { return fmt.Sprintf("%p.bitfiler", f) }
|
||||
func (f *bitFiler) Size() (int64, error) { return f.size, nil }
|
||||
|
||||
func (f *bitFiler) PunchHole(off, size int64) (err error) {
|
||||
first := off >> bfBits
|
||||
if off&bfMask != 0 {
|
||||
first++
|
||||
}
|
||||
off += size - 1
|
||||
last := off >> bfBits
|
||||
if off&bfMask != 0 {
|
||||
last--
|
||||
}
|
||||
if limit := f.size >> bfBits; last > limit {
|
||||
last = limit
|
||||
}
|
||||
f.Lock()
|
||||
for pgI := first; pgI <= last; pgI++ {
|
||||
pg := &bitPage{}
|
||||
pg.flags = allDirtyFlags
|
||||
f.m[pgI] = pg
|
||||
}
|
||||
f.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (f *bitFiler) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
avail := f.size - off
|
||||
pgI := off >> bfBits
|
||||
pgO := int(off & bfMask)
|
||||
rem := len(b)
|
||||
if int64(rem) >= avail {
|
||||
rem = int(avail)
|
||||
err = io.EOF
|
||||
}
|
||||
for rem != 0 && avail > 0 {
|
||||
f.Lock()
|
||||
pg := f.m[pgI]
|
||||
if pg == nil {
|
||||
pg = &bitPage{}
|
||||
if f.parent != nil {
|
||||
_, err = f.parent.ReadAt(pg.data[:], off&^bfMask)
|
||||
if err != nil && !fileutil.IsEOF(err) {
|
||||
f.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
err = nil
|
||||
}
|
||||
f.m[pgI] = pg
|
||||
}
|
||||
f.Unlock()
|
||||
nc := copy(b[:mathutil.Min(rem, bfSize)], pg.data[pgO:])
|
||||
pgI++
|
||||
pgO = 0
|
||||
rem -= nc
|
||||
n += nc
|
||||
b = b[nc:]
|
||||
off += int64(nc)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *bitFiler) Truncate(size int64) (err error) {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
switch {
|
||||
case size < 0:
|
||||
return &ErrINVAL{"Truncate size", size}
|
||||
case size == 0:
|
||||
f.m = bitFilerMap{}
|
||||
f.size = 0
|
||||
return
|
||||
}
|
||||
|
||||
first := size >> bfBits
|
||||
if size&bfMask != 0 {
|
||||
first++
|
||||
}
|
||||
last := f.size >> bfBits
|
||||
if f.size&bfMask != 0 {
|
||||
last++
|
||||
}
|
||||
for ; first < last; first++ {
|
||||
delete(f.m, first)
|
||||
}
|
||||
|
||||
f.size = size
|
||||
return
|
||||
}
|
||||
|
||||
func (f *bitFiler) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
off0 := off
|
||||
pgI := off >> bfBits
|
||||
pgO := int(off & bfMask)
|
||||
n = len(b)
|
||||
rem := n
|
||||
var nc int
|
||||
for rem != 0 {
|
||||
f.Lock()
|
||||
pg := f.m[pgI]
|
||||
if pg == nil {
|
||||
pg = &bitPage{}
|
||||
if f.parent != nil {
|
||||
_, err = f.parent.ReadAt(pg.data[:], off&^bfMask)
|
||||
if err != nil && !fileutil.IsEOF(err) {
|
||||
f.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
err = nil
|
||||
}
|
||||
f.m[pgI] = pg
|
||||
}
|
||||
f.Unlock()
|
||||
nc = copy(pg.data[pgO:], b)
|
||||
pgI++
|
||||
pg.dirty = true
|
||||
for i := pgO; i < pgO+nc; i++ {
|
||||
pg.flags[i>>3] |= bitmask[i&7]
|
||||
}
|
||||
pgO = 0
|
||||
rem -= nc
|
||||
b = b[nc:]
|
||||
off += int64(nc)
|
||||
}
|
||||
f.size = mathutil.MaxInt64(f.size, off0+int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
func (f *bitFiler) link() {
|
||||
for pgI, pg := range f.m {
|
||||
nx, ok := f.m[pgI+1]
|
||||
if !ok || !nx.dirty {
|
||||
continue
|
||||
}
|
||||
|
||||
nx.prev, pg.next = pg, nx
|
||||
}
|
||||
}
|
||||
|
||||
func (f *bitFiler) dumpDirty(w io.WriterAt) (nwr int, err error) {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
f.link()
|
||||
for pgI, pg := range f.m {
|
||||
if !pg.dirty {
|
||||
continue
|
||||
}
|
||||
|
||||
for pg.prev != nil && pg.prev.dirty {
|
||||
pg = pg.prev
|
||||
pgI--
|
||||
}
|
||||
|
||||
for pg != nil && pg.dirty {
|
||||
last := false
|
||||
var off int64
|
||||
first := -1
|
||||
for i := 0; i < bfSize; i++ {
|
||||
flag := pg.flags[i>>3]&bitmask[i&7] != 0
|
||||
switch {
|
||||
case flag && !last: // Leading edge detected
|
||||
off = pgI<<bfBits + int64(i)
|
||||
first = i
|
||||
case !flag && last: // Trailing edge detected
|
||||
n, err := w.WriteAt(pg.data[first:i], off)
|
||||
if n != i-first {
|
||||
return 0, err
|
||||
}
|
||||
first = -1
|
||||
nwr++
|
||||
}
|
||||
|
||||
last = flag
|
||||
}
|
||||
if first >= 0 {
|
||||
i := bfSize
|
||||
n, err := w.WriteAt(pg.data[first:i], off)
|
||||
if n != i-first {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
nwr++
|
||||
}
|
||||
|
||||
pg.dirty = false
|
||||
pg = pg.next
|
||||
pgI++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RollbackFiler is a Filer implementing structural transaction handling.
|
||||
// Structural transactions should be small and short lived because all non
|
||||
// committed data are held in memory until committed or discarded by a
|
||||
// Rollback.
|
||||
//
|
||||
// While using RollbackFiler, every intended update of the wrapped Filler, by
|
||||
// WriteAt, Truncate or PunchHole, _must_ be made within a transaction.
|
||||
// Attempts to do it outside of a transaction will return ErrPERM. OTOH,
|
||||
// invoking ReadAt outside of a transaction is not a problem.
|
||||
//
|
||||
// No nested transactions: All updates within a transaction are held in memory.
|
||||
// On a matching EndUpdate the updates held in memory are actually written to
|
||||
// the wrapped Filer.
|
||||
//
|
||||
// Nested transactions: Correct data will be seen from RollbackFiler when any
|
||||
// level of a nested transaction is rollbacked. The actual writing to the
|
||||
// wrapped Filer happens only when the outer most transaction nesting level is
|
||||
// closed.
|
||||
//
|
||||
// Invoking Rollback is an alternative to EndUpdate. It discards all changes
|
||||
// made at the current transaction level and returns the "state" (possibly not
|
||||
// yet persisted) of the Filer to what it was before the corresponding
|
||||
// BeginUpdate.
|
||||
//
|
||||
// During an open transaction, all reads (using ReadAt) are "dirty" reads,
|
||||
// seeing the uncommitted changes made to the Filer's data.
|
||||
//
|
||||
// Lldb databases should be based upon a RollbackFiler.
|
||||
//
|
||||
// With a wrapped MemFiler one gets transactional memory. With, for example a
|
||||
// wrapped disk based SimpleFileFiler it protects against at least some HW
|
||||
// errors - if Rollback is properly invoked on such failures and/or if there's
|
||||
// some WAL or 2PC or whatever other safe mechanism based recovery procedure
|
||||
// used by the client.
|
||||
//
|
||||
// The "real" writes to the wrapped Filer (or WAL instead) go through the
|
||||
// writerAt supplied to NewRollbackFiler.
|
||||
//
|
||||
// List of functions/methods which are recommended to be wrapped in a
|
||||
// BeginUpdate/EndUpdate structural transaction:
|
||||
//
|
||||
// Allocator.Alloc
|
||||
// Allocator.Free
|
||||
// Allocator.Realloc
|
||||
//
|
||||
// CreateBTree
|
||||
// RemoveBTree
|
||||
// BTree.Clear
|
||||
// BTree.Delete
|
||||
// BTree.DeleteAny
|
||||
// BTree.Clear
|
||||
// BTree.Extract
|
||||
// BTree.Get (it can mutate the DB)
|
||||
// BTree.Put
|
||||
// BTree.Set
|
||||
//
|
||||
// NOTE: RollbackFiler is a generic solution intended to wrap Filers provided
|
||||
// by this package which do not implement any of the transactional methods.
|
||||
// RollbackFiler thus _does not_ invoke any of the transactional methods of its
|
||||
// wrapped Filer.
|
||||
//
|
||||
// RollbackFiler is safe for concurrent use by multiple goroutines.
|
||||
type RollbackFiler struct {
|
||||
mu sync.RWMutex
|
||||
inCallback bool
|
||||
inCallbackMu sync.RWMutex
|
||||
bitFiler *bitFiler
|
||||
checkpoint func(int64) error
|
||||
closed bool
|
||||
f Filer
|
||||
parent Filer
|
||||
tlevel int // transaction nesting level, 0 == not in transaction
|
||||
writerAt io.WriterAt
|
||||
|
||||
// afterRollback, if not nil, is called after performing Rollback
|
||||
// without errros.
|
||||
afterRollback func() error
|
||||
}
|
||||
|
||||
// NewRollbackFiler returns a RollbackFiler wrapping f.
|
||||
//
|
||||
// The checkpoint parameter
|
||||
//
|
||||
// The checkpoint function is called after closing (by EndUpdate) the upper
|
||||
// most level open transaction if all calls of writerAt were successful and the
|
||||
// DB (or eg. a WAL) is thus now in a consistent state (virtually, in the ideal
|
||||
// world with no write caches, no HW failures, no process crashes, ...).
|
||||
//
|
||||
// NOTE: In, for example, a 2PC it is necessary to reflect also the sz
|
||||
// parameter as the new file size (as in the parameter to Truncate). All
|
||||
// changes were successfully written already by writerAt before invoking
|
||||
// checkpoint.
|
||||
//
|
||||
// The writerAt parameter
|
||||
//
|
||||
// The writerAt interface is used to commit the updates of the wrapped Filer.
|
||||
// If any invocation of writerAt fails then a non nil error will be returned
|
||||
// from EndUpdate and checkpoint will _not_ ne called. Neither is necessary to
|
||||
// call Rollback. The rule of thumb: The [structural] transaction [level] is
|
||||
// closed by invoking exactly once one of EndUpdate _or_ Rollback.
|
||||
//
|
||||
// It is presumed that writerAt uses WAL or 2PC or whatever other safe
|
||||
// mechanism to physically commit the updates.
|
||||
//
|
||||
// Updates performed by invocations of writerAt are byte-precise, but not
|
||||
// necessarily maximum possible length precise. IOW, for example an update
|
||||
// crossing page boundaries may be performed by more than one writerAt
|
||||
// invocation. No offset sorting is performed. This may change if it proves
|
||||
// to be a problem. Such change would be considered backward compatible.
|
||||
//
|
||||
// NOTE: Using RollbackFiler, but failing to ever invoke a matching "closing"
|
||||
// EndUpdate after an "opening" BeginUpdate means neither writerAt or
|
||||
// checkpoint will ever get called - with all the possible data loss
|
||||
// consequences.
|
||||
func NewRollbackFiler(f Filer, checkpoint func(sz int64) error, writerAt io.WriterAt) (r *RollbackFiler, err error) {
|
||||
if f == nil || checkpoint == nil || writerAt == nil {
|
||||
return nil, &ErrINVAL{Src: "lldb.NewRollbackFiler, nil argument"}
|
||||
}
|
||||
|
||||
return &RollbackFiler{
|
||||
checkpoint: checkpoint,
|
||||
f: f,
|
||||
writerAt: writerAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) BeginUpdate() (err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
parent := r.f
|
||||
if r.tlevel != 0 {
|
||||
parent = r.bitFiler
|
||||
}
|
||||
r.bitFiler, err = newBitFiler(parent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.tlevel++
|
||||
return
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
//
|
||||
// Close will return an error if not invoked at nesting level 0. However, to
|
||||
// allow emergency closing from eg. a signal handler; if Close is invoked
|
||||
// within an open transaction(s), it rollbacks any non committed open
|
||||
// transactions and performs the Close operation.
|
||||
//
|
||||
// IOW: Regardless of the transaction nesting level the Close is always
|
||||
// performed but any uncommitted transaction data are lost.
|
||||
func (r *RollbackFiler) Close() (err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.closed {
|
||||
return &ErrPERM{r.f.Name() + ": Already closed"}
|
||||
}
|
||||
|
||||
r.closed = true
|
||||
if err = r.f.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if r.tlevel != 0 {
|
||||
err = &ErrPERM{r.f.Name() + ": Close inside an open transaction"}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) EndUpdate() (err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.tlevel == 0 {
|
||||
return &ErrPERM{r.f.Name() + " : EndUpdate outside of a transaction"}
|
||||
}
|
||||
|
||||
sz, err := r.size() // Cannot call .Size() -> deadlock
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.tlevel--
|
||||
bf := r.bitFiler
|
||||
parent := bf.parent
|
||||
w := r.writerAt
|
||||
if r.tlevel != 0 {
|
||||
w = parent
|
||||
}
|
||||
nwr, err := bf.dumpDirty(w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case r.tlevel == 0:
|
||||
r.bitFiler = nil
|
||||
if nwr == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
return r.checkpoint(sz)
|
||||
default:
|
||||
r.bitFiler = parent.(*bitFiler)
|
||||
sz, _ := bf.Size() // bitFiler.Size() never returns err != nil
|
||||
return parent.Truncate(sz)
|
||||
}
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) Name() string {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
return r.f.Name()
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) PunchHole(off, size int64) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.tlevel == 0 {
|
||||
return &ErrPERM{r.f.Name() + ": PunchHole outside of a transaction"}
|
||||
}
|
||||
|
||||
if off < 0 {
|
||||
return &ErrINVAL{r.f.Name() + ": PunchHole off", off}
|
||||
}
|
||||
|
||||
if size < 0 || off+size > r.bitFiler.size {
|
||||
return &ErrINVAL{r.f.Name() + ": PunchHole size", size}
|
||||
}
|
||||
|
||||
return r.bitFiler.PunchHole(off, size)
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
r.inCallbackMu.RLock()
|
||||
defer r.inCallbackMu.RUnlock()
|
||||
if !r.inCallback {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
}
|
||||
if r.tlevel == 0 {
|
||||
return r.f.ReadAt(b, off)
|
||||
}
|
||||
|
||||
return r.bitFiler.ReadAt(b, off)
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) Rollback() (err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.tlevel == 0 {
|
||||
return &ErrPERM{r.f.Name() + ": Rollback outside of a transaction"}
|
||||
}
|
||||
|
||||
if r.tlevel > 1 {
|
||||
r.bitFiler = r.bitFiler.parent.(*bitFiler)
|
||||
}
|
||||
r.tlevel--
|
||||
if f := r.afterRollback; f != nil {
|
||||
r.inCallbackMu.Lock()
|
||||
r.inCallback = true
|
||||
r.inCallbackMu.Unlock()
|
||||
defer func() {
|
||||
r.inCallbackMu.Lock()
|
||||
r.inCallback = false
|
||||
r.inCallbackMu.Unlock()
|
||||
}()
|
||||
return f()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *RollbackFiler) size() (sz int64, err error) {
|
||||
if r.tlevel == 0 {
|
||||
return r.f.Size()
|
||||
}
|
||||
|
||||
return r.bitFiler.Size()
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) Size() (sz int64, err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
return r.size()
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) Sync() error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
return r.f.Sync()
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) Truncate(size int64) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.tlevel == 0 {
|
||||
return &ErrPERM{r.f.Name() + ": Truncate outside of a transaction"}
|
||||
}
|
||||
|
||||
return r.bitFiler.Truncate(size)
|
||||
}
|
||||
|
||||
// Implements Filer.
|
||||
func (r *RollbackFiler) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.tlevel == 0 {
|
||||
return 0, &ErrPERM{r.f.Name() + ": WriteAt outside of a transaction"}
|
||||
}
|
||||
|
||||
return r.bitFiler.WriteAt(b, off)
|
||||
}
|
6
vendor/github.com/cznic/zappy/decode_cgo.go
generated
vendored
6
vendor/github.com/cznic/zappy/decode_cgo.go
generated
vendored
@ -10,6 +10,10 @@
|
||||
|
||||
package zappy
|
||||
|
||||
import (
|
||||
"github.com/cznic/internal/buffer"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
#include <stdint.h>
|
||||
@ -109,7 +113,7 @@ func Decode(buf, src []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
if len(buf) < dLen {
|
||||
buf = make([]byte, dLen)
|
||||
buf = *buffer.Get(dLen)
|
||||
}
|
||||
|
||||
d := int(C.decode(C.int(s), C.int(len(src)), (*C.uint8_t)(&src[0]), C.int(len(buf)), (*C.uint8_t)(&buf[0])))
|
||||
|
4
vendor/github.com/cznic/zappy/decode_nocgo.go
generated
vendored
4
vendor/github.com/cznic/zappy/decode_nocgo.go
generated
vendored
@ -12,6 +12,8 @@ package zappy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/cznic/internal/buffer"
|
||||
)
|
||||
|
||||
func puregoDecode() bool { return true }
|
||||
@ -35,7 +37,7 @@ func Decode(buf, src []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
if len(buf) < dLen {
|
||||
buf = make([]byte, dLen)
|
||||
buf = *buffer.Get(dLen)
|
||||
}
|
||||
|
||||
var d, offset, length int
|
||||
|
2
vendor/github.com/cznic/zappy/encode.go
generated
vendored
2
vendor/github.com/cznic/zappy/encode.go
generated
vendored
@ -33,5 +33,5 @@ func emitLiteral(dst, lit []byte) (n int) {
|
||||
// MaxEncodedLen returns the maximum length of a zappy block, given its
|
||||
// uncompressed length.
|
||||
func MaxEncodedLen(srcLen int) int {
|
||||
return 10 + srcLen
|
||||
return 10 + srcLen + (srcLen+1)/2
|
||||
}
|
||||
|
4
vendor/github.com/cznic/zappy/encode_cgo.go
generated
vendored
4
vendor/github.com/cznic/zappy/encode_cgo.go
generated
vendored
@ -107,6 +107,8 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/cznic/internal/buffer"
|
||||
)
|
||||
|
||||
func puregoEncode() bool { return false }
|
||||
@ -117,7 +119,7 @@ func puregoEncode() bool { return false }
|
||||
// It is valid to pass a nil buf.
|
||||
func Encode(buf, src []byte) ([]byte, error) {
|
||||
if n := MaxEncodedLen(len(src)); len(buf) < n {
|
||||
buf = make([]byte, n)
|
||||
buf = *buffer.Get(n)
|
||||
}
|
||||
|
||||
if len(src) > math.MaxInt32 {
|
||||
|
4
vendor/github.com/cznic/zappy/encode_nocgo.go
generated
vendored
4
vendor/github.com/cznic/zappy/encode_nocgo.go
generated
vendored
@ -14,6 +14,8 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/cznic/internal/buffer"
|
||||
)
|
||||
|
||||
func puregoEncode() bool { return true }
|
||||
@ -24,7 +26,7 @@ func puregoEncode() bool { return true }
|
||||
// It is valid to pass a nil buf.
|
||||
func Encode(buf, src []byte) ([]byte, error) {
|
||||
if n := MaxEncodedLen(len(src)); len(buf) < n {
|
||||
buf = make([]byte, n)
|
||||
buf = *buffer.Get(n)
|
||||
}
|
||||
|
||||
if len(src) > math.MaxInt32 {
|
||||
|
1
vendor/github.com/cznic/zappy/zappy.go
generated
vendored
1
vendor/github.com/cznic/zappy/zappy.go
generated
vendored
@ -124,7 +124,6 @@ Old=Go snappy, new=zappy:
|
||||
|
||||
The package builds with CGO_ENABLED=0 as well, but the performance is worse.
|
||||
|
||||
|
||||
$ CGO_ENABLED=0 go test -test.run=NONE -test.bench=. > old.benchcmp
|
||||
$ CGO_ENABLED=1 go test -test.run=NONE -test.bench=. > new.benchcmp
|
||||
$ benchcmp old.benchcmp new.benchcmp
|
||||
|
8
vendor/manifest
vendored
8
vendor/manifest
vendored
@ -34,7 +34,7 @@
|
||||
{
|
||||
"importpath": "github.com/cznic/b",
|
||||
"repository": "https://github.com/cznic/b",
|
||||
"revision": "47184dd8c1d2c7e7f87dae8448ee2007cdf0c6c4",
|
||||
"revision": "bcff30a622dbdcb425aba904792de1df606dab7c",
|
||||
"branch": "master",
|
||||
"notests": true
|
||||
},
|
||||
@ -86,14 +86,14 @@
|
||||
{
|
||||
"importpath": "github.com/cznic/mathutil",
|
||||
"repository": "https://github.com/cznic/mathutil",
|
||||
"revision": "38a5fe05cd94d69433fd1c928417834c604f281d",
|
||||
"revision": "78ad7f262603437f0ecfebc835d80094f89c8f54",
|
||||
"branch": "master",
|
||||
"notests": true
|
||||
},
|
||||
{
|
||||
"importpath": "github.com/cznic/ql",
|
||||
"repository": "https://github.com/cznic/ql",
|
||||
"revision": "f5e72a6fe84f25e7539555bdfcee8dc440d93894",
|
||||
"revision": "c81467d34c630800dd4ba81033e234a8159ff2e3",
|
||||
"branch": "master",
|
||||
"notests": true
|
||||
},
|
||||
@ -114,7 +114,7 @@
|
||||
{
|
||||
"importpath": "github.com/cznic/zappy",
|
||||
"repository": "https://github.com/cznic/zappy",
|
||||
"revision": "4f5e6ef19fd692f1ef9b01206de4f1161a314e9a",
|
||||
"revision": "2533cb5b45cc6c07421468ce262899ddc9d53fb7",
|
||||
"branch": "master",
|
||||
"notests": true
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user