Merge pull request #2453 from AlvinMooreSr/release_6.2_merge

Merge Release 6.2 Into Master
This commit is contained in:
A.J. Beamon 2019-12-12 08:56:30 -08:00 committed by GitHub
commit 05ac4a38f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 486 additions and 242 deletions

View File

@ -26,7 +26,7 @@ package fdb
// #include <foundationdb/fdb_c.h>
import "C"
// Deprecated: Use OpenDatabase or OpenDefault to obtain a database handle directly
// Deprecated: Use OpenDatabase or OpenDefault to obtain a database handle directly.
// Cluster is a handle to a FoundationDB cluster. Cluster is a lightweight
// object that may be efficiently copied, and is safe for concurrent use by
// multiple goroutines.
@ -34,7 +34,7 @@ type Cluster struct {
clusterFileName string
}
// Deprecated: Use OpenDatabase or OpenDefault to obtain a database handle directly
// Deprecated: Use OpenDatabase or OpenDefault to obtain a database handle directly.
// OpenDatabase returns a database handle from the FoundationDB cluster.
//
// The database name must be []byte("DB").

View File

@ -236,8 +236,12 @@ func StartNetwork() error {
const DefaultClusterFile string = ""
// OpenDefault returns a database handle to the FoundationDB cluster identified
// by the DefaultClusterFile on the current machine. The FoundationDB client
// networking engine will be initialized first, if necessary.
// by the DefaultClusterFile on the current machine.
//
// A single client can use this function multiple times to connect to different
// clusters simultaneously, with each invocation requiring its own cluster file.
// To connect to multiple clusters running at different, incompatible versions,
// the multi-version client API must be used.
func OpenDefault() (Database, error) {
return OpenDatabase(DefaultClusterFile)
}
@ -254,6 +258,11 @@ func MustOpenDefault() Database {
// Open returns a database handle to the FoundationDB cluster identified
// by the provided cluster file and database name.
//
// A single client can use this function multiple times to connect to different
// clusters simultaneously, with each invocation requiring its own cluster file.
// To connect to multiple clusters running at different, incompatible versions,
// the multi-version client API must be used.
func OpenDatabase(clusterFile string) (Database, error) {
networkMutex.Lock()
defer networkMutex.Unlock()
@ -283,6 +292,8 @@ func OpenDatabase(clusterFile string) (Database, error) {
return db, nil
}
// MustOpenDatabase is like OpenDatabase but panics if the default database cannot
// be opened.
func MustOpenDatabase(clusterFile string) Database {
db, err := OpenDatabase(clusterFile)
if err != nil {
@ -291,7 +302,7 @@ func MustOpenDatabase(clusterFile string) Database {
return db
}
// Deprecated: Use OpenDatabase instead
// Deprecated: Use OpenDatabase instead.
// The database name must be []byte("DB").
func Open(clusterFile string, dbName []byte) (Database, error) {
if bytes.Compare(dbName, []byte("DB")) != 0 {
@ -300,7 +311,7 @@ func Open(clusterFile string, dbName []byte) (Database, error) {
return OpenDatabase(clusterFile)
}
// Deprecated: Use MustOpenDatabase instead
// Deprecated: Use MustOpenDatabase instead.
// MustOpen is like Open but panics if the database cannot be opened.
func MustOpen(clusterFile string, dbName []byte) Database {
db, err := Open(clusterFile, dbName)

View File

@ -80,6 +80,7 @@ func newFuture(ptr *C.FDBFuture) *future {
return f
}
// Note: This function guarantees the callback will be executed **at most once**.
func fdb_future_block_until_ready(f *C.FDBFuture) {
if C.fdb_future_is_ready(f) != 0 {
return

View File

@ -215,10 +215,13 @@ if(NOT OPEN_FOR_IDE)
else()
set(lib_destination "linux/amd64")
endif()
set(lib_destination "${unpack_dir}/lib/${lib_destination}")
set(lib_destination "${unpack_dir}/lib/${lib_destination}")
set(jni_package "${CMAKE_BINARY_DIR}/packages/lib")
file(MAKE_DIRECTORY ${lib_destination})
file(MAKE_DIRECTORY ${jni_package})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lib_copied
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:fdb_java> ${lib_destination} &&
${CMAKE_COMMAND} -E copy $<TARGET_FILE:fdb_java> ${jni_package} &&
${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/lib_copied
COMMENT "Copy jni library for fat jar")
add_custom_target(copy_lib DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/lib_copied)

View File

@ -292,9 +292,14 @@ public class FDB {
}
/**
* Initializes networking, connects with the
* <a href="/foundationdb/administration.html#default-cluster-file" target="_blank">default fdb.cluster file</a>,
* and opens the database.
* Initializes networking if required and connects to the cluster specified by the
* <a href="/foundationdb/administration.html#default-cluster-file" target="_blank">default fdb.cluster file</a>.<br>
* <br>
* A single client can use this function multiple times to connect to different
* clusters simultaneously, with each invocation requiring its own cluster file.
* To connect to multiple clusters running at different, incompatible versions,
* the <a href="/foundationdb/api-general.html#multi-version-client-api" target="_blank">multi-version client API</a>
* must be used.
*
* @return a {@code CompletableFuture} that will be set to a FoundationDB {@link Database}
*/
@ -303,8 +308,13 @@ public class FDB {
}
/**
* Initializes networking, connects to the cluster specified by {@code clusterFilePath}
* and opens the database.
* Initializes networking if required and connects to the cluster specified by {@code clusterFilePath}.<br>
* <br>
* A single client can use this function multiple times to connect to different
* clusters simultaneously, with each invocation requiring its own cluster file.
* To connect to multiple clusters running at different, incompatible versions,
* the <a href="/foundationdb/api-general.html#multi-version-client-api" target="_blank">multi-version client API</a>
* must be used.
*
* @param clusterFilePath the
* <a href="/foundationdb/administration.html#foundationdb-cluster-file" target="_blank">cluster file</a>
@ -319,8 +329,13 @@ public class FDB {
}
/**
* Initializes networking, connects to the cluster specified by {@code clusterFilePath}
* and opens the database.
* Initializes networking if required and connects to the cluster specified by {@code clusterFilePath}.<br>
* <br>
* A single client can use this function multiple times to connect to different
* clusters simultaneously, with each invocation requiring its own cluster file.
* To connect to multiple clusters running at different, incompatible versions,
* the <a href="/foundationdb/api-general.html#multi-version-client-api" target="_blank">multi-version client API</a>
* must be used.
*
* @param clusterFilePath the
* <a href="/foundationdb/administration.html#foundationdb-cluster-file" target="_blank">cluster file</a>

View File

@ -44,6 +44,9 @@ abstract class NativeFuture<T> extends CompletableFuture<T> implements AutoClose
//
// Since this must be called from a constructor, we assume that close
// cannot be called concurrently.
//
// Note: This function guarantees the callback will be executed **at most once**.
//
protected void registerMarshalCallback(Executor executor) {
if(cPtr != 0) {
Future_registerCallback(cPtr, () -> executor.execute(this::marshalWhenDone));

View File

@ -25,7 +25,10 @@ elseif(CPACK_GENERATOR MATCHES "productbuild")
set(CPACK_PRODUCTBUILD_RESOURCES_DIR ${CMAKE_SOURCE_DIR}/packaging/osx/resources)
# Changing the path of this file as CMAKE_BINARY_DIR does not seem to be defined
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_BINARY_DIR}/License.txt)
set(CPACK_PACKAGE_FILE_NAME "foundationdb-${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string}")
if(NOT FDB_RELEASE)
set(prerelease_string_osx "-PRERELEASE")
endif()
set(CPACK_PACKAGE_FILE_NAME "FoundationDB-${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string_osx}")
elseif(CPACK_GENERATOR MATCHES "TGZ")
set(CPACK_STRIP_FILES TRUE)
set(CPACK_COMPONENTS_ALL clients-tgz server-tgz)

View File

@ -79,6 +79,20 @@ function(install_symlink)
endif()
endfunction()
function(symlink_files)
if (NOT WIN32)
set(options "")
set(one_value_options LOCATION SOURCE)
set(multi_value_options TARGETS)
cmake_parse_arguments(SYM "${options}" "${one_value_options}" "${multi_value_options}" "${ARGN}")
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${SYM_LOCATION})
foreach(component IN LISTS SYM_TARGETS)
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${SYM_SOURCE} ${CMAKE_BINARY_DIR}/${SYM_LOCATION}/${component} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/${SYM_LOCATION})
endforeach()
endif()
endfunction()
# 'map' from (destination, package) to path
# format vars like install_destination_for_${destination}_${package}
set(install_destination_for_bin_tgz "bin")
@ -254,8 +268,14 @@ configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/License.txt COPYO
if(NOT FDB_RELEASE)
set(prerelease_string ".PRERELEASE")
endif()
set(clients-filename "foundationdb-clients-${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string}")
set(server-filename "foundationdb-server-${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string}")
# RPM filenames
set(rpm-clients-filename "foundationdb-clients-${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string}")
set(rpm-server-filename "foundationdb-server-${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string}")
# Deb filenames
set(deb-clients-filename "foundationdb-clients_${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string}")
set(deb-server-filename "foundationdb-server_${PROJECT_VERSION}.${CURRENT_GIT_VERSION}${prerelease_string}")
################################################################################
# Configuration for RPM
@ -269,15 +289,15 @@ set(CPACK_RPM_CLIENTS-EL7_PACKAGE_NAME "foundationdb-clients")
set(CPACK_RPM_SERVER-EL6_PACKAGE_NAME "foundationdb-server")
set(CPACK_RPM_SERVER-EL7_PACKAGE_NAME "foundationdb-server")
set(CPACK_RPM_CLIENTS-EL6_FILE_NAME "${clients-filename}.el6.x86_64.rpm")
set(CPACK_RPM_CLIENTS-EL7_FILE_NAME "${clients-filename}.el7.x86_64.rpm")
set(CPACK_RPM_SERVER-EL6_FILE_NAME "${server-filename}.el6.x86_64.rpm")
set(CPACK_RPM_SERVER-EL7_FILE_NAME "${server-filename}.el7.x86_64.rpm")
set(CPACK_RPM_CLIENTS-EL6_FILE_NAME "${rpm-clients-filename}.el6.x86_64.rpm")
set(CPACK_RPM_CLIENTS-EL7_FILE_NAME "${rpm-clients-filename}.el7.x86_64.rpm")
set(CPACK_RPM_SERVER-EL6_FILE_NAME "${rpm-server-filename}.el6.x86_64.rpm")
set(CPACK_RPM_SERVER-EL7_FILE_NAME "${rpm-server-filename}.el7.x86_64.rpm")
set(CPACK_RPM_CLIENTS-EL6_DEBUGINFO_FILE_NAME "${clients-filename}.el6-debuginfo.x86_64.rpm")
set(CPACK_RPM_CLIENTS-EL7_DEBUGINFO_FILE_NAME "${clients-filename}.el7-debuginfo.x86_64.rpm")
set(CPACK_RPM_SERVER-EL6_DEBUGINFO_FILE_NAME "${server-filename}.el6-debuginfo.x86_64.rpm")
set(CPACK_RPM_SERVER-EL7_DEBUGINFO_FILE_NAME "${server-filename}.el7-debuginfo.x86_64.rpm")
set(CPACK_RPM_CLIENTS-EL6_DEBUGINFO_FILE_NAME "${rpm-clients-filename}.el6-debuginfo.x86_64.rpm")
set(CPACK_RPM_CLIENTS-EL7_DEBUGINFO_FILE_NAME "${rpm-clients-filename}.el7-debuginfo.x86_64.rpm")
set(CPACK_RPM_SERVER-EL6_DEBUGINFO_FILE_NAME "${rpm-server-filename}.el6-debuginfo.x86_64.rpm")
set(CPACK_RPM_SERVER-EL7_DEBUGINFO_FILE_NAME "${rpm-server-filename}.el7-debuginfo.x86_64.rpm")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/packaging/emptydir")
fdb_install(DIRECTORY "${CMAKE_BINARY_DIR}/packaging/emptydir/" DESTINATION data COMPONENT server)
@ -346,8 +366,8 @@ set(CPACK_RPM_SERVER-EL7_PACKAGE_REQUIRES
# Configuration for DEB
################################################################################
set(CPACK_DEBIAN_CLIENTS-DEB_FILE_NAME "${clients-filename}_amd64.deb")
set(CPACK_DEBIAN_SERVER-DEB_FILE_NAME "${server-filename}_amd64.deb")
set(CPACK_DEBIAN_CLIENTS-DEB_FILE_NAME "${deb-clients-filename}_amd64.deb")
set(CPACK_DEBIAN_SERVER-DEB_FILE_NAME "${deb-server-filename}_amd64.deb")
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_DEBIAN_DEBUGINFO_PACKAGE ON)
set(CPACK_DEBIAN_PACKAGE_SECTION "database")
@ -387,8 +407,8 @@ endif()
################################################################################
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
set(CPACK_ARCHIVE_CLIENTS-TGZ_FILE_NAME "${clients-filename}.x86_64")
set(CPACK_ARCHIVE_SERVER-TGZ_FILE_NAME "${server-filename}.x86_64")
set(CPACK_ARCHIVE_CLIENTS-TGZ_FILE_NAME "${deb-clients-filename}.x86_64")
set(CPACK_ARCHIVE_SERVER-TGZ_FILE_NAME "${deb-server-filename}.x86_64")
################################################################################
# Server configuration

View File

@ -7,6 +7,7 @@
#include <stack>
#include <memory>
#include <sstream>
#include <algorithm>
namespace {

View File

@ -277,6 +277,8 @@ See :ref:`developer-guide-programming-with-futures` for further (language-indepe
Causes the :type:`FDBCallback` function to be invoked as ``callback(future, callback_parameter)`` when the given Future is ready. If the Future is already ready, the call may occur in the current thread before this function returns (but this behavior is not guaranteed). Alternatively, the call may be delayed indefinitely and take place on the thread on which :func:`fdb_run_network()` was invoked, and the callback is responsible for any necessary thread synchronization (and/or for posting work back to your application event loop, thread pool, etc. if your application's architecture calls for that).
.. note:: This function guarantees the callback will be executed **at most once**.
.. warning:: Never call :func:`fdb_future_block_until_ready()` from a callback passed to this function. This may block the thread on which :func:`fdb_run_network()` was invoked, resulting in a deadlock.
.. type:: FDBCallback
@ -393,6 +395,8 @@ An |database-blurb1| Modifications to a database are performed via transactions.
Creates a new database connected the specified cluster. The caller assumes ownership of the :type:`FDBDatabase` object and must destroy it with :func:`fdb_database_destroy()`.
|fdb-open-blurb2|
``cluster_file_path``
A NULL-terminated string giving a local path of a :ref:`cluster file <foundationdb-cluster-file>` (often called 'fdb.cluster') which contains connection information for the FoundationDB cluster. If cluster_file_path is NULL or an empty string, then a :ref:`default cluster file <default-cluster-file>` will be used.

View File

@ -441,6 +441,14 @@
Sets the maximum escaped length of key and value fields to be logged to the trace file via the LOG_TRANSACTION option, after which the field will be truncated. A negative value disables truncation. One can set the default max field length for all transactions by calling |transaction-logging-max-field-length-database-option|.
.. |option-set-debug-transaction-identifier| replace::
Sets a client provided string identifier for the transaction that will be used in scenarios like tracing or profiling. Client trace logging or transaction profiling must be separately enabled.
.. |option-set-log-transaction| replace::
Enables tracing for this transaction and logs results to the client trace logs. The DEBUG_TRANSACTION_IDENTIFIER option must be set before using this option, and client trace logging must be enabled to get log output.
.. |future-blurb1| replace::
Many FoundationDB API functions return "future" objects. A brief overview of futures is included in the :doc:`class scheduling tutorial <class-scheduling>`. Most future objects behave just like a normal object, but block when you use them for the first time if the asynchronous function which returned the future has not yet completed its action. A future object is considered ready when either a value is available, or when an error has occurred.
@ -448,8 +456,11 @@
Cancels |future-type-string| and its associated asynchronous operation. If called before the future is ready, attempts to access its value will |error-raise-type| an :ref:`operation_cancelled <developer-guide-error-codes>` |error-type|. Cancelling a future which is already ready has no effect. Note that even if a future is not ready, its associated asynchronous operation may have succesfully completed and be unable to be cancelled.
.. |fdb-open-blurb| replace::
Initializes the FoundationDB API and connects to the cluster specified by the :ref:`cluster file <foundationdb-cluster-file>`. This function is often called without any parameters, using only the defaults. If no cluster file is passed, FoundationDB automatically :ref:`determines a cluster file <specifying-a-cluster-file>` with which to connect to a cluster.
.. |fdb-open-blurb1| replace::
Connects to the cluster specified by the :ref:`cluster file <foundationdb-cluster-file>`. This function is often called without any parameters, using only the defaults. If no cluster file is passed, FoundationDB automatically :ref:`determines a cluster file <specifying-a-cluster-file>` with which to connect to a cluster.
.. |fdb-open-blurb2| replace::
A single client can use this function multiple times to connect to different clusters simultaneously, with each invocation requiring its own cluster file. To connect to multiple clusters running at different, incompatible versions, the :ref:`multi-version client API <multi-version-client-api>` must be used.
.. |fdb-transactional-unknown-result-note| replace::
In some failure scenarios, it is possible that your transaction will be executed twice. See :ref:`developer-guide-unknown-results` for more information.

View File

@ -111,7 +111,9 @@ After importing the ``fdb`` module and selecting an API version, you probably wa
.. function:: open( cluster_file=None, event_model=None )
|fdb-open-blurb|
|fdb-open-blurb1|
|fdb-open-blurb2|
.. param event_model:: Can be used to select alternate :ref:`api-python-event-models`
@ -881,6 +883,14 @@ Transaction options
|option-set-transaction-logging-max-field-length-blurb|
.. method:: Transaction.options.set_debug_transaction_identifier(id_string)
|option-set-debug-transaction-identifier|
.. method:: Transaction.options.set_log_transaction()
|option-set-log-transaction|
.. _api-python-future:
Future objects
@ -912,6 +922,8 @@ All future objects are a subclass of the :class:`Future` type.
Calls the specified callback function, passing itself as a single argument, when the future object is ready. If the future object is ready at the time :meth:`on_ready()` is called, the call may occur immediately in the current thread (although this behavior is not guaranteed). Otherwise, the call may be delayed and take place on the thread with which the client was initialized. Therefore, the callback is responsible for any needed thread synchronization (and/or for posting work to your application's event loop, thread pool, etc., as may be required by your application's architecture).
.. note:: This function guarantees the callback will be executed **at most once**.
.. warning:: |fdb-careful-with-callbacks-blurb|
.. method:: Future.cancel()

View File

@ -100,7 +100,9 @@ After requiring the ``FDB`` gem and selecting an API version, you probably want
.. function:: open( cluster_file=nil ) -> Database
|fdb-open-blurb|
|fdb-open-blurb1|
|fdb-open-blurb2|
.. global:: FDB.options
@ -823,6 +825,14 @@ Transaction options
|option-set-transaction-logging-max-field-length-blurb|
.. method:: Transaction.options.set_debug_transaction_identifier(id_string) -> nil
|option-set-debug-transaction-identifier|
.. method:: Transaction.options.set_log_transaction() -> nil
|option-set-log-transaction|
.. _transact:
The transact method
@ -912,6 +922,8 @@ All future objects are a subclass of the :class:`Future` type.
Yields ``self`` to the given block when the future object is ready. If the future object is ready at the time :meth:`on_ready` is called, the block may be called immediately in the current thread (although this behavior is not guaranteed). Otherwise, the call may be delayed and take place on the thread with which the client was initialized. Therefore, the block is responsible for any needed thread synchronization (and/or for posting work to your application's event loop, thread pool, etc., as may be required by your application's architecture).
.. note:: This function guarantees the callback will be executed **at most once**.
.. warning:: |fdb-careful-with-callbacks-blurb|
.. method:: Future.cancel() -> nil

View File

@ -2,6 +2,14 @@
Release Notes
#############
6.2.12
======
Fixes
-----
* Clients could throw an internal error during ``commit`` if client buggification was enabled. `(PR #2427) <https://github.com/apple/foundationdb/pull/2427>`_.
6.2.11
======
@ -197,4 +205,4 @@ Earlier release notes
* :doc:`Beta 2 (API Version 22) </old-release-notes/release-notes-022>`
* :doc:`Beta 1 (API Version 21) </old-release-notes/release-notes-021>`
* :doc:`Alpha 6 (API Version 16) </old-release-notes/release-notes-016>`
* :doc:`Alpha 5 (API Version 14) </old-release-notes/release-notes-014>`
* :doc:`Alpha 5 (API Version 14) </old-release-notes/release-notes-014>`

View File

@ -30,6 +30,14 @@ if(NOT OPEN_FOR_IDE)
LINK_DIR bin
FILE_NAME fdbbackup
LINK_NAME fdbdr)
symlink_files(
LOCATION packages/bin
SOURCE fdbbackup
TARGETS fdbdr dr_agent backup_agent fdbrestore)
symlink_files(
LOCATION bin
SOURCE fdbbackup
TARGETS fdbdr dr_agent backup_agent fdbrestore)
endif()
if (GPERFTOOLS_FOUND)

View File

@ -881,7 +881,9 @@ struct ClusterControllerPriorityInfo {
uint8_t dcFitness;
bool operator== (ClusterControllerPriorityInfo const& r) const { return processClassFitness == r.processClassFitness && isExcluded == r.isExcluded && dcFitness == r.dcFitness; }
ClusterControllerPriorityInfo()
: ClusterControllerPriorityInfo(/*ProcessClass::UnsetFit*/ 2, false,
ClusterControllerPriorityInfo::FitnessUnknown) {}
ClusterControllerPriorityInfo(uint8_t processClassFitness, bool isExcluded, uint8_t dcFitness) : processClassFitness(processClassFitness), isExcluded(isExcluded), dcFitness(dcFitness) {}
template <class Ar>

View File

@ -2602,19 +2602,19 @@ void Transaction::setupWatches() {
ACTOR static Future<Void> tryCommit( Database cx, Reference<TransactionLogInfo> trLogInfo, CommitTransactionRequest req, Future<Version> readVersion, TransactionInfo info, Version* pCommittedVersion, Transaction* tr, TransactionOptions options) {
state TraceInterval interval( "TransactionCommit" );
state double startTime;
state double startTime = now();
if (info.debugID.present())
TraceEvent(interval.begin()).detail( "Parent", info.debugID.get() );
if(CLIENT_BUGGIFY) {
throw deterministicRandom()->randomChoice(std::vector<Error>{
not_committed(),
transaction_too_old(),
proxy_memory_limit_exceeded(),
commit_unknown_result()});
}
try {
if(CLIENT_BUGGIFY) {
throw deterministicRandom()->randomChoice(std::vector<Error>{
not_committed(),
transaction_too_old(),
proxy_memory_limit_exceeded(),
commit_unknown_result()});
}
Version v = wait( readVersion );
req.transaction.read_snapshot = v;
@ -2643,6 +2643,9 @@ ACTOR static Future<Void> tryCommit( Database cx, Reference<TransactionLogInfo>
when (CommitID ci = wait( reply )) {
Version v = ci.version;
if (v != invalidVersion) {
if (CLIENT_BUGGIFY) {
throw commit_unknown_result();
}
if (info.debugID.present())
TraceEvent(interval.end()).detail("CommittedVersion", v);
*pCommittedVersion = v;
@ -2668,9 +2671,6 @@ ACTOR static Future<Void> tryCommit( Database cx, Reference<TransactionLogInfo>
cx->latencies.addSample(now() - tr->startTime);
if (trLogInfo)
trLogInfo->addLog(FdbClientLogEvents::EventCommit(startTime, latency, req.transaction.mutations.size(), req.transaction.mutations.expectedSize(), req));
if (CLIENT_BUGGIFY) {
throw commit_unknown_result();
}
return Void();
} else {
if (info.debugID.present())

View File

@ -33,7 +33,9 @@ struct ExtStringRef {
Standalone<StringRef> toStandaloneStringRef() {
auto s = makeString( size() );
memcpy( mutateString( s ), base.begin(), base.size() );
if (base.size() > 0) {
memcpy(mutateString(s), base.begin(), base.size());
}
memset( mutateString( s ) + base.size(), 0, extra_zero_bytes );
return s;
};
@ -41,7 +43,9 @@ struct ExtStringRef {
StringRef toArenaOrRef( Arena& a ) {
if (extra_zero_bytes) {
StringRef dest = StringRef( new(a) uint8_t[ size() ], size() );
memcpy( mutateString(dest), base.begin(), base.size() );
if (base.size()) {
memcpy(mutateString(dest), base.begin(), base.size());
}
memset( mutateString(dest)+base.size(), 0, extra_zero_bytes );
return dest;
} else
@ -56,7 +60,9 @@ struct ExtStringRef {
StringRef toArena( Arena& a ) {
if (extra_zero_bytes) {
StringRef dest = StringRef( new(a) uint8_t[ size() ], size() );
memcpy( mutateString(dest), base.begin(), base.size() );
if (base.size() > 0) {
memcpy(mutateString(dest), base.begin(), base.size());
}
memset( mutateString(dest)+base.size(), 0, extra_zero_bytes );
return dest;
} else
@ -65,10 +71,12 @@ struct ExtStringRef {
int size() const { return base.size() + extra_zero_bytes; }
int cmp( ExtStringRef const& rhs ) const {
int cmp(ExtStringRef const& rhs) const {
int cbl = std::min(base.size(), rhs.base.size());
int c = memcmp( base.begin(), rhs.base.begin(), cbl );
if (c!=0) return c;
if (cbl > 0) {
int c = memcmp(base.begin(), rhs.base.begin(), cbl);
if (c != 0) return c;
}
for(int i=cbl; i<base.size(); i++)
if (base[i]) return 1;

View File

@ -33,7 +33,7 @@ namespace vexillographer
outFile.WriteLine("struct FDB{0}s {{", scope.ToString());
outFile.WriteLine("\tfriend class FDBOptionInfoMap<FDB{0}s>;",scope.ToString());
outFile.WriteLine();
outFile.WriteLine("\tenum Option {");
outFile.WriteLine("\tenum Option : int {");
outFile.WriteLine(string.Join(",\n\n", options.Select(f => c.getCLine(f, "\t\t", "")).ToArray()));
outFile.WriteLine("\t};");
outFile.WriteLine();

View File

@ -1249,3 +1249,25 @@ TEST_CASE("/fdbrpc/flow/wait_expression_after_cancel")
ASSERT( a == 1 );
return Void();
}
// Meant to be run with -fsanitize=undefined
TEST_CASE("/flow/DeterministicRandom/SignedOverflow") {
deterministicRandom()->randomInt(std::numeric_limits<int>::min(), 0);
deterministicRandom()->randomInt(0, std::numeric_limits<int>::max());
deterministicRandom()->randomInt(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
ASSERT(deterministicRandom()->randomInt(std::numeric_limits<int>::min(), std::numeric_limits<int>::min() + 1) ==
std::numeric_limits<int>::min());
ASSERT(deterministicRandom()->randomInt(std::numeric_limits<int>::max() - 1, std::numeric_limits<int>::max()) ==
std::numeric_limits<int>::max() - 1);
deterministicRandom()->randomInt64(std::numeric_limits<int64_t>::min(), 0);
deterministicRandom()->randomInt64(0, std::numeric_limits<int64_t>::max());
deterministicRandom()->randomInt64(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max());
ASSERT(deterministicRandom()->randomInt64(std::numeric_limits<int64_t>::min(),
std::numeric_limits<int64_t>::min() + 1) ==
std::numeric_limits<int64_t>::min());
ASSERT(deterministicRandom()->randomInt64(std::numeric_limits<int64_t>::max() - 1,
std::numeric_limits<int64_t>::max()) ==
std::numeric_limits<int64_t>::max() - 1);
return Void();
}

View File

@ -818,7 +818,9 @@ ACTOR static Future<Void> connectionReader(
const int unproc_len = unprocessed_end - unprocessed_begin;
const int len = getNewBufferSize(unprocessed_begin, unprocessed_end, peerAddress);
uint8_t* const newBuffer = new (newArena) uint8_t[ len ];
memcpy( newBuffer, unprocessed_begin, unproc_len );
if (unproc_len > 0) {
memcpy(newBuffer, unprocessed_begin, unproc_len);
}
arena = newArena;
unprocessed_begin = newBuffer;
unprocessed_end = newBuffer + unproc_len;

View File

@ -92,7 +92,9 @@ struct StringBuffer {
uint8_t* p = (uint8_t*)(int64_t(b+alignment-1) & ~(alignment-1)); // first multiple of alignment greater than or equal to b
ASSERT( p>=b && p+reserved<=e && int64_t(p)%alignment == 0 );
memcpy(p, str.begin(), str.size());
if (str.size() > 0) {
memcpy(p, str.begin(), str.size());
}
ref() = StringRef( p, str.size() );
}
}

View File

@ -428,15 +428,16 @@ Value encodeKVFragment( KeyValueRef kv, uint32_t index) {
// a signed representation of the index value. The type code for 0 is 0 (which is
// actually the null type in SQLite).
int8_t indexCode = 0;
uint32_t tmp = index;
while(tmp != 0) {
++indexCode;
tmp >>= 8;
if (index != 0) {
uint32_t tmp = index;
while (tmp != 0) {
++indexCode;
tmp >>= 8;
}
// An increment is required if the high bit of the N-byte index value is set, since it is
// positive number but SQLite only stores signed values and would interpret it as negative.
if (index >> (8 * indexCode - 1)) ++indexCode;
}
// An increment is required if the high bit of the N-byte index value is set, since it is
// positive number but SQLite only stores signed values and would interpret it as negative.
if(index >> (8 * indexCode - 1))
++indexCode;
int header_size = sqlite3VarintLen(keyCode) + sizeof(indexCode) + sqlite3VarintLen(valCode);
int hh = sqlite3VarintLen(header_size);

View File

@ -94,11 +94,12 @@ struct StorageQueueInfo {
Smoother smoothFreeSpace;
Smoother smoothTotalSpace;
limitReason_t limitReason;
StorageQueueInfo(UID id, LocalityData locality) : valid(false), id(id), locality(locality), smoothDurableBytes(SERVER_KNOBS->SMOOTHING_AMOUNT),
smoothInputBytes(SERVER_KNOBS->SMOOTHING_AMOUNT), verySmoothDurableBytes(SERVER_KNOBS->SLOW_SMOOTHING_AMOUNT),
verySmoothDurableVersion(SERVER_KNOBS->SLOW_SMOOTHING_AMOUNT), smoothLatestVersion(SERVER_KNOBS->SMOOTHING_AMOUNT), smoothFreeSpace(SERVER_KNOBS->SMOOTHING_AMOUNT),
smoothTotalSpace(SERVER_KNOBS->SMOOTHING_AMOUNT)
{
StorageQueueInfo(UID id, LocalityData locality)
: valid(false), id(id), locality(locality), smoothDurableBytes(SERVER_KNOBS->SMOOTHING_AMOUNT),
smoothInputBytes(SERVER_KNOBS->SMOOTHING_AMOUNT), verySmoothDurableBytes(SERVER_KNOBS->SLOW_SMOOTHING_AMOUNT),
verySmoothDurableVersion(SERVER_KNOBS->SLOW_SMOOTHING_AMOUNT),
smoothLatestVersion(SERVER_KNOBS->SMOOTHING_AMOUNT), smoothFreeSpace(SERVER_KNOBS->SMOOTHING_AMOUNT),
smoothTotalSpace(SERVER_KNOBS->SMOOTHING_AMOUNT), limitReason(limitReason_t::unlimited) {
// FIXME: this is a tacky workaround for a potential uninitialized use in trackStorageServerQueueInfo
lastReply.instanceID = -1;
}
@ -553,10 +554,13 @@ void updateRate(RatekeeperData* self, RatekeeperLimits* limits) {
maxTLVer = std::max(maxTLVer, tl.lastReply.v);
}
// writeToReadLatencyLimit: 0 = infinte speed; 1 = TL durable speed ; 2 = half TL durable speed
writeToReadLatencyLimit = ((maxTLVer - minLimitingSSVer) - limits->maxVersionDifference/2) / (limits->maxVersionDifference/4);
worstVersionLag = std::max((Version)0, maxTLVer - minSSVer);
limitingVersionLag = std::max((Version)0, maxTLVer - minLimitingSSVer);
if (minSSVer != std::numeric_limits<Version>::max() && maxTLVer != std::numeric_limits<Version>::min()) {
// writeToReadLatencyLimit: 0 = infinte speed; 1 = TL durable speed ; 2 = half TL durable speed
writeToReadLatencyLimit =
((maxTLVer - minLimitingSSVer) - limits->maxVersionDifference / 2) / (limits->maxVersionDifference / 4);
worstVersionLag = std::max((Version)0, maxTLVer - minSSVer);
limitingVersionLag = std::max((Version)0, maxTLVer - minLimitingSSVer);
}
}
int64_t worstFreeSpaceTLog = std::numeric_limits<int64_t>::max();

View File

@ -343,7 +343,9 @@ private:
n->nPointers = level+1;
n->valueLength = value.size();
memcpy(n->value(), value.begin(), value.size());
if (value.size() > 0) {
memcpy(n->value(), value.begin(), value.size());
}
return n;
}
@ -1033,8 +1035,8 @@ class MiniConflictSet : NonCopyable {
std::vector<wordType> andValues;
MiniConflictSet2 debug; // SOMEDAY: Test on big ranges, eliminate this
uint64_t bitMask(unsigned int bit){ // computes results for bit%word
return (((wordType)1) << ( bit & bucketMask )); // '&' unnecesary?
wordType bitMask(unsigned int bit) { // computes results for bit%word
return (((wordType)1) << (bit & bucketMask));
}
void setNthBit(std::vector<wordType>& v, const unsigned int bit){
v[bit>>bucketShift] |= bitMask(bit);
@ -1050,11 +1052,11 @@ class MiniConflictSet : NonCopyable {
}
wordType highBits(int b){ // bits (b&bucketMask) and higher are 1
#pragma warning(disable: 4146)
return -(wordType(1) << b);
return -bitMask(b);
#pragma warning(default: 4146)
}
wordType lowBits(int b){ // bits lower than b are 1
return (wordType(1)<<b)-1;
wordType lowBits(int b) { // bits lower than (b&bucketMask) are 1
return bitMask(b) - 1;
}
wordType lowBits2(int b) {
return (b&bucketMask) ? lowBits(b) : -1;
@ -1090,6 +1092,15 @@ class MiniConflictSet : NonCopyable {
}
}
bool orImpl(int begin, int end) {
if (begin == end) return false;
int beginWord = begin >> bucketShift;
int lastWord = ((end + bucketMask) >> bucketShift) - 1;
return orBits(orValues, beginWord + 1, lastWord, true) || getNthBit(andValues, beginWord) ||
getNthBit(andValues, lastWord) || orBits(values, begin, end, false);
}
public:
explicit MiniConflictSet( int size ) : debug(size) {
static_assert((1<<bucketShift) == sizeof(wordType)*8, "BucketShift incorrect");
@ -1117,16 +1128,6 @@ public:
ASSERT( a == b );
return b;
}
bool orImpl( int begin, int end ) {
if (begin == end) return false;
int beginWord = begin>>bucketShift;
int lastWord = ((end+bucketMask) >> bucketShift) - 1;
return orBits( orValues, beginWord+1, lastWord, true ) ||
getNthBit( andValues, beginWord ) || getNthBit( andValues, lastWord ) ||
orBits( values, begin, end, false );
}
};

View File

@ -155,7 +155,7 @@ struct TLogPeekReply {
Version maxKnownVersion;
Version minKnownCommittedVersion;
Optional<Version> begin;
bool onlySpilled;
bool onlySpilled = false;
template <class Ar>
void serialize(Ar& ar) {

View File

@ -1603,7 +1603,9 @@ private:
void setMetaKey(StringRef key) {
ASSERT(key.size() < (smallestPhysicalBlock - sizeof(Header)));
metaKeySize = key.size();
memcpy(this + 1, key.begin(), key.size());
if (key.size() > 0) {
memcpy(this + 1, key.begin(), key.size());
}
}
int size() const {

View File

@ -14706,7 +14706,7 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
** Read or write a four-byte big-endian integer value.
*/
SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
return ((u32)p[0]<<24) | ((u32)p[1]<<16) | ((u32)p[2]<<8) | (u32)p[3];
}
SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
p[0] = (u8)(v>>24);

View File

@ -927,7 +927,7 @@ ACTOR Future<Void> watchValue_impl( StorageServer* data, WatchValueRequest req )
if(reply.error.present()) {
throw reply.error.get();
}
debugMutation("ShardWatchValue", latest, MutationRef(MutationRef::DebugKey, req.key, reply.value.present() ? StringRef( reply.value.get() ) : LiteralStringRef("<null>") ) );
if( req.debugID.present() )
@ -1154,7 +1154,7 @@ ACTOR Future<GetKeyValuesReply> readRange( StorageServer* data, Version version,
merge( result.arena, result.data, atStorageVersion, vStart, vEnd, vCount, limit, more, *pLimitBytes );
limit -= result.data.size() - prevSize;
for (auto i = &result.data[prevSize]; i != result.data.end(); i++) {
for (auto i = result.data.begin() + prevSize; i != result.data.end(); i++) {
*pLimitBytes -= sizeof(KeyValueRef) + i->expectedSize();
}
@ -1243,7 +1243,7 @@ ACTOR Future<GetKeyValuesReply> readRange( StorageServer* data, Version version,
merge( result.arena, result.data, atStorageVersion, vStart, vEnd, vCount, limit, false, *pLimitBytes );
limit += result.data.size() - prevSize;
for (auto i = &result.data[prevSize]; i != result.data.end(); i++) {
for (auto i = result.data.begin() + prevSize; i != result.data.end(); i++) {
*pLimitBytes -= sizeof(KeyValueRef) + i->expectedSize();
}
@ -1481,7 +1481,7 @@ ACTOR Future<Void> getKeyValues( StorageServer* data, GetKeyValuesRequest req )
++data->counters.finishedQueries;
--data->readQueueSizeMetric;
if(data->latencyBandConfig.present()) {
int maxReadBytes = data->latencyBandConfig.get().readConfig.maxReadBytes.orDefault(std::numeric_limits<int>::max());
int maxSelectorOffset = data->latencyBandConfig.get().readConfig.maxKeySelectorOffset.orDefault(std::numeric_limits<int>::max());

View File

@ -128,6 +128,11 @@ struct FuzzApiCorrectnessWorkload : TestWorkload {
useSystemKeys = deterministicRandom()->coinflip();
initialKeyDensity = deterministicRandom()->random01(); // This fraction of keys are present before the first transaction (and after an unknown result)
// See https://github.com/apple/foundationdb/issues/2424
if (BUGGIFY) {
enableBuggify(true, BuggifyType::Client);
}
if( adjacentKeys ) {
nodes = std::min<int64_t>( deterministicRandom()->randomInt(1, 4 << deterministicRandom()->randomInt(0,14)), CLIENT_KNOBS->KEY_SIZE_LIMIT * 1.2 );
}
@ -383,8 +388,8 @@ struct FuzzApiCorrectnessWorkload : TestWorkload {
ExceptionContract contract;
std::vector<ThreadFuture<Void> > pre_steps;
BaseTest(unsigned int id_, FuzzApiCorrectnessWorkload *wl, const char *func)
: id(id_), workload(wl), contract(func, std::bind(&Subclass::augmentTrace, static_cast<Subclass *>(this), ph::_1)) {}
BaseTest(unsigned int id_, FuzzApiCorrectnessWorkload* wl, const char* func)
: id(id_), workload(wl), contract(func, std::bind(&BaseTest::augmentTrace, this, ph::_1)) {}
static Key makeKey() {
double ksrv = deterministicRandom()->random01();

View File

@ -57,7 +57,7 @@ struct Operation {
Value value;
int limit;
bool reverse;
bool reverse = false;
};
//A workload which executes random sequences of operations on RYOW transactions and confirms the results

View File

@ -546,7 +546,9 @@ public:
constexpr static FileIdentifier file_identifier = 13300811;
StringRef() : data(0), length(0) {}
StringRef( Arena& p, const StringRef& toCopy ) : data( new (p) uint8_t[toCopy.size()] ), length( toCopy.size() ) {
memcpy( (void*)data, toCopy.data, length );
if (length > 0) {
memcpy((void*)data, toCopy.data, length);
}
}
StringRef( Arena& p, const std::string& toCopy ) : length( (int)toCopy.size() ) {
UNSTOPPABLE_ASSERT( toCopy.size() <= std::numeric_limits<int>::max());
@ -554,7 +556,9 @@ public:
if (length) memcpy( (void*)data, &toCopy[0], length );
}
StringRef( Arena& p, const uint8_t* toCopy, int length ) : data( new (p) uint8_t[length] ), length(length) {
memcpy( (void*)data, toCopy, length );
if (length > 0) {
memcpy((void*)data, toCopy, length);
}
}
StringRef( const uint8_t* data, int length ) : data(data), length(length) {}
StringRef( const std::string& s ) : data((const uint8_t*)s.c_str()), length((int)s.size()) {
@ -573,17 +577,25 @@ public:
bool startsWith( const StringRef& s ) const { return size() >= s.size() && !memcmp(begin(), s.begin(), s.size()); }
bool endsWith( const StringRef& s ) const { return size() >= s.size() && !memcmp(end()-s.size(), s.begin(), s.size()); }
StringRef withPrefix( const StringRef& prefix, Arena& arena ) const {
uint8_t* s = new (arena) uint8_t[ prefix.size() + size() ];
memcpy(s, prefix.begin(), prefix.size());
memcpy(s+prefix.size(), begin(), size());
return StringRef(s,prefix.size() + size());
StringRef withPrefix(const StringRef& prefix, Arena& arena) const {
uint8_t* s = new (arena) uint8_t[prefix.size() + size()];
if (prefix.size() > 0) {
memcpy(s, prefix.begin(), prefix.size());
}
if (size() > 0) {
memcpy(s + prefix.size(), begin(), size());
}
return StringRef(s, prefix.size() + size());
}
StringRef withSuffix( const StringRef& suffix, Arena& arena ) const {
uint8_t* s = new (arena) uint8_t[ suffix.size() + size() ];
memcpy(s, begin(), size());
memcpy(s+size(), suffix.begin(), suffix.size());
if (size() > 0) {
memcpy(s, begin(), size());
}
if (suffix.size() > 0) {
memcpy(s + size(), suffix.begin(), suffix.size());
}
return StringRef(s,suffix.size() + size());
}
@ -644,9 +656,11 @@ public:
int expectedSize() const { return size(); }
int compare( StringRef const& other ) const {
int c = memcmp( begin(), other.begin(), std::min( size(), other.size() ) );
if (c!=0) return c;
int compare(StringRef const& other) const {
if (std::min(size(), other.size()) > 0) {
int c = memcmp(begin(), other.begin(), std::min(size(), other.size()));
if (c != 0) return c;
}
return size() - other.size();
}
@ -782,17 +796,24 @@ struct dynamic_size_traits<StringRef> : std::true_type {
}
};
inline bool operator == (const StringRef& lhs, const StringRef& rhs ) {
inline bool operator==(const StringRef& lhs, const StringRef& rhs) {
if (lhs.size() == 0 && rhs.size() == 0) {
return true;
}
return lhs.size() == rhs.size() && !memcmp(lhs.begin(), rhs.begin(), lhs.size());
}
inline bool operator < ( const StringRef& lhs, const StringRef& rhs ) {
int c = memcmp( lhs.begin(), rhs.begin(), std::min(lhs.size(), rhs.size()) );
if (c!=0) return c<0;
inline bool operator<(const StringRef& lhs, const StringRef& rhs) {
if (std::min(lhs.size(), rhs.size()) > 0) {
int c = memcmp(lhs.begin(), rhs.begin(), std::min(lhs.size(), rhs.size()));
if (c != 0) return c < 0;
}
return lhs.size() < rhs.size();
}
inline bool operator > ( const StringRef& lhs, const StringRef& rhs ) {
int c = memcmp( lhs.begin(), rhs.begin(), std::min(lhs.size(), rhs.size()) );
if (c!=0) return c>0;
inline bool operator>(const StringRef& lhs, const StringRef& rhs) {
if (std::min(lhs.size(), rhs.size()) > 0) {
int c = memcmp(lhs.begin(), rhs.begin(), std::min(lhs.size(), rhs.size()));
if (c != 0) return c > 0;
}
return lhs.size() > rhs.size();
}
inline bool operator != (const StringRef& lhs, const StringRef& rhs ) { return !(lhs==rhs); }
@ -903,7 +924,9 @@ public:
VectorRef(Arena& p, const VectorRef<T, S>& toCopy, typename std::enable_if<memcpy_able<T2>::value, int>::type = 0)
: VPS(toCopy), data((T*)new (p) uint8_t[sizeof(T) * toCopy.size()]), m_size(toCopy.size()),
m_capacity(toCopy.size()) {
memcpy(data, toCopy.data, m_size * sizeof(T));
if (m_size > 0) {
memcpy(data, toCopy.data, m_size * sizeof(T));
}
}
// Arena constructor for Ref types, which must have an Arena constructor
@ -997,7 +1020,9 @@ public:
void append(Arena& p, const T* begin, int count) {
if (m_size + count > m_capacity) reallocate(p, m_size + count);
VPS::invalidate();
memcpy(data + m_size, begin, sizeof(T) * count);
if (count > 0) {
memcpy(data + m_size, begin, sizeof(T) * count);
}
m_size += count;
}
template <class It>
@ -1062,7 +1087,9 @@ private:
requiredCapacity = std::max(m_capacity * 2, requiredCapacity);
// SOMEDAY: Maybe we are right at the end of the arena and can expand cheaply
T* newData = (T*)new (p) uint8_t[requiredCapacity * sizeof(T)];
memcpy(newData, data, m_size * sizeof(T));
if (m_size > 0) {
memcpy(newData, data, m_size * sizeof(T));
}
data = newData;
m_capacity = requiredCapacity;
}

View File

@ -9,6 +9,7 @@ set(FLOW_SRCS
CompressedInt.h
Deque.cpp
Deque.h
DeterministicRandom.cpp
DeterministicRandom.h
Error.cpp
Error.h

View File

@ -42,8 +42,10 @@ public:
// TODO: iterator construction, other constructors
Deque(Deque const& r) : arr(0), begin(0), end(r.size()), mask(r.mask) {
if(r.capacity() > 0)
arr = (T*)aligned_alloc(__alignof(T), capacity()*sizeof(T));
if (r.capacity() > 0) {
arr = (T*)aligned_alloc(std::max(__alignof(T), sizeof(void*)), capacity() * sizeof(T));
ASSERT(arr != nullptr);
}
ASSERT(capacity() >= end || end == 0);
for (uint32_t i=0; i<end; i++)
new (&arr[i]) T(r[i]);
@ -57,8 +59,10 @@ public:
begin = 0;
end = r.size();
mask = r.mask;
if(r.capacity() > 0)
arr = (T*)aligned_alloc(__alignof(T), capacity()*sizeof(T));
if (r.capacity() > 0) {
arr = (T*)aligned_alloc(std::max(__alignof(T), sizeof(void*)), capacity() * sizeof(T));
ASSERT(arr != nullptr);
}
ASSERT(capacity() >= end || end == 0);
for (uint32_t i=0; i<end; i++)
new (&arr[i]) T(r[i]);
@ -163,7 +167,9 @@ private:
size_t newSize = mp1 * 2;
if (newSize > max_size()) throw std::bad_alloc();
//printf("Growing to %lld (%u-%u mask %u)\n", (long long)newSize, begin, end, mask);
T *newArr = (T*)aligned_alloc(__alignof(T), newSize*sizeof(T)); // SOMEDAY: FastAllocator, exception safety
T* newArr = (T*)aligned_alloc(std::max(__alignof(T), sizeof(void*)),
newSize * sizeof(T)); // SOMEDAY: FastAllocator, exception safety
ASSERT(newArr != nullptr);
for (int i = begin; i != end; i++) {
new (&newArr[i - begin]) T(std::move(arr[i&mask]));
arr[i&mask].~T();

View File

@ -0,0 +1,122 @@
/*
* DeterministicRandom.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flow/DeterministicRandom.h"
uint64_t DeterministicRandom::gen64() {
uint64_t curr = next;
next = (uint64_t(random()) << 32) ^ random();
if (TRACE_SAMPLE()) TraceEvent(SevSample, "Random");
return curr;
}
DeterministicRandom::DeterministicRandom(uint32_t seed, bool useRandLog)
: random((unsigned long)seed), next((uint64_t(random()) << 32) ^ random()), useRandLog(useRandLog) {
UNSTOPPABLE_ASSERT(seed != 0); // docs for mersenne twister say x0>0
};
double DeterministicRandom::random01() {
double d = gen64() / double(uint64_t(-1));
if (randLog && useRandLog) fprintf(randLog, "R01 %f\n", d);
return d;
}
int DeterministicRandom::randomInt(int min, int maxPlusOne) {
ASSERT(min < maxPlusOne);
unsigned int range;
if (maxPlusOne < 0)
range = std::abs(maxPlusOne - min);
else {
range = maxPlusOne;
range -= min;
}
uint64_t v = (gen64() % range);
int i;
if (min < 0 && (-static_cast<unsigned int>(min + 1)) >= v)
i = -static_cast<int>(-static_cast<unsigned int>(min + 1) - v) - 1;
else
i = v + min;
if (randLog && useRandLog) fprintf(randLog, "Rint %d\n", i);
return i;
}
int64_t DeterministicRandom::randomInt64(int64_t min, int64_t maxPlusOne) {
ASSERT(min < maxPlusOne);
uint64_t range;
if (maxPlusOne < 0)
range = std::abs(maxPlusOne - min);
else {
range = maxPlusOne;
range -= min;
}
uint64_t v = (gen64() % range);
int64_t i;
if (min < 0 && (-static_cast<uint64_t>(min + 1)) >= v)
i = -static_cast<int64_t>(-static_cast<uint64_t>(min + 1) - v) - 1;
else
i = v + min;
if (randLog && useRandLog) fprintf(randLog, "Rint64 %" PRId64 "\n", i);
return i;
}
uint32_t DeterministicRandom::randomUInt32() {
return gen64();
}
uint32_t DeterministicRandom::randomSkewedUInt32(uint32_t min, uint32_t maxPlusOne) {
std::uniform_real_distribution<double> distribution(std::log(min), std::log(maxPlusOne - 1));
double logpower = distribution(random);
uint32_t loguniform = static_cast<uint32_t>(std::pow(10, logpower));
// doubles can be imprecise, so let's make sure we don't violate an edge case.
return std::max(std::min(loguniform, maxPlusOne - 1), min);
}
UID DeterministicRandom::randomUniqueID() {
uint64_t x, y;
x = gen64();
y = gen64();
if (randLog && useRandLog) fprintf(randLog, "Ruid %" PRIx64 " %" PRIx64 "\n", x, y);
return UID(x, y);
}
char DeterministicRandom::randomAlphaNumeric() {
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char c = alphanum[gen64() % 62];
if (randLog && useRandLog) fprintf(randLog, "Rchar %c\n", c);
return c;
}
std::string DeterministicRandom::randomAlphaNumeric(int length) {
std::string s;
s.reserve(length);
for (int i = 0; i < length; i++) s += randomAlphaNumeric();
return s;
}
uint64_t DeterministicRandom::peek() const {
return next;
}
void DeterministicRandom::addref() {
ReferenceCounted<DeterministicRandom>::addref();
}
void DeterministicRandom::delref() {
ReferenceCounted<DeterministicRandom>::delref();
}

View File

@ -36,99 +36,21 @@ private:
uint64_t next;
bool useRandLog;
uint64_t gen64() {
uint64_t curr = next;
next = (uint64_t(random()) << 32) ^ random();
if (TRACE_SAMPLE()) TraceEvent(SevSample, "Random");
return curr;
}
uint64_t gen64();
public:
DeterministicRandom( uint32_t seed, bool useRandLog=false ) : random( (unsigned long)seed ), next( (uint64_t(random()) << 32) ^ random() ), useRandLog(useRandLog) {
UNSTOPPABLE_ASSERT( seed != 0 ); // docs for mersenne twister say x0>0
};
double random01() {
double d = gen64() / double(uint64_t(-1));
if (randLog && useRandLog) fprintf(randLog, "R01 %f\n", d);
return d;
}
int randomInt(int min, int maxPlusOne) {
ASSERT(min < maxPlusOne);
unsigned int range;
if (maxPlusOne < 0)
range = std::abs(maxPlusOne - min);
else {
range = maxPlusOne;
range -= min;
}
uint64_t v = (gen64() % range);
int i;
if (min < 0 && ((unsigned int) -min) > v)
i = -(int)(((unsigned int) -min) - v);
else
i = v + min;
if (randLog && useRandLog) fprintf(randLog, "Rint %d\n", i);
return i;
}
int64_t randomInt64(int64_t min, int64_t maxPlusOne) {
ASSERT(min < maxPlusOne);
uint64_t range;
if (maxPlusOne < 0)
range = std::abs(maxPlusOne - min);
else {
range = maxPlusOne;
range -= min;
}
uint64_t v = (gen64() % range);
int64_t i;
if (min < 0 && ((uint64_t) -min) > v)
i = -(int64_t)(((uint64_t) -min) - v);
else
i = v + min;
if (randLog && useRandLog) fprintf(randLog, "Rint64 %" PRId64 "\n", i);
return i;
}
uint32_t randomUInt32() { return gen64(); }
uint32_t randomSkewedUInt32(uint32_t min, uint32_t maxPlusOne) {
std::uniform_real_distribution<double> distribution( std::log(min), std::log(maxPlusOne-1) );
double logpower = distribution(random);
uint32_t loguniform = static_cast<uint32_t>( std::pow( 10, logpower ) );
// doubles can be imprecise, so let's make sure we don't violate an edge case.
return std::max(std::min(loguniform, maxPlusOne-1), min);
}
UID randomUniqueID() {
uint64_t x,y;
x = gen64();
y = gen64();
if (randLog && useRandLog) fprintf(randLog, "Ruid %" PRIx64 " %" PRIx64 "\n", x, y);
return UID(x,y);
}
char randomAlphaNumeric() {
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char c = alphanum[ gen64() % 62 ];
if (randLog && useRandLog) fprintf(randLog, "Rchar %c\n", c);
return c;
}
std::string randomAlphaNumeric( int length ) {
std::string s;
s.reserve( length );
for( int i = 0; i < length; i++ )
s += randomAlphaNumeric();
return s;
}
uint64_t peek() const { return next; }
virtual void addref() { ReferenceCounted<DeterministicRandom>::addref(); }
virtual void delref() { ReferenceCounted<DeterministicRandom>::delref(); }
DeterministicRandom(uint32_t seed, bool useRandLog = false);
double random01() override;
int randomInt(int min, int maxPlusOne) override;
int64_t randomInt64(int64_t min, int64_t maxPlusOne) override;
uint32_t randomUInt32() override;
uint32_t randomSkewedUInt32(uint32_t min, uint32_t maxPlusOne) override;
UID randomUniqueID() override;
char randomAlphaNumeric() override;
std::string randomAlphaNumeric(int length) override;
uint64_t peek() const override;
void addref() override;
void delref() override;
};
#endif

View File

@ -527,16 +527,6 @@ inline static void* aligned_alloc(size_t alignment, size_t size) { return memali
#if !defined(HAS_ALIGNED_ALLOC)
#include <cstdlib>
inline static void* aligned_alloc(size_t alignment, size_t size) {
// Linux's aligned_alloc() requires alignment to be a power of 2. While posix_memalign()
// also requires this, in addition it requires alignment to be a multiple of sizeof(void *).
// Rather than add this requirement to the platform::aligned_alloc() interface we will simply
// upgrade powers of 2 which are less than sizeof(void *) to be exactly sizeof(void *). Non
// powers of 2 of any size will fail as they would on other platforms. This change does not
// break the platform::aligned_alloc() contract as all addresses which are aligned to
// sizeof(void *) are also aligned to any power of 2 less than sizeof(void *).
if(alignment != 0 && alignment < sizeof(void *) && (alignment & (alignment - 1)) == 0) {
alignment = sizeof(void *);
}
void* ptr = nullptr;
posix_memalign(&ptr, alignment, size);
return ptr;

View File

@ -699,6 +699,8 @@ private:
} else {
load_<Alternative + 1>(type_tag, member);
}
} else {
member = std::decay_t<decltype(member)>{};
}
}
};
@ -809,6 +811,7 @@ struct LoadMember {
if constexpr (is_vector_of_union_like<Member>) {
if (!field_present()) {
i += 2;
member = std::decay_t<decltype(member)>{};
return;
}
const uint8_t* types_current = &message[vtable[i++]];
@ -829,6 +832,8 @@ struct LoadMember {
if (types_current[i] > 0) {
uint8_t type_tag = types_current[i] - 1; // Flatbuffers indexes from 1.
(LoadAlternative<Context, union_like_traits<T>>{ context, current }).load(type_tag, value);
} else {
value = std::decay_t<decltype(value)>{};
}
*inserter = std::move(value);
++inserter;
@ -837,6 +842,7 @@ struct LoadMember {
} else if constexpr (is_union_like<Member>) {
if (!field_present()) {
i += 2;
member = std::decay_t<decltype(member)>{};
return;
}
uint8_t fb_type_tag;
@ -846,6 +852,8 @@ struct LoadMember {
if (field_present() && fb_type_tag > 0) {
(LoadAlternative<Context, union_like_traits<Member>>{ context, &message[vtable[i]] })
.load(type_tag, member);
} else {
member = std::decay_t<decltype(member)>{};
}
++i;
} else if constexpr (_SizeOf<Member>::size == 0) {
@ -853,6 +861,8 @@ struct LoadMember {
} else {
if (field_present()) {
load_helper(member, &message[vtable[i]], context);
} else {
member = std::decay_t<decltype(member)>{};
}
++i;
}
@ -1040,10 +1050,10 @@ struct LoadSaveHelper<std::vector<bool, Alloc>, Context> : Context {
current += sizeof(uint32_t);
member.clear();
member.resize(length);
bool m;
uint8_t m;
for (uint32_t i = 0; i < length; ++i) {
load_helper(m, current, *this);
member[i] = m;
member[i] = m != 0;
current += fb_size<bool>;
}
}
@ -1158,7 +1168,7 @@ struct NoFileIdentifier {};
template <class T>
struct EnsureTable
: std::conditional_t<HasFileIdentifier<T>::value, detail::YesFileIdentifier<T>, detail::NoFileIdentifier> {
EnsureTable() = default;
EnsureTable() : t() {}
EnsureTable(const T& t) : t(t) {}
template <class Archive>
void serialize(Archive& ar) {

View File

@ -13,6 +13,7 @@
<ItemGroup>
<ActorCompiler Include="ActorCollection.actor.cpp" />
<ActorCompiler Include="CompressedInt.actor.cpp" />
<ClCompile Include="DeterministicRandom.cpp" />
<ClCompile Include="Deque.cpp" />
<ClCompile Include="Error.cpp" />
<ClCompile Include="FastAlloc.cpp" />

View File

@ -14,6 +14,7 @@
<ActorCompiler Include="TDMetric.actor.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="DeterministicRandom.cpp" />
<ClCompile Include="Error.cpp" />
<ClCompile Include="FastAlloc.cpp" />
<ClCompile Include="Hash3.c" />

View File

@ -897,11 +897,6 @@ struct Quorum : SAV<Void> {
template <class T>
class QuorumCallback : public Callback<T> {
public:
QuorumCallback(Future<T> future, Quorum<T>* head)
: head(head)
{
future.addCallbackAndClear(this);
}
virtual void fire(const T& value) {
Callback<T>::remove();
Callback<T>::next = 0;
@ -914,7 +909,11 @@ public:
}
private:
template <class U>
friend Future<Void> quorum(std::vector<Future<U>> const& results, int n);
Quorum<T>* head;
QuorumCallback() = default;
QuorumCallback(Future<T> future, Quorum<T>* head) : head(head) { future.addCallbackAndClear(this); }
};
template <class T>
@ -925,15 +924,15 @@ Future<Void> quorum(std::vector<Future<T>> const& results, int n) {
Quorum<T>* q = new (allocateFast(size)) Quorum<T>(n, results.size());
QuorumCallback<T>* nextCallback = q->callbacks();
for (auto & r : results) {
for (auto& r : results) {
if (r.isReady()) {
new (nextCallback) QuorumCallback<T>();
nextCallback->next = 0;
if (r.isError())
q->oneError(r.getError());
else
q->oneSuccess();
}
else
} else
new (nextCallback) QuorumCallback<T>(r, q);
++nextCallback;
}

View File

@ -324,9 +324,11 @@ public:
serializeBytes(bytes.begin(), bytes.size());
}
void serializeBytes(const void* data, int bytes) {
valgrindCheck( data, bytes, "serializeBytes" );
void* p = writeBytes(bytes);
memcpy(p, data, bytes);
if (bytes > 0) {
valgrindCheck(data, bytes, "serializeBytes");
void* p = writeBytes(bytes);
memcpy(p, data, bytes);
}
}
template <class T>
void serializeBinaryItem( const T& t ) {
@ -456,7 +458,9 @@ private:
}
Arena newArena;
uint8_t* newData = new ( newArena ) uint8_t[ allocated ];
memcpy(newData, data, p);
if (p > 0) {
memcpy(newData, data, p);
}
arena = newArena;
data = newData;
}