Merge branch 'tuple-uint64' into feature-bigint-support-go-ruby
# Conflicts: # bindings/go/src/fdb/tuple/tuple.go
This commit is contained in:
commit
42d101c517
|
@ -286,6 +286,8 @@ func (ri *RangeIterator) MustGet() KeyValue {
|
|||
return kv
|
||||
}
|
||||
|
||||
// Strinc returns the first key that would sort outside the range prefixed by
|
||||
// prefix, or an error if prefix is empty or contains only 0xFF bytes.
|
||||
func Strinc(prefix []byte) ([]byte, error) {
|
||||
for i := len(prefix) - 1; i >= 0; i-- {
|
||||
if prefix[i] != 0xFF {
|
||||
|
@ -311,7 +313,7 @@ func PrefixRange(prefix []byte) (KeyRange, error) {
|
|||
copy(begin, prefix)
|
||||
end, e := Strinc(begin)
|
||||
if e != nil {
|
||||
return KeyRange{}, nil
|
||||
return KeyRange{}, e
|
||||
}
|
||||
return KeyRange{Key(begin), Key(end)}, nil
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
// FoundationDB tuples can currently encode byte and unicode strings, integers,
|
||||
// large integers, floats, doubles, booleans, UUIDs, tuples, and NULL values.
|
||||
// In Go these are represented as []byte (or fdb.KeyConvertible), string, int64
|
||||
// (or int, uint, uint64), *big.Int (or big.Int, uint64), float32, float64, bool,
|
||||
// (or int, uint, uint64), *big.Int (or big.Int), float32, float64, bool,
|
||||
// UUID, Tuple, and nil.
|
||||
package tuple
|
||||
|
||||
|
@ -52,8 +52,8 @@ import (
|
|||
// result in a runtime panic).
|
||||
//
|
||||
// The valid types for TupleElement are []byte (or fdb.KeyConvertible), string,
|
||||
// int64 (or int, uint, uint64), *big.Int (or big.Int, uint64), float, double,
|
||||
// bool, UUID, Tuple, and nil.
|
||||
// int64 (or int, uint, uint64), *big.Int (or big.Int), float, double, bool,
|
||||
// UUID, Tuple, and nil.
|
||||
type TupleElement interface{}
|
||||
|
||||
// Tuple is a slice of objects that can be encoded as FoundationDB tuples. If
|
||||
|
@ -62,7 +62,7 @@ type TupleElement interface{}
|
|||
//
|
||||
// Given a Tuple T containing objects only of these types, then T will be
|
||||
// identical to the Tuple returned by unpacking the byte slice obtained by
|
||||
// packing T (modulo type normalization to []byte and int64).
|
||||
// packing T (modulo type normalization to []byte, uint64, and int64).
|
||||
type Tuple []TupleElement
|
||||
|
||||
// UUID wraps a basic byte array as a UUID. We do not provide any special
|
||||
|
@ -151,36 +151,39 @@ func (p *packer) encodeBytes(code byte, b []byte) {
|
|||
p.putByte(0x00)
|
||||
}
|
||||
|
||||
func (p *packer) encodeInt(i int64) {
|
||||
func (p *packer) encodeUint(i uint64) {
|
||||
if i == 0 {
|
||||
p.putByte(intZeroCode)
|
||||
return
|
||||
}
|
||||
|
||||
var n int
|
||||
n := bisectLeft(i)
|
||||
var scratch [8]byte
|
||||
|
||||
switch {
|
||||
case i > 0:
|
||||
n = bisectLeft(uint64(i))
|
||||
p.putByte(byte(intZeroCode + n))
|
||||
binary.BigEndian.PutUint64(scratch[:], uint64(i))
|
||||
case i < 0:
|
||||
n = bisectLeft(uint64(-i))
|
||||
p.putByte(byte(intZeroCode - n))
|
||||
offsetEncoded := int64(sizeLimits[n]) + i
|
||||
binary.BigEndian.PutUint64(scratch[:], uint64(offsetEncoded))
|
||||
p.putByte(byte(intZeroCode + n))
|
||||
binary.BigEndian.PutUint64(scratch[:], i)
|
||||
|
||||
p.putBytes(scratch[8-n:])
|
||||
}
|
||||
|
||||
|
||||
func (p *packer) encodeInt(i int64) {
|
||||
if i >= 0 {
|
||||
p.encodeUint(uint64(i))
|
||||
return
|
||||
}
|
||||
|
||||
n := bisectLeft(uint64(-i))
|
||||
var scratch [8]byte
|
||||
|
||||
p.putByte(byte(intZeroCode - n))
|
||||
offsetEncoded := int64(sizeLimits[n]) + i
|
||||
binary.BigEndian.PutUint64(scratch[:], uint64(offsetEncoded))
|
||||
|
||||
p.putBytes(scratch[8-n:])
|
||||
}
|
||||
|
||||
func (p *packer) encodeBigInt(i *big.Int) {
|
||||
if i.Cmp(big.NewInt(math.MaxInt64)) <= 0 && i.Cmp(big.NewInt(math.MinInt64)) >= 0 {
|
||||
p.encodeInt(i.Int64())
|
||||
return
|
||||
}
|
||||
|
||||
length := len(i.Bytes())
|
||||
if length > 0xff {
|
||||
panic(fmt.Sprintf("Integer magnitude is too large (more than 255 bytes)"))
|
||||
|
@ -218,16 +221,6 @@ func (p *packer) encodeBigInt(i *big.Int) {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *packer) encodeUint(i uint64) {
|
||||
if i > math.MaxInt64 {
|
||||
val := new(big.Int)
|
||||
val.SetUint64(i)
|
||||
p.encodeBigInt(val)
|
||||
} else {
|
||||
p.encodeInt(int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *packer) encodeFloat(f float32) {
|
||||
var scratch [4]byte
|
||||
binary.BigEndian.PutUint32(scratch[:], math.Float32bits(f))
|
||||
|
@ -265,14 +258,14 @@ func (p *packer) encodeTuple(t Tuple, nested bool) {
|
|||
if nested {
|
||||
p.putByte(0xff)
|
||||
}
|
||||
case int64:
|
||||
p.encodeInt(e)
|
||||
case uint64:
|
||||
p.encodeUint(e)
|
||||
case int:
|
||||
p.encodeInt(int64(e))
|
||||
case int64:
|
||||
p.encodeInt(e)
|
||||
case uint:
|
||||
p.encodeUint(uint64(e))
|
||||
case uint64:
|
||||
p.encodeUint(e)
|
||||
case *big.Int:
|
||||
p.encodeBigInt(e)
|
||||
case big.Int:
|
||||
|
@ -348,9 +341,9 @@ func decodeString(b []byte) (string, int) {
|
|||
return string(bp), idx
|
||||
}
|
||||
|
||||
func decodeInt(b []byte) (int64, int) {
|
||||
func decodeInt(b []byte) (interface{}, int) {
|
||||
if b[0] == intZeroCode {
|
||||
return 0, 1
|
||||
return int64(0), 1
|
||||
}
|
||||
|
||||
var neg bool
|
||||
|
@ -365,14 +358,17 @@ func decodeInt(b []byte) (int64, int) {
|
|||
copy(bp[8-n:], b[1:n+1])
|
||||
|
||||
var ret int64
|
||||
|
||||
binary.Read(bytes.NewBuffer(bp), binary.BigEndian, &ret)
|
||||
|
||||
if neg {
|
||||
ret -= int64(sizeLimits[n])
|
||||
return ret - int64(sizeLimits[n]), n + 1
|
||||
}
|
||||
|
||||
return ret, n + 1
|
||||
if ret > 0 {
|
||||
return ret, n + 1
|
||||
}
|
||||
|
||||
return uint64(ret), n + 1
|
||||
}
|
||||
|
||||
func decodeBigInt(b []byte) (*big.Int, int) {
|
||||
|
|
|
@ -14,7 +14,7 @@ Documentation
|
|||
|
||||
FoundationDB is a robust choice for a broad range of use cases:
|
||||
|
||||
**Developers can store all types of data.** FoundationDB is multi-model, meaning you can store many types data in a single database. All data is safely stored, distributed, and replicated in FoundationDB.
|
||||
**Developers can store all types of data.** FoundationDB is multi-model, meaning you can store many types of data in a single database. All data is safely stored, distributed, and replicated in FoundationDB.
|
||||
|
||||
**Administrators easily scale and handle hardware failures.** FoundationDB is easy to install, grow, and manage. It has a distributed architecture that gracefully scales out and handles faults while acting like a single ACID database.
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ Anyone who can connect to a FoundationDB cluster can read and write every key in
|
|||
Current limitations
|
||||
===================
|
||||
|
||||
These limitations do not reflect fundamental aspects of our design and are likely be resolved or mitigated in future versions. Administrators should be aware of these issues, but longer-term application development should be less driven by them.
|
||||
These limitations do not reflect fundamental aspects of our design and are likely to be resolved or mitigated in future versions. Administrators should be aware of these issues, but longer-term application development should be less driven by them.
|
||||
|
||||
.. _long-transactions:
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ Bindings
|
|||
* C API calls made on the network thread could be reordered with calls made from other threads. [6.0.2] `(Issue #518) <https://github.com/apple/foundationdb/issues/518>`_
|
||||
* The TLS_PLUGIN option is now a no-op and has been deprecated. [6.0.10] `(PR #710) <https://github.com/apple/foundationdb/pull/710>`_
|
||||
* Java: the `Versionstamp::getUserVersion() </javadoc/com/apple/foundationdb/tuple/Versionstamp.html#getUserVersion-->`_ method did not handle user versions greater than ``0x00FF`` due to operator precedence errors. [6.0.11] `(Issue #761) <https://github.com/apple/foundationdb/issues/761>`_
|
||||
* Python bindings didn't work with Python 3.7 because of the new `async` keyword. [6.0.13] `(Issue #830) <https://github.com/apple/foundationdb/issues/830>`_
|
||||
* Python: bindings didn't work with Python 3.7 because of the new `async` keyword. [6.0.13] `(Issue #830) <https://github.com/apple/foundationdb/issues/830>`_
|
||||
* Go: `PrefixRange` didn't correctly return an error if it failed to generate the range. [6.0.15] `(PR #878) <https://github.com/apple/foundationdb/pull/878>`_
|
||||
|
||||
|
||||
Other Changes
|
||||
|
|
|
@ -58,6 +58,10 @@ struct SyncFileForSim : ReferenceCounted<SyncFileForSim> {
|
|||
f = fopen(filename.c_str(), "wb");
|
||||
}
|
||||
|
||||
virtual bool isOpen() {
|
||||
return f != nullptr;
|
||||
}
|
||||
|
||||
virtual void addref() { ReferenceCounted<SyncFileForSim>::addref(); }
|
||||
virtual void delref() { ReferenceCounted<SyncFileForSim>::delref(); }
|
||||
|
||||
|
@ -69,6 +73,7 @@ struct SyncFileForSim : ReferenceCounted<SyncFileForSim> {
|
|||
}
|
||||
|
||||
virtual Future<Void> write( void const* data, int length, int64_t offset ) {
|
||||
ASSERT(isOpen());
|
||||
fseek(f, offset, SEEK_SET);
|
||||
if (fwrite(data, 1, length, f) != length)
|
||||
throw io_error();
|
||||
|
@ -81,6 +86,7 @@ struct SyncFileForSim : ReferenceCounted<SyncFileForSim> {
|
|||
}
|
||||
|
||||
virtual Future<Void> flush() {
|
||||
ASSERT(isOpen());
|
||||
fflush(f);
|
||||
return Void();
|
||||
}
|
||||
|
@ -125,15 +131,19 @@ struct Profiler {
|
|||
static Profiler* active_profiler;
|
||||
BinaryWriter environmentInfoWriter;
|
||||
INetwork* network;
|
||||
timer_t periodic_timer;
|
||||
timer_t periodicTimer;
|
||||
bool timerInitialized;
|
||||
|
||||
Profiler(int period, std::string const& outfn, INetwork* network) : environmentInfoWriter(Unversioned()), signalClosure(signal_handler_for_closure, this), network(network) {
|
||||
Profiler(int period, std::string const& outfn, INetwork* network) : environmentInfoWriter(Unversioned()), signalClosure(signal_handler_for_closure, this), network(network), timerInitialized(false) {
|
||||
actor = profile(this, period, outfn);
|
||||
}
|
||||
|
||||
~Profiler() {
|
||||
enableSignal(false);
|
||||
timer_delete(periodic_timer);
|
||||
|
||||
if(timerInitialized) {
|
||||
timer_delete(periodicTimer);
|
||||
}
|
||||
}
|
||||
|
||||
void signal_handler() { // async signal safe!
|
||||
|
@ -173,6 +183,13 @@ struct Profiler {
|
|||
}
|
||||
|
||||
ACTOR static Future<Void> profile(Profiler* self, int period, std::string outfn) {
|
||||
// Open and truncate output file
|
||||
state Reference<SyncFileForSim> outFile = Reference<SyncFileForSim>(new SyncFileForSim(outfn));
|
||||
if(!outFile->isOpen()) {
|
||||
TraceEvent(SevWarn, "FailedToOpenProfilingOutputFile").detail("Filename", outfn).GetLastError();
|
||||
return Void();
|
||||
}
|
||||
|
||||
// According to folk wisdom, calling this once before setting up the signal handler makes
|
||||
// it async signal safe in practice :-/
|
||||
platform::raw_backtrace(self->addresses, MAX_STACK_DEPTH);
|
||||
|
@ -201,34 +218,28 @@ struct Profiler {
|
|||
sigaction( SIGPROF, &act, NULL );
|
||||
|
||||
// Set up periodic profiling timer
|
||||
if (0) {
|
||||
itimerval tv;
|
||||
sigevent sev;
|
||||
setitimer( ITIMER_PROF, &tv, NULL );
|
||||
tv.it_interval.tv_sec = 0;
|
||||
tv.it_interval.tv_usec = period;
|
||||
tv.it_value.tv_sec = 0;
|
||||
tv.it_value.tv_usec = g_nondeterministic_random->randomInt(period/2,period+1);
|
||||
setitimer( ITIMER_PROF, &tv, NULL );
|
||||
} else {
|
||||
int period_ns = period * 1000;
|
||||
itimerspec tv;
|
||||
tv.it_interval.tv_sec = 0;
|
||||
tv.it_interval.tv_nsec = period_ns;
|
||||
tv.it_value.tv_sec = 0;
|
||||
tv.it_value.tv_nsec = g_nondeterministic_random->randomInt(period_ns/2,period_ns+1);
|
||||
int period_ns = period * 1000;
|
||||
itimerspec tv;
|
||||
tv.it_interval.tv_sec = 0;
|
||||
tv.it_interval.tv_nsec = period_ns;
|
||||
tv.it_value.tv_sec = 0;
|
||||
tv.it_value.tv_nsec = g_nondeterministic_random->randomInt(period_ns/2,period_ns+1);
|
||||
|
||||
sigevent sev;
|
||||
sev.sigev_notify = SIGEV_THREAD_ID;
|
||||
sev.sigev_signo = SIGPROF;
|
||||
sev.sigev_value.sival_ptr = &(self->signalClosure);
|
||||
sev._sigev_un._tid = gettid();
|
||||
timer_create( CLOCK_THREAD_CPUTIME_ID, &sev, &self->periodic_timer );
|
||||
timer_settime( self->periodic_timer, 0, &tv, NULL );
|
||||
sigevent sev;
|
||||
sev.sigev_notify = SIGEV_THREAD_ID;
|
||||
sev.sigev_signo = SIGPROF;
|
||||
sev.sigev_value.sival_ptr = &(self->signalClosure);
|
||||
sev._sigev_un._tid = gettid();
|
||||
if(timer_create( CLOCK_THREAD_CPUTIME_ID, &sev, &self->periodicTimer ) != 0) {
|
||||
TraceEvent(SevWarn, "FailedToCreateProfilingTimer").GetLastError();
|
||||
return Void();
|
||||
}
|
||||
self->timerInitialized = true;
|
||||
if(timer_settime( self->periodicTimer, 0, &tv, NULL ) != 0) {
|
||||
TraceEvent(SevWarn, "FailedToSetProfilingTimer").GetLastError();
|
||||
return Void();
|
||||
}
|
||||
|
||||
// Open and truncate output file
|
||||
state Reference<SyncFileForSim> outFile = Reference<SyncFileForSim>(new SyncFileForSim(outfn));
|
||||
state int64_t outOffset = 0;
|
||||
Void _ = wait( outFile->truncate(outOffset) );
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
|
||||
<Product Name='$(var.Title)'
|
||||
Id='{4932C603-0935-4D83-9C4B-7C47D0A8EB76}'
|
||||
Id='{34D46755-0BA0-4CA5-8287-EA759D5FAF41}'
|
||||
UpgradeCode='{A95EA002-686E-4164-8356-C715B7F8B1C8}'
|
||||
Version='$(var.Version)'
|
||||
Manufacturer='$(var.Manufacturer)'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Version>6.0.14</Version>
|
||||
<Version>6.0.15</Version>
|
||||
<PackageName>6.0</PackageName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue