mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-09 23:00:58 +00:00
vendor: Add github.com/cznic/lldb and friends (new recursive dependency)
This commit is contained in:
parent
ca755ec9e0
commit
81d19a00aa
27
vendor/github.com/cznic/internal/buffer/LICENSE
generated
vendored
Normal file
27
vendor/github.com/cznic/internal/buffer/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2016 The Internal Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the names of the authors nor the names of the
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
55
vendor/github.com/cznic/internal/buffer/buffer.go
generated
vendored
Normal file
55
vendor/github.com/cznic/internal/buffer/buffer.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2016 The Internal 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 buffer implements a pool of pointers to byte slices.
|
||||||
|
//
|
||||||
|
// Example usage pattern
|
||||||
|
//
|
||||||
|
// p := buffer.Get(size)
|
||||||
|
// b := *p // Now you can use b in any way you need.
|
||||||
|
// ...
|
||||||
|
// // When b will not be used anymore
|
||||||
|
// buffer.Put(p)
|
||||||
|
// ...
|
||||||
|
// // If b or p are not going out of scope soon, optionally
|
||||||
|
// b = nil
|
||||||
|
// p = nil
|
||||||
|
//
|
||||||
|
// Otherwise the pool cannot release the buffer on garbage collection.
|
||||||
|
//
|
||||||
|
// Do not do
|
||||||
|
//
|
||||||
|
// p := buffer.Get(size)
|
||||||
|
// b := *p
|
||||||
|
// ...
|
||||||
|
// buffer.Put(&b)
|
||||||
|
//
|
||||||
|
// or
|
||||||
|
//
|
||||||
|
// b := *buffer.Get(size)
|
||||||
|
// ...
|
||||||
|
// buffer.Put(&b)
|
||||||
|
package buffer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cznic/internal/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CGet returns a pointer to a byte slice of len size. The pointed to byte
|
||||||
|
// slice is zeroed up to its cap. CGet panics for size < 0.
|
||||||
|
//
|
||||||
|
// CGet is safe for concurrent use by multiple goroutines.
|
||||||
|
func CGet(size int) *[]byte { return slice.Bytes.CGet(size).(*[]byte) }
|
||||||
|
|
||||||
|
// Get returns a pointer to a byte slice of len size. The pointed to byte slice
|
||||||
|
// is not zeroed. Get panics for size < 0.
|
||||||
|
//
|
||||||
|
// Get is safe for concurrent use by multiple goroutines.
|
||||||
|
func Get(size int) *[]byte { return slice.Bytes.Get(size).(*[]byte) }
|
||||||
|
|
||||||
|
// Put puts a pointer to a byte slice into a pool for possible later reuse by
|
||||||
|
// CGet or Get.
|
||||||
|
//
|
||||||
|
// Put is safe for concurrent use by multiple goroutines.
|
||||||
|
func Put(p *[]byte) { slice.Bytes.Put(p) }
|
27
vendor/github.com/cznic/internal/file/LICENSE
generated
vendored
Normal file
27
vendor/github.com/cznic/internal/file/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2016 The Internal Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the names of the authors nor the names of the
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
434
vendor/github.com/cznic/internal/file/file.go
generated
vendored
Normal file
434
vendor/github.com/cznic/internal/file/file.go
generated
vendored
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
// Copyright 2016 The Internal 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 file provides an os.File-like interface of a memory mapped file.
|
||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cznic/fileutil"
|
||||||
|
"github.com/cznic/internal/buffer"
|
||||||
|
"github.com/cznic/mathutil"
|
||||||
|
"github.com/edsrzf/mmap-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const copyBufSize = 1 << 20 // 1 MB.
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ Interface = (*mem)(nil)
|
||||||
|
_ Interface = (*file)(nil)
|
||||||
|
|
||||||
|
_ os.FileInfo = stat{}
|
||||||
|
|
||||||
|
sysPage = os.Getpagesize()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface is a os.File-like entity.
|
||||||
|
type Interface interface {
|
||||||
|
io.ReaderAt
|
||||||
|
io.ReaderFrom
|
||||||
|
io.WriterAt
|
||||||
|
io.WriterTo
|
||||||
|
|
||||||
|
Close() error
|
||||||
|
Stat() (os.FileInfo, error)
|
||||||
|
Sync() error
|
||||||
|
Truncate(int64) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open returns a new Interface backed by f, or an error, if any.
|
||||||
|
func Open(f *os.File) (Interface, error) { return newFile(f, 1<<30, 20) }
|
||||||
|
|
||||||
|
// OpenMem returns a new Interface, or an error, if any. The Interface content
|
||||||
|
// is volatile, it's backed only by process' memory.
|
||||||
|
func OpenMem(name string) (Interface, error) { return newMem(name, 18), nil }
|
||||||
|
|
||||||
|
type memMap map[int64]*[]byte
|
||||||
|
|
||||||
|
type mem struct {
|
||||||
|
m memMap
|
||||||
|
modTime time.Time
|
||||||
|
name string
|
||||||
|
pgBits uint
|
||||||
|
pgMask int
|
||||||
|
pgSize int
|
||||||
|
size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMem(name string, pgBits uint) *mem {
|
||||||
|
pgSize := 1 << pgBits
|
||||||
|
return &mem{
|
||||||
|
m: memMap{},
|
||||||
|
modTime: time.Now(),
|
||||||
|
name: name,
|
||||||
|
pgBits: pgBits,
|
||||||
|
pgMask: pgSize - 1,
|
||||||
|
pgSize: pgSize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mem) IsDir() bool { return false }
|
||||||
|
func (f *mem) Mode() os.FileMode { return os.ModeTemporary + 0600 }
|
||||||
|
func (f *mem) ModTime() time.Time { return f.modTime }
|
||||||
|
func (f *mem) Name() string { return f.name }
|
||||||
|
func (f *mem) ReadFrom(r io.Reader) (n int64, err error) { return readFrom(f, r) }
|
||||||
|
func (f *mem) Size() (n int64) { return f.size }
|
||||||
|
func (f *mem) Stat() (os.FileInfo, error) { return f, nil }
|
||||||
|
func (f *mem) Sync() error { return nil }
|
||||||
|
func (f *mem) Sys() interface{} { return nil }
|
||||||
|
func (f *mem) WriteTo(w io.Writer) (n int64, err error) { return writeTo(f, w) }
|
||||||
|
|
||||||
|
func (f *mem) Close() error {
|
||||||
|
f.Truncate(0)
|
||||||
|
f.m = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mem) ReadAt(b []byte, off int64) (n int, err error) {
|
||||||
|
avail := f.size - off
|
||||||
|
pi := off >> f.pgBits
|
||||||
|
po := int(off) & f.pgMask
|
||||||
|
rem := len(b)
|
||||||
|
if int64(rem) >= avail {
|
||||||
|
rem = int(avail)
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
var zeroPage *[]byte
|
||||||
|
for rem != 0 && avail > 0 {
|
||||||
|
pg := f.m[pi]
|
||||||
|
if pg == nil {
|
||||||
|
if zeroPage == nil {
|
||||||
|
zeroPage = buffer.CGet(f.pgSize)
|
||||||
|
defer buffer.Put(zeroPage)
|
||||||
|
}
|
||||||
|
pg = zeroPage
|
||||||
|
}
|
||||||
|
nc := copy(b[:mathutil.Min(rem, f.pgSize)], (*pg)[po:])
|
||||||
|
pi++
|
||||||
|
po = 0
|
||||||
|
rem -= nc
|
||||||
|
n += nc
|
||||||
|
b = b[nc:]
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mem) Truncate(size int64) (err error) {
|
||||||
|
if size < 0 {
|
||||||
|
return fmt.Errorf("invalid truncate size: %d", size)
|
||||||
|
}
|
||||||
|
|
||||||
|
first := size >> f.pgBits
|
||||||
|
if size&int64(f.pgMask) != 0 {
|
||||||
|
first++
|
||||||
|
}
|
||||||
|
last := f.size >> f.pgBits
|
||||||
|
if f.size&int64(f.pgMask) != 0 {
|
||||||
|
last++
|
||||||
|
}
|
||||||
|
for ; first <= last; first++ {
|
||||||
|
if p := f.m[first]; p != nil {
|
||||||
|
buffer.Put(p)
|
||||||
|
}
|
||||||
|
delete(f.m, first)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.size = size
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mem) WriteAt(b []byte, off int64) (n int, err error) {
|
||||||
|
pi := off >> f.pgBits
|
||||||
|
po := int(off) & f.pgMask
|
||||||
|
n = len(b)
|
||||||
|
rem := n
|
||||||
|
var nc int
|
||||||
|
for rem != 0 {
|
||||||
|
pg := f.m[pi]
|
||||||
|
if pg == nil {
|
||||||
|
pg = buffer.CGet(f.pgSize)
|
||||||
|
f.m[pi] = pg
|
||||||
|
}
|
||||||
|
nc = copy((*pg)[po:], b)
|
||||||
|
pi++
|
||||||
|
po = 0
|
||||||
|
rem -= nc
|
||||||
|
b = b[nc:]
|
||||||
|
}
|
||||||
|
f.size = mathutil.MaxInt64(f.size, off+int64(n))
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type stat struct {
|
||||||
|
os.FileInfo
|
||||||
|
size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s stat) Size() int64 { return s.size }
|
||||||
|
|
||||||
|
type fileMap map[int64]mmap.MMap
|
||||||
|
|
||||||
|
type file struct {
|
||||||
|
f *os.File
|
||||||
|
m fileMap
|
||||||
|
maxPages int
|
||||||
|
pgBits uint
|
||||||
|
pgMask int
|
||||||
|
pgSize int
|
||||||
|
size int64
|
||||||
|
fsize int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFile(f *os.File, maxSize int64, pgBits uint) (*file, error) {
|
||||||
|
if maxSize < 0 {
|
||||||
|
panic("internal error")
|
||||||
|
}
|
||||||
|
|
||||||
|
pgSize := 1 << pgBits
|
||||||
|
switch {
|
||||||
|
case sysPage > pgSize:
|
||||||
|
pgBits = uint(mathutil.Log2Uint64(uint64(sysPage)))
|
||||||
|
default:
|
||||||
|
pgBits = uint(mathutil.Log2Uint64(uint64(pgSize / sysPage * sysPage)))
|
||||||
|
}
|
||||||
|
pgSize = 1 << pgBits
|
||||||
|
fi := &file{
|
||||||
|
f: f,
|
||||||
|
m: fileMap{},
|
||||||
|
maxPages: int(mathutil.MinInt64(
|
||||||
|
1024,
|
||||||
|
mathutil.MaxInt64(maxSize/int64(pgSize), 1)),
|
||||||
|
),
|
||||||
|
pgBits: pgBits,
|
||||||
|
pgMask: pgSize - 1,
|
||||||
|
pgSize: pgSize,
|
||||||
|
}
|
||||||
|
info, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = fi.Truncate(info.Size()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) ReadFrom(r io.Reader) (n int64, err error) { return readFrom(f, r) }
|
||||||
|
func (f *file) Sync() (err error) { return f.f.Sync() }
|
||||||
|
func (f *file) WriteTo(w io.Writer) (n int64, err error) { return writeTo(f, w) }
|
||||||
|
|
||||||
|
func (f *file) Close() (err error) {
|
||||||
|
for _, p := range f.m {
|
||||||
|
if err = p.Unmap(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = f.f.Truncate(f.size); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = f.f.Sync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = f.f.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.m = nil
|
||||||
|
f.f = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) page(index int64) (mmap.MMap, error) {
|
||||||
|
if len(f.m) == f.maxPages {
|
||||||
|
for i, p := range f.m {
|
||||||
|
if err := p.Unmap(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(f.m, i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
off := index << f.pgBits
|
||||||
|
fsize := off + int64(f.pgSize)
|
||||||
|
if fsize > f.fsize {
|
||||||
|
if err := f.f.Truncate(fsize); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.fsize = fsize
|
||||||
|
}
|
||||||
|
p, err := mmap.MapRegion(f.f, f.pgSize, mmap.RDWR, 0, off)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.m[index] = p
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) ReadAt(b []byte, off int64) (n int, err error) {
|
||||||
|
avail := f.size - off
|
||||||
|
pi := off >> f.pgBits
|
||||||
|
po := int(off) & f.pgMask
|
||||||
|
rem := len(b)
|
||||||
|
if int64(rem) >= avail {
|
||||||
|
rem = int(avail)
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
for rem != 0 && avail > 0 {
|
||||||
|
pg := f.m[pi]
|
||||||
|
if pg == nil {
|
||||||
|
if pg, err = f.page(pi); err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nc := copy(b[:mathutil.Min(rem, f.pgSize)], pg[po:])
|
||||||
|
pi++
|
||||||
|
po = 0
|
||||||
|
rem -= nc
|
||||||
|
n += nc
|
||||||
|
b = b[nc:]
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) Stat() (os.FileInfo, error) {
|
||||||
|
fi, err := f.f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stat{fi, f.size}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) Truncate(size int64) (err error) {
|
||||||
|
if size < 0 {
|
||||||
|
return fmt.Errorf("invalid truncate size: %d", size)
|
||||||
|
}
|
||||||
|
|
||||||
|
first := size >> f.pgBits
|
||||||
|
if size&int64(f.pgMask) != 0 {
|
||||||
|
first++
|
||||||
|
}
|
||||||
|
last := f.size >> f.pgBits
|
||||||
|
if f.size&int64(f.pgMask) != 0 {
|
||||||
|
last++
|
||||||
|
}
|
||||||
|
for ; first <= last; first++ {
|
||||||
|
if p := f.m[first]; p != nil {
|
||||||
|
if err := p.Unmap(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(f.m, first)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.size = size
|
||||||
|
fsize := (size + int64(f.pgSize) - 1) &^ int64(f.pgMask)
|
||||||
|
if fsize != f.fsize {
|
||||||
|
if err := f.f.Truncate(fsize); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
f.fsize = fsize
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) WriteAt(b []byte, off int64) (n int, err error) {
|
||||||
|
pi := off >> f.pgBits
|
||||||
|
po := int(off) & f.pgMask
|
||||||
|
n = len(b)
|
||||||
|
rem := n
|
||||||
|
var nc int
|
||||||
|
for rem != 0 {
|
||||||
|
pg := f.m[pi]
|
||||||
|
if pg == nil {
|
||||||
|
pg, err = f.page(pi)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nc = copy(pg[po:], b)
|
||||||
|
pi++
|
||||||
|
po = 0
|
||||||
|
rem -= nc
|
||||||
|
b = b[nc:]
|
||||||
|
}
|
||||||
|
f.size = mathutil.MaxInt64(f.size, off+int64(n))
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func readFrom(f Interface, r io.Reader) (n int64, err error) {
|
||||||
|
f.Truncate(0)
|
||||||
|
p := buffer.Get(copyBufSize)
|
||||||
|
b := *p
|
||||||
|
defer buffer.Put(p)
|
||||||
|
|
||||||
|
var off int64
|
||||||
|
var werr error
|
||||||
|
for {
|
||||||
|
rn, rerr := r.Read(b)
|
||||||
|
if rn != 0 {
|
||||||
|
_, werr = f.WriteAt(b[:rn], off)
|
||||||
|
n += int64(rn)
|
||||||
|
off += int64(rn)
|
||||||
|
}
|
||||||
|
if rerr != nil {
|
||||||
|
if !fileutil.IsEOF(rerr) {
|
||||||
|
err = rerr
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if werr != nil {
|
||||||
|
err = werr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeTo(f Interface, w io.Writer) (n int64, err error) {
|
||||||
|
p := buffer.Get(copyBufSize)
|
||||||
|
b := *p
|
||||||
|
defer buffer.Put(p)
|
||||||
|
|
||||||
|
var off int64
|
||||||
|
var werr error
|
||||||
|
for {
|
||||||
|
rn, rerr := f.ReadAt(b, off)
|
||||||
|
if rn != 0 {
|
||||||
|
_, werr = w.Write(b[:rn])
|
||||||
|
n += int64(rn)
|
||||||
|
off += int64(rn)
|
||||||
|
}
|
||||||
|
if rerr != nil {
|
||||||
|
if !fileutil.IsEOF(rerr) {
|
||||||
|
err = rerr
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if werr != nil {
|
||||||
|
err = werr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
27
vendor/github.com/cznic/internal/slice/LICENSE
generated
vendored
Normal file
27
vendor/github.com/cznic/internal/slice/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2016 The Internal Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the names of the authors nor the names of the
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
173
vendor/github.com/cznic/internal/slice/pool.go
generated
vendored
Normal file
173
vendor/github.com/cznic/internal/slice/pool.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright 2016 The Internal 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 slice implements pools of pointers to slices.
|
||||||
|
package slice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/cznic/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Bytes is a ready to use *[]byte Pool.
|
||||||
|
Bytes *Pool
|
||||||
|
// Ints is a ready to use *[]int Pool.
|
||||||
|
Ints *Pool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Bytes = newBytes()
|
||||||
|
Ints = NewPool(
|
||||||
|
func(size int) interface{} { // create
|
||||||
|
b := make([]int, size)
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
func(s interface{}) { // clear
|
||||||
|
b := *s.(*[]int)
|
||||||
|
b = b[:cap(b)]
|
||||||
|
for i := range b {
|
||||||
|
b[i] = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(s interface{}, size int) { // setSize
|
||||||
|
p := s.(*[]int)
|
||||||
|
*p = (*p)[:size]
|
||||||
|
},
|
||||||
|
func(s interface{}) int { return cap(*s.(*[]int)) }, // cap
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBytes() *Pool {
|
||||||
|
return NewPool(
|
||||||
|
func(size int) interface{} { // create
|
||||||
|
b := make([]byte, size)
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
func(s interface{}) { // clear
|
||||||
|
b := *s.(*[]byte)
|
||||||
|
b = b[:cap(b)]
|
||||||
|
for i := range b {
|
||||||
|
b[i] = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(s interface{}, size int) { // setSize
|
||||||
|
p := s.(*[]byte)
|
||||||
|
*p = (*p)[:size]
|
||||||
|
},
|
||||||
|
func(s interface{}) int { return cap(*s.(*[]byte)) }, // cap
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pool implements a pool of pointers to slices.
|
||||||
|
//
|
||||||
|
// Example usage pattern (assuming pool is, for example, a *[]byte Pool)
|
||||||
|
//
|
||||||
|
// p := pool.Get(size).(*[]byte)
|
||||||
|
// b := *p // Now you can use b in any way you need.
|
||||||
|
// ...
|
||||||
|
// // When b will not be used anymore
|
||||||
|
// pool.Put(p)
|
||||||
|
// ...
|
||||||
|
// // If b or p are not going out of scope soon, optionally
|
||||||
|
// b = nil
|
||||||
|
// p = nil
|
||||||
|
//
|
||||||
|
// Otherwise the pool cannot release the slice on garbage collection.
|
||||||
|
//
|
||||||
|
// Do not do
|
||||||
|
//
|
||||||
|
// p := pool.Get(size).(*[]byte)
|
||||||
|
// b := *p
|
||||||
|
// ...
|
||||||
|
// pool.Put(&b)
|
||||||
|
//
|
||||||
|
// or
|
||||||
|
//
|
||||||
|
// b := *pool.Get(size).(*[]byte)
|
||||||
|
// ...
|
||||||
|
// pool.Put(&b)
|
||||||
|
type Pool struct {
|
||||||
|
cap func(interface{}) int
|
||||||
|
clear func(interface{})
|
||||||
|
m [63]sync.Pool
|
||||||
|
null interface{}
|
||||||
|
setSize func(interface{}, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPool returns a newly created Pool. Assuming the desired slice type is
|
||||||
|
// []T:
|
||||||
|
//
|
||||||
|
// The create function returns a *[]T of len == cap == size.
|
||||||
|
//
|
||||||
|
// The argument of clear is *[]T and the function sets all the slice elements
|
||||||
|
// to the respective zero value.
|
||||||
|
//
|
||||||
|
// The setSize function gets a *[]T and sets its len to size.
|
||||||
|
//
|
||||||
|
// The cap function gets a *[]T and returns its capacity.
|
||||||
|
func NewPool(
|
||||||
|
create func(size int) interface{},
|
||||||
|
clear func(interface{}),
|
||||||
|
setSize func(p interface{}, size int),
|
||||||
|
cap func(p interface{}) int,
|
||||||
|
) *Pool {
|
||||||
|
p := &Pool{clear: clear, setSize: setSize, cap: cap, null: create(0)}
|
||||||
|
for i := range p.m {
|
||||||
|
size := 1 << uint(i)
|
||||||
|
p.m[i] = sync.Pool{New: func() interface{} {
|
||||||
|
// 0: 1 - 1
|
||||||
|
// 1: 10 - 10
|
||||||
|
// 2: 11 - 100
|
||||||
|
// 3: 101 - 1000
|
||||||
|
// 4: 1001 - 10000
|
||||||
|
// 5: 10001 - 100000
|
||||||
|
return create(size)
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// CGet returns a *[]T of len size. The pointed to slice is zeroed up to its
|
||||||
|
// cap. CGet panics for size < 0.
|
||||||
|
//
|
||||||
|
// CGet is safe for concurrent use by multiple goroutines.
|
||||||
|
func (p *Pool) CGet(size int) interface{} {
|
||||||
|
s := p.Get(size)
|
||||||
|
p.clear(s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a *[]T of len size. The pointed to slice is not zeroed. Get
|
||||||
|
// panics for size < 0.
|
||||||
|
//
|
||||||
|
// Get is safe for concurrent use by multiple goroutines.
|
||||||
|
func (p *Pool) Get(size int) interface{} {
|
||||||
|
var index int
|
||||||
|
switch {
|
||||||
|
case size < 0:
|
||||||
|
panic("Pool.Get: negative size")
|
||||||
|
case size == 0:
|
||||||
|
return p.null
|
||||||
|
case size > 1:
|
||||||
|
index = mathutil.Log2Uint64(uint64(size-1)) + 1
|
||||||
|
}
|
||||||
|
s := p.m[index].Get()
|
||||||
|
p.setSize(s, size)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put puts a *[]T into a pool for possible later reuse by CGet or Get. Put
|
||||||
|
// panics is its argument is not of type *[]T.
|
||||||
|
//
|
||||||
|
// Put is safe for concurrent use by multiple goroutines.
|
||||||
|
func (p *Pool) Put(b interface{}) {
|
||||||
|
size := p.cap(b)
|
||||||
|
if size == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.m[mathutil.Log2Uint64(uint64(size))].Put(b)
|
||||||
|
}
|
324
vendor/github.com/cznic/lldb/2pc.go
generated
vendored
Normal file
324
vendor/github.com/cznic/lldb/2pc.go
generated
vendored
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
// 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.newEpoch {
|
||||||
|
f.newEpoch = false
|
||||||
|
f.data = f.data[:0]
|
||||||
|
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
|
||||||
|
bwal *bufio.Writer
|
||||||
|
data []acidWrite
|
||||||
|
newEpoch bool
|
||||||
|
peakBitFilerPages int // track maximum transaction memory
|
||||||
|
peakWal int64 // tracks WAL maximum used size
|
||||||
|
testHook bool // keeps WAL untruncated (once)
|
||||||
|
wal *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.bwal = bufio.NewWriter(r.wal)
|
||||||
|
r.newEpoch = true
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = r.wal.Sync(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wfi, err := r.wal.Stat()
|
||||||
|
if err == nil {
|
||||||
|
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
|
||||||
|
r.bwal.Reset(r.wal)
|
||||||
|
r.newEpoch = true
|
||||||
|
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/lldb/2pc_docs.go
generated
vendored
Normal file
44
vendor/github.com/cznic/lldb/2pc_docs.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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
|
27
vendor/github.com/cznic/lldb/LICENSE
generated
vendored
Normal file
27
vendor/github.com/cznic/lldb/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2014 The lldb Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the names of the authors nor the names of the
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2344
vendor/github.com/cznic/lldb/btree.go
generated
vendored
Normal file
2344
vendor/github.com/cznic/lldb/btree.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
170
vendor/github.com/cznic/lldb/errors.go
generated
vendored
Normal file
170
vendor/github.com/cznic/lldb/errors.go
generated
vendored
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
// 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)
|
||||||
|
}
|
1999
vendor/github.com/cznic/lldb/falloc.go
generated
vendored
Normal file
1999
vendor/github.com/cznic/lldb/falloc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
192
vendor/github.com/cznic/lldb/filer.go
generated
vendored
Normal file
192
vendor/github.com/cznic/lldb/filer.go
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
// 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/lldb/gb.go
generated
vendored
Normal file
812
vendor/github.com/cznic/lldb/gb.go
generated
vendored
Normal file
@ -0,0 +1,812 @@
|
|||||||
|
// 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
|
||||||
|
}
|
160
vendor/github.com/cznic/lldb/lldb.go
generated
vendored
Normal file
160
vendor/github.com/cznic/lldb/lldb.go
generated
vendored
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
// 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 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).
|
||||||
|
//
|
||||||
|
// Changelog
|
||||||
|
//
|
||||||
|
// 2016-07-24: v1.0.4 brings some performance improvements.
|
||||||
|
//
|
||||||
|
// 2016-07-22: v1.0.3 brings some small performance improvements.
|
||||||
|
//
|
||||||
|
// 2016-07-12: v1.0.2 now uses packages from cznic/internal.
|
||||||
|
//
|
||||||
|
// 2016-07-12: v1.0.1 adds a license for testdata/fortunes.txt.
|
||||||
|
//
|
||||||
|
// 2016-07-11: First standalone release v1.0.0 of the package previously
|
||||||
|
// published as experimental (github.com/cznic/exp/lldb).
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
}
|
107
vendor/github.com/cznic/lldb/memfiler.go
generated
vendored
Normal file
107
vendor/github.com/cznic/lldb/memfiler.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package lldb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/cznic/internal/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
pgBits = 16
|
||||||
|
pgSize = 1 << pgBits
|
||||||
|
pgMask = pgSize - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Filer = &MemFiler{}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
fi file.Interface
|
||||||
|
nest int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemFiler returns a new MemFiler.
|
||||||
|
func NewMemFiler() *MemFiler {
|
||||||
|
fi, err := file.OpenMem("")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MemFiler{fi: fi}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 f.fi.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) { return nil }
|
||||||
|
|
||||||
|
// ReadAt implements Filer.
|
||||||
|
func (f *MemFiler) ReadAt(b []byte, off int64) (n int, err error) { return f.fi.ReadAt(b, off) }
|
||||||
|
|
||||||
|
// 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) { return f.fi.ReadFrom(r) }
|
||||||
|
|
||||||
|
// Rollback implements Filer.
|
||||||
|
func (f *MemFiler) Rollback() (err error) { return nil }
|
||||||
|
|
||||||
|
// Size implements Filer.
|
||||||
|
func (f *MemFiler) Size() (int64, error) {
|
||||||
|
info, err := f.fi.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return info.Size(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync implements Filer.
|
||||||
|
func (f *MemFiler) Sync() error { return nil }
|
||||||
|
|
||||||
|
// Truncate implements Filer.
|
||||||
|
func (f *MemFiler) Truncate(size int64) (err error) { return f.fi.Truncate(size) }
|
||||||
|
|
||||||
|
// WriteAt implements Filer.
|
||||||
|
func (f *MemFiler) WriteAt(b []byte, off int64) (n int, err error) { return f.fi.WriteAt(b, off) }
|
||||||
|
|
||||||
|
// 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) { return f.fi.WriteTo(w) }
|
130
vendor/github.com/cznic/lldb/osfiler.go
generated
vendored
Normal file
130
vendor/github.com/cznic/lldb/osfiler.go
generated
vendored
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// 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)
|
||||||
|
}
|
99
vendor/github.com/cznic/lldb/simplefilefiler.go
generated
vendored
Normal file
99
vendor/github.com/cznic/lldb/simplefilefiler.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// 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/internal/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Filer = &SimpleFileFiler{}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
fi file.Interface
|
||||||
|
name string
|
||||||
|
nest int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSimpleFileFiler returns a new SimpleFileFiler.
|
||||||
|
func NewSimpleFileFiler(f *os.File) *SimpleFileFiler {
|
||||||
|
fi, err := file.Open(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sf := &SimpleFileFiler{fi: fi, name: f.Name()}
|
||||||
|
return sf
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.fi.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.name }
|
||||||
|
|
||||||
|
// PunchHole implements Filer.
|
||||||
|
func (f *SimpleFileFiler) PunchHole(off, size int64) (err error) { return nil }
|
||||||
|
|
||||||
|
// ReadAt implements Filer.
|
||||||
|
func (f *SimpleFileFiler) ReadAt(b []byte, off int64) (n int, err error) { return f.fi.ReadAt(b, off) }
|
||||||
|
|
||||||
|
// Rollback implements Filer.
|
||||||
|
func (f *SimpleFileFiler) Rollback() (err error) { return nil }
|
||||||
|
|
||||||
|
// Size implements Filer.
|
||||||
|
func (f *SimpleFileFiler) Size() (int64, error) {
|
||||||
|
info, err := f.fi.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return info.Size(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync implements Filer.
|
||||||
|
func (f *SimpleFileFiler) Sync() error { return f.fi.Sync() }
|
||||||
|
|
||||||
|
// Truncate implements Filer.
|
||||||
|
func (f *SimpleFileFiler) Truncate(size int64) (err error) { return f.fi.Truncate(size) }
|
||||||
|
|
||||||
|
// WriteAt implements Filer.
|
||||||
|
func (f *SimpleFileFiler) WriteAt(b []byte, off int64) (n int, err error) { return f.fi.WriteAt(b, off) }
|
616
vendor/github.com/cznic/lldb/xact.go
generated
vendored
Normal file
616
vendor/github.com/cznic/lldb/xact.go
generated
vendored
Normal file
@ -0,0 +1,616 @@
|
|||||||
|
// 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/internal/buffer"
|
||||||
|
"github.com/cznic/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ Filer = &bitFiler{} // Ensure bitFiler is a Filer.
|
||||||
|
_ Filer = &RollbackFiler{} // ditto
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bfBits = 12
|
||||||
|
bfSize = 1 << bfBits
|
||||||
|
bfMask = bfSize - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
bitPage struct {
|
||||||
|
prev, next *bitPage
|
||||||
|
pdata *[]byte
|
||||||
|
data []byte
|
||||||
|
dirty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
bitFilerMap map[int64]*bitPage
|
||||||
|
|
||||||
|
bitFiler struct {
|
||||||
|
parent Filer
|
||||||
|
m bitFilerMap
|
||||||
|
size int64
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
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) free() {
|
||||||
|
for _, pg := range f.m {
|
||||||
|
buffer.Put(pg.pdata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
for pgI := first; pgI <= last; pgI++ {
|
||||||
|
pg := &bitPage{}
|
||||||
|
pg.pdata = buffer.CGet(bfSize)
|
||||||
|
pg.data = *pg.pdata
|
||||||
|
pg.dirty = true
|
||||||
|
f.m[pgI] = pg
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
pg := f.m[pgI]
|
||||||
|
if pg == nil {
|
||||||
|
pg = &bitPage{}
|
||||||
|
pg.pdata = buffer.CGet(bfSize)
|
||||||
|
pg.data = *pg.pdata
|
||||||
|
if f.parent != nil {
|
||||||
|
_, err = f.parent.ReadAt(pg.data, off&^bfMask)
|
||||||
|
if err != nil && !fileutil.IsEOF(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
f.m[pgI] = pg
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
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++ {
|
||||||
|
if bp, ok := f.m[first]; ok {
|
||||||
|
buffer.Put(bp.pdata)
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
pg := f.m[pgI]
|
||||||
|
if pg == nil {
|
||||||
|
pg = &bitPage{}
|
||||||
|
pg.pdata = buffer.CGet(bfSize)
|
||||||
|
pg.data = *pg.pdata
|
||||||
|
if f.parent != nil {
|
||||||
|
_, err = f.parent.ReadAt(pg.data, off&^bfMask)
|
||||||
|
if err != nil && !fileutil.IsEOF(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
f.m[pgI] = pg
|
||||||
|
}
|
||||||
|
nc = copy(pg.data[pgO:], b)
|
||||||
|
pgI++
|
||||||
|
pg.dirty = true
|
||||||
|
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.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 {
|
||||||
|
if _, err := w.WriteAt(pg.data, pgI<<bfBits); err != nil {
|
||||||
|
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"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.bitFiler != nil {
|
||||||
|
r.bitFiler.free()
|
||||||
|
r.bitFiler = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
defer func() {
|
||||||
|
r.bitFiler.free()
|
||||||
|
r.bitFiler = nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
if nwr == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.checkpoint(sz)
|
||||||
|
default:
|
||||||
|
r.bitFiler.free()
|
||||||
|
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.free()
|
||||||
|
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)
|
||||||
|
}
|
25
vendor/github.com/edsrzf/mmap-go/LICENSE
generated
vendored
Normal file
25
vendor/github.com/edsrzf/mmap-go/LICENSE
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2011, Evan Shaw <edsrzf@gmail.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
112
vendor/github.com/edsrzf/mmap-go/mmap.go
generated
vendored
Normal file
112
vendor/github.com/edsrzf/mmap-go/mmap.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Copyright 2011 Evan Shaw. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file defines the common package interface and contains a little bit of
|
||||||
|
// factored out logic.
|
||||||
|
|
||||||
|
// Package mmap allows mapping files into memory. It tries to provide a simple, reasonably portable interface,
|
||||||
|
// but doesn't go out of its way to abstract away every little platform detail.
|
||||||
|
// This specifically means:
|
||||||
|
// * forked processes may or may not inherit mappings
|
||||||
|
// * a file's timestamp may or may not be updated by writes through mappings
|
||||||
|
// * specifying a size larger than the file's actual size can increase the file's size
|
||||||
|
// * If the mapped file is being modified by another process while your program's running, don't expect consistent results between platforms
|
||||||
|
package mmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RDONLY maps the memory read-only.
|
||||||
|
// Attempts to write to the MMap object will result in undefined behavior.
|
||||||
|
RDONLY = 0
|
||||||
|
// RDWR maps the memory as read-write. Writes to the MMap object will update the
|
||||||
|
// underlying file.
|
||||||
|
RDWR = 1 << iota
|
||||||
|
// COPY maps the memory as copy-on-write. Writes to the MMap object will affect
|
||||||
|
// memory, but the underlying file will remain unchanged.
|
||||||
|
COPY
|
||||||
|
// If EXEC is set, the mapped memory is marked as executable.
|
||||||
|
EXEC
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// If the ANON flag is set, the mapped memory will not be backed by a file.
|
||||||
|
ANON = 1 << iota
|
||||||
|
)
|
||||||
|
|
||||||
|
// MMap represents a file mapped into memory.
|
||||||
|
type MMap []byte
|
||||||
|
|
||||||
|
// Map maps an entire file into memory.
|
||||||
|
// If ANON is set in flags, f is ignored.
|
||||||
|
func Map(f *os.File, prot, flags int) (MMap, error) {
|
||||||
|
return MapRegion(f, -1, prot, flags, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapRegion maps part of a file into memory.
|
||||||
|
// The offset parameter must be a multiple of the system's page size.
|
||||||
|
// If length < 0, the entire file will be mapped.
|
||||||
|
// If ANON is set in flags, f is ignored.
|
||||||
|
func MapRegion(f *os.File, length int, prot, flags int, offset int64) (MMap, error) {
|
||||||
|
var fd uintptr
|
||||||
|
if flags&ANON == 0 {
|
||||||
|
fd = uintptr(f.Fd())
|
||||||
|
if length < 0 {
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
length = int(fi.Size())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if length <= 0 {
|
||||||
|
return nil, errors.New("anonymous mapping requires non-zero length")
|
||||||
|
}
|
||||||
|
fd = ^uintptr(0)
|
||||||
|
}
|
||||||
|
return mmap(length, uintptr(prot), uintptr(flags), fd, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MMap) header() *reflect.SliceHeader {
|
||||||
|
return (*reflect.SliceHeader)(unsafe.Pointer(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock keeps the mapped region in physical memory, ensuring that it will not be
|
||||||
|
// swapped out.
|
||||||
|
func (m MMap) Lock() error {
|
||||||
|
dh := m.header()
|
||||||
|
return lock(dh.Data, uintptr(dh.Len))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock reverses the effect of Lock, allowing the mapped region to potentially
|
||||||
|
// be swapped out.
|
||||||
|
// If m is already unlocked, aan error will result.
|
||||||
|
func (m MMap) Unlock() error {
|
||||||
|
dh := m.header()
|
||||||
|
return unlock(dh.Data, uintptr(dh.Len))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush synchronizes the mapping's contents to the file's contents on disk.
|
||||||
|
func (m MMap) Flush() error {
|
||||||
|
dh := m.header()
|
||||||
|
return flush(dh.Data, uintptr(dh.Len))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap deletes the memory mapped region, flushes any remaining changes, and sets
|
||||||
|
// m to nil.
|
||||||
|
// Trying to read or write any remaining references to m after Unmap is called will
|
||||||
|
// result in undefined behavior.
|
||||||
|
// Unmap should only be called on the slice value that was originally returned from
|
||||||
|
// a call to Map. Calling Unmap on a derived slice may cause errors.
|
||||||
|
func (m *MMap) Unmap() error {
|
||||||
|
dh := m.header()
|
||||||
|
err := unmap(dh.Data, uintptr(dh.Len))
|
||||||
|
*m = nil
|
||||||
|
return err
|
||||||
|
}
|
67
vendor/github.com/edsrzf/mmap-go/mmap_unix.go
generated
vendored
Normal file
67
vendor/github.com/edsrzf/mmap-go/mmap_unix.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2011 Evan Shaw. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build darwin dragonfly freebsd linux openbsd solaris netbsd
|
||||||
|
|
||||||
|
package mmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mmap(len int, inprot, inflags, fd uintptr, off int64) ([]byte, error) {
|
||||||
|
flags := syscall.MAP_SHARED
|
||||||
|
prot := syscall.PROT_READ
|
||||||
|
switch {
|
||||||
|
case inprot© != 0:
|
||||||
|
prot |= syscall.PROT_WRITE
|
||||||
|
flags = syscall.MAP_PRIVATE
|
||||||
|
case inprot&RDWR != 0:
|
||||||
|
prot |= syscall.PROT_WRITE
|
||||||
|
}
|
||||||
|
if inprot&EXEC != 0 {
|
||||||
|
prot |= syscall.PROT_EXEC
|
||||||
|
}
|
||||||
|
if inflags&ANON != 0 {
|
||||||
|
flags |= syscall.MAP_ANON
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := syscall.Mmap(int(fd), off, len, prot, flags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func flush(addr, len uintptr) error {
|
||||||
|
_, _, errno := syscall.Syscall(_SYS_MSYNC, addr, len, _MS_SYNC)
|
||||||
|
if errno != 0 {
|
||||||
|
return syscall.Errno(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lock(addr, len uintptr) error {
|
||||||
|
_, _, errno := syscall.Syscall(syscall.SYS_MLOCK, addr, len, 0)
|
||||||
|
if errno != 0 {
|
||||||
|
return syscall.Errno(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(addr, len uintptr) error {
|
||||||
|
_, _, errno := syscall.Syscall(syscall.SYS_MUNLOCK, addr, len, 0)
|
||||||
|
if errno != 0 {
|
||||||
|
return syscall.Errno(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmap(addr, len uintptr) error {
|
||||||
|
_, _, errno := syscall.Syscall(syscall.SYS_MUNMAP, addr, len, 0)
|
||||||
|
if errno != 0 {
|
||||||
|
return syscall.Errno(errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
125
vendor/github.com/edsrzf/mmap-go/mmap_windows.go
generated
vendored
Normal file
125
vendor/github.com/edsrzf/mmap-go/mmap_windows.go
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// Copyright 2011 Evan Shaw. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package mmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mmap on Windows is a two-step process.
|
||||||
|
// First, we call CreateFileMapping to get a handle.
|
||||||
|
// Then, we call MapviewToFile to get an actual pointer into memory.
|
||||||
|
// Because we want to emulate a POSIX-style mmap, we don't want to expose
|
||||||
|
// the handle -- only the pointer. We also want to return only a byte slice,
|
||||||
|
// not a struct, so it's convenient to manipulate.
|
||||||
|
|
||||||
|
// We keep this map so that we can get back the original handle from the memory address.
|
||||||
|
var handleLock sync.Mutex
|
||||||
|
var handleMap = map[uintptr]syscall.Handle{}
|
||||||
|
|
||||||
|
func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) {
|
||||||
|
flProtect := uint32(syscall.PAGE_READONLY)
|
||||||
|
dwDesiredAccess := uint32(syscall.FILE_MAP_READ)
|
||||||
|
switch {
|
||||||
|
case prot© != 0:
|
||||||
|
flProtect = syscall.PAGE_WRITECOPY
|
||||||
|
dwDesiredAccess = syscall.FILE_MAP_COPY
|
||||||
|
case prot&RDWR != 0:
|
||||||
|
flProtect = syscall.PAGE_READWRITE
|
||||||
|
dwDesiredAccess = syscall.FILE_MAP_WRITE
|
||||||
|
}
|
||||||
|
if prot&EXEC != 0 {
|
||||||
|
flProtect <<= 4
|
||||||
|
dwDesiredAccess |= syscall.FILE_MAP_EXECUTE
|
||||||
|
}
|
||||||
|
|
||||||
|
// The maximum size is the area of the file, starting from 0,
|
||||||
|
// that we wish to allow to be mappable. It is the sum of
|
||||||
|
// the length the user requested, plus the offset where that length
|
||||||
|
// is starting from. This does not map the data into memory.
|
||||||
|
maxSizeHigh := uint32((off + int64(len)) >> 32)
|
||||||
|
maxSizeLow := uint32((off + int64(len)) & 0xFFFFFFFF)
|
||||||
|
// TODO: Do we need to set some security attributes? It might help portability.
|
||||||
|
h, errno := syscall.CreateFileMapping(syscall.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil)
|
||||||
|
if h == 0 {
|
||||||
|
return nil, os.NewSyscallError("CreateFileMapping", errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually map a view of the data into memory. The view's size
|
||||||
|
// is the length the user requested.
|
||||||
|
fileOffsetHigh := uint32(off >> 32)
|
||||||
|
fileOffsetLow := uint32(off & 0xFFFFFFFF)
|
||||||
|
addr, errno := syscall.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len))
|
||||||
|
if addr == 0 {
|
||||||
|
return nil, os.NewSyscallError("MapViewOfFile", errno)
|
||||||
|
}
|
||||||
|
handleLock.Lock()
|
||||||
|
handleMap[addr] = h
|
||||||
|
handleLock.Unlock()
|
||||||
|
|
||||||
|
m := MMap{}
|
||||||
|
dh := m.header()
|
||||||
|
dh.Data = addr
|
||||||
|
dh.Len = len
|
||||||
|
dh.Cap = dh.Len
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func flush(addr, len uintptr) error {
|
||||||
|
errno := syscall.FlushViewOfFile(addr, len)
|
||||||
|
if errno != nil {
|
||||||
|
return os.NewSyscallError("FlushViewOfFile", errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLock.Lock()
|
||||||
|
defer handleLock.Unlock()
|
||||||
|
handle, ok := handleMap[addr]
|
||||||
|
if !ok {
|
||||||
|
// should be impossible; we would've errored above
|
||||||
|
return errors.New("unknown base address")
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = syscall.FlushFileBuffers(handle)
|
||||||
|
return os.NewSyscallError("FlushFileBuffers", errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lock(addr, len uintptr) error {
|
||||||
|
errno := syscall.VirtualLock(addr, len)
|
||||||
|
return os.NewSyscallError("VirtualLock", errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(addr, len uintptr) error {
|
||||||
|
errno := syscall.VirtualUnlock(addr, len)
|
||||||
|
return os.NewSyscallError("VirtualUnlock", errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmap(addr, len uintptr) error {
|
||||||
|
flush(addr, len)
|
||||||
|
// Lock the UnmapViewOfFile along with the handleMap deletion.
|
||||||
|
// As soon as we unmap the view, the OS is free to give the
|
||||||
|
// same addr to another new map. We don't want another goroutine
|
||||||
|
// to insert and remove the same addr into handleMap while
|
||||||
|
// we're trying to remove our old addr/handle pair.
|
||||||
|
handleLock.Lock()
|
||||||
|
defer handleLock.Unlock()
|
||||||
|
err := syscall.UnmapViewOfFile(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
handle, ok := handleMap[addr]
|
||||||
|
if !ok {
|
||||||
|
// should be impossible; we would've errored above
|
||||||
|
return errors.New("unknown base address")
|
||||||
|
}
|
||||||
|
delete(handleMap, addr)
|
||||||
|
|
||||||
|
e := syscall.CloseHandle(syscall.Handle(handle))
|
||||||
|
return os.NewSyscallError("CloseHandle", e)
|
||||||
|
}
|
8
vendor/github.com/edsrzf/mmap-go/msync_netbsd.go
generated
vendored
Normal file
8
vendor/github.com/edsrzf/mmap-go/msync_netbsd.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2011 Evan Shaw. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package mmap
|
||||||
|
|
||||||
|
const _SYS_MSYNC = 277
|
||||||
|
const _MS_SYNC = 0x04
|
14
vendor/github.com/edsrzf/mmap-go/msync_unix.go
generated
vendored
Normal file
14
vendor/github.com/edsrzf/mmap-go/msync_unix.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2011 Evan Shaw. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build darwin dragonfly freebsd linux openbsd solaris
|
||||||
|
|
||||||
|
package mmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const _SYS_MSYNC = syscall.SYS_MSYNC
|
||||||
|
const _MS_SYNC = syscall.MS_SYNC
|
38
vendor/manifest
vendored
38
vendor/manifest
vendored
@ -52,6 +52,37 @@
|
|||||||
"branch": "master",
|
"branch": "master",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/cznic/internal/buffer",
|
||||||
|
"repository": "https://github.com/cznic/internal",
|
||||||
|
"revision": "cef02a853c3a93623c42eacd574e7ea05f55531b",
|
||||||
|
"branch": "master",
|
||||||
|
"path": "/buffer",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/cznic/internal/file",
|
||||||
|
"repository": "https://github.com/cznic/internal",
|
||||||
|
"revision": "cef02a853c3a93623c42eacd574e7ea05f55531b",
|
||||||
|
"branch": "master",
|
||||||
|
"path": "/file",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/cznic/internal/slice",
|
||||||
|
"repository": "https://github.com/cznic/internal",
|
||||||
|
"revision": "cef02a853c3a93623c42eacd574e7ea05f55531b",
|
||||||
|
"branch": "master",
|
||||||
|
"path": "/slice",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/cznic/lldb",
|
||||||
|
"repository": "https://github.com/cznic/lldb",
|
||||||
|
"revision": "7376b3bed3d27a7b640e264bfaf278d6d5232550",
|
||||||
|
"branch": "master",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "github.com/cznic/mathutil",
|
"importpath": "github.com/cznic/mathutil",
|
||||||
"repository": "https://github.com/cznic/mathutil",
|
"repository": "https://github.com/cznic/mathutil",
|
||||||
@ -93,6 +124,13 @@
|
|||||||
"revision": "bf29d7cd9038386a5b4a22e2d73c8fb20ae14602",
|
"revision": "bf29d7cd9038386a5b4a22e2d73c8fb20ae14602",
|
||||||
"branch": "master"
|
"branch": "master"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/edsrzf/mmap-go",
|
||||||
|
"repository": "https://github.com/edsrzf/mmap-go",
|
||||||
|
"revision": "935e0e8a636ca4ba70b713f3e38a19e1b77739e8",
|
||||||
|
"branch": "master",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "github.com/gobwas/glob",
|
"importpath": "github.com/gobwas/glob",
|
||||||
"repository": "https://github.com/gobwas/glob",
|
"repository": "https://github.com/gobwas/glob",
|
||||||
|
Loading…
Reference in New Issue
Block a user