Merge branch 'tuple-uint64' into feature-bigint-support-go-ruby

# Conflicts:
#	bindings/go/src/fdb/tuple/tuple.go
This commit is contained in:
A.J. Beamon 2018-10-30 14:23:26 -07:00
commit 42d101c517
8 changed files with 84 additions and 74 deletions

View File

@ -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
}

View File

@ -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) {

View File

@ -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.

View File

@ -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:

View File

@ -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

View File

@ -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) );

View File

@ -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)'

View File

@ -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>