Merge branch 'master' into mengxu/fr-code-improvement-PR

This commit is contained in:
Meng Xu 2020-05-01 09:26:29 -07:00
commit 038f3834fc
46 changed files with 900 additions and 106 deletions

View File

@ -146,6 +146,10 @@ set(SEED "0x${SEED_}" CACHE STRING "Random seed for testing")
# components
################################################################################
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
include_directories(/usr/local/include)
endif()
include(CompileBoost)
add_subdirectory(flow)
add_subdirectory(fdbrpc)
@ -173,6 +177,10 @@ else()
include(CPack)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
add_link_options(-lexecinfo)
endif()
################################################################################
# process compile commands for IDE
################################################################################

View File

@ -9,4 +9,4 @@ set(SRCS
FDBLibTLSVerify.h)
add_library(FDBLibTLS STATIC ${SRCS})
target_link_libraries(FDBLibTLS PUBLIC LibreSSL boost_target PRIVATE flow)
target_link_libraries(FDBLibTLS PUBLIC OpenSSL::SSL boost_target PRIVATE flow)

View File

@ -123,6 +123,37 @@ cmake -G Xcode -DOPEN_FOR_IDE=ON <FDB_SOURCE_DIRECTORY>
You should create a second build-directory which you will use for building
(probably with make or ninja) and debugging.
#### FreeBSD
1. Check out this repo on your server.
1. Install compile-time dependencies from ports.
1. (Optional) Use tmpfs & ccache for significantly faster repeat builds
1. (Optional) Install a [JDK](https://www.freshports.org/java/openjdk8/)
for Java Bindings. FoundationDB currently builds with Java 8.
1. Navigate to the directory where you checked out the foundationdb
repo.
1. Build from source.
```shell
sudo pkg install -r FreeBSD \
shells/bash devel/cmake devel/ninja devel/ccache \
lang/mono lang/python3 \
devel/boost-libs devel/libeio \
security/openssl
mkdir .build && cd .build
cmake -G Ninja \
-DUSE_CCACHE=on \
-DDISABLE_TLS=off \
-DUSE_DTRACE=off \
..
ninja -j 10
# run fast tests
ctest -L fast
# run all tests
ctest --output-on-failure -v
```
### Linux
There are no special requirements for Linux. A docker image can be pulled from

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
######################################################
#
# FoundationDB Binding Test Script

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
LOGGING_LEVEL=WARNING

View File

@ -61,7 +61,7 @@ def write_windows_asm(asmfile, functions):
def write_unix_asm(asmfile, functions, prefix):
asmfile.write(".intel_syntax noprefix\n")
if platform == "linux":
if platform == "linux" or platform == "freebsd":
asmfile.write("\n.data\n")
for f in functions:
asmfile.write("\t.extern fdb_api_ptr_%s\n" % f)

View File

@ -12,6 +12,9 @@
#if defined(__linux__)
#include <linux/limits.h>
#elif defined(__FreeBSD__)
#include <sys/stat.h>
#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST
#elif defined(__APPLE__)
#include <sys/syslimits.h>
#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC

View File

@ -25,6 +25,9 @@ platform=$(uname)
if [[ "${platform}" == "Darwin" ]] ; then
FDBLIBDIR="${FDBLIBDIR:-/usr/local/lib}"
libfdbc="libfdb_c.dylib"
elif [[ "${platform}" == "FreeBSD" ]] ; then
FDBLIBDIR="${FDBLIBDIR:-/lib}"
libfdbc="libfdb_c.so"
elif [[ "${platform}" == "Linux" ]] ; then
libfdbc="libfdb_c.so"
custom_libdir="${FDBLIBDIR:-}"
@ -248,8 +251,11 @@ else
:
elif [[ "${status}" -eq 0 ]] ; then
echo "Building generated files."
if [[ "${platform}" == "FreeBSD" ]] ; then
cmd=( 'gmake' '-C' "${fdbdir}" 'bindings/c/foundationdb/fdb_c_options.g.h' )
else
cmd=( 'make' '-C' "${fdbdir}" 'bindings/c/foundationdb/fdb_c_options.g.h' )
fi
echo "${cmd[*]}"
if ! "${cmd[@]}" ; then
let status="${status} + 1"

View File

@ -23,6 +23,8 @@
package directory
import (
"fmt"
"strings"
"github.com/apple/foundationdb/bindings/go/src/fdb"
"github.com/apple/foundationdb/bindings/go/src/fdb/subspace"
)
@ -43,6 +45,18 @@ type directorySubspace struct {
layer []byte
}
// String implements the fmt.Stringer interface and returns human-readable
// string representation of this object.
func (ds directorySubspace) String() string {
var path string
if len(ds.path) > 0 {
path = "(" + strings.Join(ds.path, ",") + ")"
} else {
path = "nil"
}
return fmt.Sprintf("DirectorySubspace(%s, %s)", path, fdb.Printable(ds.Bytes()))
}
func (d directorySubspace) CreateOrOpen(t fdb.Transactor, path []string, layer []byte) (DirectorySubspace, error) {
return d.dl.CreateOrOpen(t, d.dl.partitionSubpath(d.path, path), layer)
}

View File

@ -35,6 +35,8 @@ package subspace
import (
"bytes"
"errors"
"fmt"
"github.com/apple/foundationdb/bindings/go/src/fdb"
"github.com/apple/foundationdb/bindings/go/src/fdb/tuple"
)
@ -82,7 +84,7 @@ type Subspace interface {
}
type subspace struct {
b []byte
rawPrefix []byte
}
// AllKeys returns the Subspace corresponding to all keys in a FoundationDB
@ -105,40 +107,46 @@ func FromBytes(b []byte) Subspace {
return subspace{s}
}
// String implements the fmt.Stringer interface and return the subspace
// as a human readable byte string provided by fdb.Printable.
func (s subspace) String() string {
return fmt.Sprintf("Subspace(rawPrefix=%s)", fdb.Printable(s.rawPrefix))
}
func (s subspace) Sub(el ...tuple.TupleElement) Subspace {
return subspace{concat(s.Bytes(), tuple.Tuple(el).Pack()...)}
}
func (s subspace) Bytes() []byte {
return s.b
return s.rawPrefix
}
func (s subspace) Pack(t tuple.Tuple) fdb.Key {
return fdb.Key(concat(s.b, t.Pack()...))
return fdb.Key(concat(s.rawPrefix, t.Pack()...))
}
func (s subspace) PackWithVersionstamp(t tuple.Tuple) (fdb.Key, error) {
return t.PackWithVersionstamp(s.b)
return t.PackWithVersionstamp(s.rawPrefix)
}
func (s subspace) Unpack(k fdb.KeyConvertible) (tuple.Tuple, error) {
key := k.FDBKey()
if !bytes.HasPrefix(key, s.b) {
if !bytes.HasPrefix(key, s.rawPrefix) {
return nil, errors.New("key is not in subspace")
}
return tuple.Unpack(key[len(s.b):])
return tuple.Unpack(key[len(s.rawPrefix):])
}
func (s subspace) Contains(k fdb.KeyConvertible) bool {
return bytes.HasPrefix(k.FDBKey(), s.b)
return bytes.HasPrefix(k.FDBKey(), s.rawPrefix)
}
func (s subspace) FDBKey() fdb.Key {
return fdb.Key(s.b)
return fdb.Key(s.rawPrefix)
}
func (s subspace) FDBRangeKeys() (fdb.KeyConvertible, fdb.KeyConvertible) {
return fdb.Key(concat(s.b, 0x00)), fdb.Key(concat(s.b, 0xFF))
return fdb.Key(concat(s.rawPrefix, 0x00)), fdb.Key(concat(s.rawPrefix, 0xFF))
}
func (s subspace) FDBRangeKeySelectors() (fdb.Selectable, fdb.Selectable) {

View File

@ -0,0 +1,15 @@
package subspace
import (
"fmt"
"testing"
)
func TestSubspaceString(t *testing.T) {
printed := fmt.Sprint(Sub([]byte("hello"), "world", 42, 0x99))
expected := "Subspace(rawPrefix=\\x01hello\\x00\\x02world\\x00\\x15*\\x15\\x99)"
if printed != expected {
t.Fatalf("printed subspace result differs, expected %v, got %v", expected, printed)
}
}

View File

@ -43,6 +43,8 @@ import (
"fmt"
"math"
"math/big"
"strconv"
"strings"
"github.com/apple/foundationdb/bindings/go/src/fdb"
)
@ -66,6 +68,48 @@ type TupleElement interface{}
// packing T (modulo type normalization to []byte, uint64, and int64).
type Tuple []TupleElement
// String implements the fmt.Stringer interface and returns human-readable
// string representation of this tuple. For most elements, we use the
// object's default string representation.
func (tuple Tuple) String() string {
sb := strings.Builder{}
printTuple(tuple, &sb)
return sb.String()
}
func printTuple(tuple Tuple, sb *strings.Builder) {
sb.WriteString("(")
for i, t := range tuple {
switch t := t.(type) {
case Tuple:
printTuple(t, sb)
case nil:
sb.WriteString("<nil>")
case string:
sb.WriteString(strconv.Quote(t))
case UUID:
sb.WriteString("UUID(")
sb.WriteString(t.String())
sb.WriteString(")")
case []byte:
sb.WriteString("b\"")
sb.WriteString(fdb.Printable(t))
sb.WriteString("\"")
default:
// For user-defined and standard types, we use standard Go
// printer, which itself uses Stringer interface.
fmt.Fprintf(sb, "%v", t)
}
if (i < len(tuple) - 1) {
sb.WriteString(", ")
}
}
sb.WriteString(")")
}
// UUID wraps a basic byte array as a UUID. We do not provide any special
// methods for accessing or generating the UUID, but as Go does not provide
// a built-in UUID type, this simple wrapper allows for other libraries
@ -73,6 +117,10 @@ type Tuple []TupleElement
// an instance of this type.
type UUID [16]byte
func (uuid UUID) String() string {
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
}
// Versionstamp is struct for a FoundationDB verionstamp. Versionstamps are
// 12 bytes long composed of a 10 byte transaction version and a 2 byte user
// version. The transaction version is filled in at commit time and the user
@ -82,6 +130,11 @@ type Versionstamp struct {
UserVersion uint16
}
// Returns a human-readable string for this Versionstamp.
func (vs Versionstamp) String() string {
return fmt.Sprintf("Versionstamp(%s, %d)", fdb.Printable(vs.TransactionVersion[:]), vs.UserVersion)
}
var incompleteTransactionVersion = [10]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
const versionstampLength = 12

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/gob"
"flag"
"fmt"
"math/rand"
"os"
"testing"
@ -118,3 +119,38 @@ func BenchmarkTuplePacking(b *testing.B) {
})
}
}
func TestTupleString(t *testing.T) {
testCases :=[ ]struct {
input Tuple
expected string
}{
{
Tuple{[]byte("hello"), "world", 42, 0x99},
"(b\"hello\", \"world\", 42, 153)",
},
{
Tuple{nil, Tuple{"Ok", Tuple{1, 2}, "Go"}, 42, 0x99},
"(<nil>, (\"Ok\", (1, 2), \"Go\"), 42, 153)",
},
{
Tuple{"Bool", true, false},
"(\"Bool\", true, false)",
},
{
Tuple{"UUID", testUUID},
"(\"UUID\", UUID(1100aabb-ccdd-eeff-1100-aabbccddeeff))",
},
{
Tuple{"Versionstamp", Versionstamp{[10]byte{0, 0, 0, 0xaa, 0, 0xbb, 0, 0xcc, 0, 0xdd}, 620}},
"(\"Versionstamp\", Versionstamp(\\x00\\x00\\x00\\xaa\\x00\\xbb\\x00\\xcc\\x00\\xdd, 620))",
},
}
for _, testCase := range testCases {
printed := fmt.Sprint(testCase.input)
if printed != testCase.expected {
t.Fatalf("printed tuple result differs, expected %v, got %v", testCase.expected, printed)
}
}
}

View File

@ -1231,6 +1231,8 @@ if platform.system() == 'Windows':
capi_name = 'fdb_c.dll'
elif platform.system() == 'Linux':
capi_name = 'libfdb_c.so'
elif platform.system() == 'FreeBSD':
capi_name = 'libfdb_c.so'
elif platform.system() == 'Darwin':
capi_name = 'libfdb_c.dylib'
elif sys.platform == 'win32':

View File

@ -278,7 +278,51 @@ function(package_bindingtester)
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bindings ${CMAKE_BINARY_DIR}/bindingtester/tests
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/bindingtester.touch"
COMMENT "Copy test files for bindingtester")
add_custom_target(copy_bindingtester_binaries DEPENDS ${outfiles} "${CMAKE_BINARY_DIR}/bindingtester.touch")
add_custom_target(copy_binding_output_files DEPENDS ${CMAKE_BINARY_DIR}/bindingtester.touch python_binding fdb_flow_tester)
add_custom_command(
TARGET copy_binding_output_files
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:fdb_flow_tester> ${bdir}/tests/flow/bin/fdb_flow_tester
COMMENT "Copy Flow tester for bindingtester")
set(generated_binding_files python/fdb/fdboptions.py)
if(WITH_JAVA)
if(NOT FDB_RELEASE)
set(prerelease_string "-PRERELEASE")
else()
set(prerelease_string "")
endif()
add_custom_command(
TARGET copy_binding_output_files
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_BINARY_DIR}/packages/fdb-java-${CMAKE_PROJECT_VERSION}${prerelease_string}.jar
${bdir}/tests/java/foundationdb-client.jar
COMMENT "Copy Java bindings for bindingtester")
add_dependencies(copy_binding_output_files fat-jar)
add_dependencies(copy_binding_output_files foundationdb-tests)
set(generated_binding_files ${generated_binding_files} java/foundationdb-tests.jar)
endif()
if(WITH_GO AND NOT OPEN_FOR_IDE)
add_dependencies(copy_binding_output_files fdb_go_tester fdb_go)
add_custom_command(
TARGET copy_binding_output_files
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/bindings/go/bin/_stacktester ${bdir}/tests/go/build/bin/_stacktester
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_BINARY_DIR}/bindings/go/src/github.com/apple/foundationdb/bindings/go/src/fdb/generated.go # SRC
${bdir}/tests/go/src/fdb/ # DEST
COMMENT "Copy generated.go for bindingtester")
endif()
foreach(generated IN LISTS generated_binding_files)
add_custom_command(
TARGET copy_binding_output_files
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/bindings/${generated} ${bdir}/tests/${generated}
COMMENT "Copy ${generated} to bindingtester")
endforeach()
add_custom_target(copy_bindingtester_binaries
DEPENDS ${outfiles} "${CMAKE_BINARY_DIR}/bindingtester.touch" copy_binding_output_files)
add_dependencies(copy_bindingtester_binaries strip_only_fdbserver strip_only_fdbcli strip_only_fdb_c)
set(tar_file ${CMAKE_BINARY_DIR}/packages/bindingtester-${CMAKE_PROJECT_VERSION}.tar.gz)
add_custom_command(

View File

@ -1,6 +1,7 @@
include(CompilerChecks)
env_set(USE_GPERFTOOLS OFF BOOL "Use gperfools for profiling")
env_set(USE_DTRACE ON BOOL "Enable dtrace probes on supported platforms")
env_set(USE_VALGRIND OFF BOOL "Compile for valgrind usage")
env_set(USE_VALGRIND_FOR_CTEST ${USE_VALGRIND} BOOL "Use valgrind for ctest")
env_set(ALLOC_INSTRUMENTATION OFF BOOL "Instrument alloc")
@ -255,7 +256,7 @@ else()
check_symbol_exists(DTRACE_PROBE sys/sdt.h SUPPORT_DTRACE)
check_symbol_exists(aligned_alloc stdlib.h HAS_ALIGNED_ALLOC)
message(STATUS "Has aligned_alloc: ${HAS_ALIGNED_ALLOC}")
if(SUPPORT_DTRACE)
if((SUPPORT_DTRACE) AND (USE_DTRACE))
add_compile_definitions(DTRACE_PROBES)
endif()
if(HAS_ALIGNED_ALLOC)

View File

@ -11,26 +11,27 @@ endif()
################################################################################
# SSL
################################################################################
include(CheckSymbolExists)
set(DISABLE_TLS OFF CACHE BOOL "Don't try to find LibreSSL and always build without TLS support")
set(DISABLE_TLS OFF CACHE BOOL "Don't try to find OpenSSL and always build without TLS support")
if(DISABLE_TLS)
set(WITH_TLS OFF)
else()
set(OPENSSL_USE_STATIC_LIBS TRUE)
find_package(OpenSSL)
if(NOT OPENSSL_FOUND)
set(LIBRESSL_USE_STATIC_LIBS TRUE)
find_package(LibreSSL)
if (LIBRESSL_FOUND)
add_library(OpenSSL::SSL ALIAS LibreSSL)
endif()
endif()
if(OPENSSL_FOUND OR LIBRESSL_FOUND)
if(OPENSSL_FOUND)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
check_symbol_exists("OPENSSL_INIT_NO_ATEXIT" "openssl/crypto.h" OPENSSL_HAS_NO_ATEXIT)
if(OPENSSL_HAS_NO_ATEXIT)
set(WITH_TLS ON)
add_compile_options(-DHAVE_OPENSSL)
else()
message(STATUS "Neither OpenSSL nor LibreSSL were found - Will compile without TLS Support")
message(STATUS "You can set OPENSSL_ROOT_DIR or LibreSSL_ROOT to the LibreSSL install directory to help cmake find it")
message(WARNING "An OpenSSL version was found, but it doesn't support OPENSSL_INIT_NO_ATEXIT - Will compile without TLS Support")
set(WITH_TLS OFF)
endif()
else()
message(STATUS "OpenSSL was not found - Will compile without TLS Support")
message(STATUS "You can set OPENSSL_ROOT_DIR to help cmake find it")
set(WITH_TLS OFF)
endif()
if(WIN32)
@ -46,7 +47,8 @@ endif()
set(WITH_JAVA OFF)
find_package(JNI 1.8)
find_package(Java 1.8 COMPONENTS Development)
if(JNI_FOUND AND Java_FOUND AND Java_Development_FOUND)
# leave FreeBSD JVM compat for later
if(JNI_FOUND AND Java_FOUND AND Java_Development_FOUND AND NOT (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD"))
set(WITH_JAVA ON)
include(UseJava)
enable_language(Java)

View File

@ -2198,13 +2198,15 @@ ACTOR Future<Void> runFastRestoreAgent(Database db, std::string tagName, std::st
state Version restoreVersion = invalidVersion;
if (ranges.size() > 1) {
fprintf(stderr, "Currently only a single restore range is supported!\n");
throw restore_error();
fprintf(stdout, "[WARNING] Currently only a single restore range is tested!\n");
}
state KeyRange range = (ranges.size() == 0) ? normalKeys : ranges.front();
if (ranges.size() == 0) {
ranges.push_back(ranges.arena(), normalKeys);
}
printf("[INFO] runFastRestoreAgent: num_ranges:%d restore_range:%s\n", ranges.size(), range.toString().c_str());
printf("[INFO] runFastRestoreAgent: restore_ranges:%d first range:%s\n", ranges.size(),
ranges.front().toString().c_str());
if (performRestore) {
if (dbVersion == invalidVersion) {

View File

@ -1373,7 +1373,8 @@ public:
wait(bc->readKeyspaceSnapshot(snapshot.get()));
restorable.ranges = std::move(results.first);
restorable.keyRanges = std::move(results.second);
if (g_network->isSimulated()) {
// TODO: Reenable the sanity check after TooManyFiles error is resolved
if (false && g_network->isSimulated()) {
// Sanity check key ranges
state std::map<std::string, KeyRange>::iterator rit;
for (rit = restorable.keyRanges.begin(); rit != restorable.keyRanges.end(); rit++) {
@ -1776,7 +1777,6 @@ public:
virtual ~BackupContainerBlobStore() {}
Future<Reference<IAsyncFile>> readFile(std::string path) final {
ASSERT(m_bstore->knobs.read_ahead_blocks > 0);
return Reference<IAsyncFile>(
new AsyncFileReadAheadCache(
Reference<IAsyncFile>(new AsyncFileBlobStoreRead(m_bstore, m_bucket, dataPath(path))),

View File

@ -107,8 +107,18 @@ struct MutationRef {
template <class Ar>
void serialize( Ar& ar ) {
if (!ar.isDeserializing && type == ClearRange && equalsKeyAfter(param1, param2)) {
StringRef empty;
serializer(ar, type, param2, empty);
} else {
serializer(ar, type, param1, param2);
}
if (ar.isDeserializing && type == ClearRange && param2 == StringRef() && param1 != StringRef()) {
ASSERT(param1[param1.size()-1] == '\x00');
param2 = param1;
param1 = param2.substr(0, param2.size()-1);
}
}
// These masks define which mutation types have particular properties (they are used to implement isSingleKeyMutation() etc)
enum {

View File

@ -1490,6 +1490,12 @@ namespace dbBackup {
Version bVersion = wait(srcTr->getReadVersion());
beginVersionKey = BinaryWriter::toValue(bVersion, Unversioned());
state Key versionKey = logUidValue.withPrefix(destUidValue).withPrefix(backupLatestVersionsPrefix);
Optional<Key> versionRecord = wait( srcTr->get(versionKey) );
if(!versionRecord.present()) {
srcTr->set(versionKey, beginVersionKey);
}
task->params[BackupAgentBase::destUid] = destUidValue;
wait(srcTr->commit());
@ -1539,9 +1545,6 @@ namespace dbBackup {
if(v.present() && BinaryReader::fromStringRef<Version>(v.get(), Unversioned()) >= BinaryReader::fromStringRef<Version>(task->params[DatabaseBackupAgent::keyFolderId], Unversioned()))
return Void();
Key versionKey = logUidValue.withPrefix(destUidValue).withPrefix(backupLatestVersionsPrefix);
srcTr2->set(versionKey, beginVersionKey);
srcTr2->set( Subspace(databaseBackupPrefixRange.begin).get(BackupAgentBase::keySourceTagName).pack(task->params[BackupAgentBase::keyTagName]), logUidValue );
srcTr2->set( sourceStates.pack(DatabaseBackupAgent::keyFolderId), task->params[DatabaseBackupAgent::keyFolderId] );
srcTr2->set( sourceStates.pack(DatabaseBackupAgent::keyStateStatus), StringRef(BackupAgentBase::getStateText(BackupAgentBase::STATE_RUNNING)));

View File

@ -282,7 +282,18 @@ struct KeyRangeRef {
template <class Ar>
force_inline void serialize(Ar& ar) {
if (!ar.isDeserializing && equalsKeyAfter(begin, end)) {
StringRef empty;
serializer(ar, const_cast<KeyRef&>(end), empty);
} else {
serializer(ar, const_cast<KeyRef&>(begin), const_cast<KeyRef&>(end));
}
if (ar.isDeserializing && end == StringRef() && begin != StringRef()) {
ASSERT(begin[begin.size()-1] == '\x00');
const_cast<KeyRef&>(end) = begin;
const_cast<KeyRef&>(begin) = end.substr(0, end.size()-1);
}
if( begin > end ) {
TraceEvent("InvertedRange").detail("Begin", begin).detail("End", end);
throw inverted_range();

View File

@ -1019,7 +1019,12 @@ public:
return Void();
}
try {
watchFuture = ryw->tr.watch(watch); // throws if there are too many outstanding watches
} catch( Error &e ) {
done.send(Void());
throw;
}
done.send(Void());
wait(watchFuture);

View File

@ -37,6 +37,11 @@
#include <linux/limits.h>
#endif
#ifdef __FreeBSD__
#include <sys/event.h>
#define O_EVTONLY O_RDONLY
#endif
#ifdef __APPLE__
#include <sys/event.h>
#include <mach/mach.h>
@ -78,7 +83,7 @@
#ifdef __linux__
typedef fd_set* fdb_fd_set;
#elif defined __APPLE__
#elif defined(__APPLE__) || defined(__FreeBSD__)
typedef int fdb_fd_set;
#endif
@ -89,7 +94,7 @@ void monitor_fd( fdb_fd_set list, int fd, int* maxfd, void* cmd ) {
FD_SET( fd, list );
if ( fd > *maxfd )
*maxfd = fd;
#elif defined __APPLE__
#elif defined(__APPLE__) || defined(__FreeBSD__)
/* ignore maxfd */
struct kevent ev;
EV_SET( &ev, fd, EVFILT_READ, EV_ADD, 0, 0, cmd );
@ -100,7 +105,7 @@ void monitor_fd( fdb_fd_set list, int fd, int* maxfd, void* cmd ) {
void unmonitor_fd( fdb_fd_set list, int fd ) {
#ifdef __linux__
FD_CLR( fd, list );
#elif defined __APPLE__
#elif defined(__APPLE__) || defined(__FreeBSD__)
struct kevent ev;
EV_SET( &ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL );
kevent( list, &ev, 1, NULL, 0, NULL ); // FIXME: check?
@ -194,7 +199,7 @@ const char* get_value_multi(const CSimpleIni& ini, const char* key, ...) {
}
double timer() {
#if defined(__linux__)
#if defined(__linux__) || defined(__FreeBSD__)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return double(ts.tv_sec) + (ts.tv_nsec * 1e-9);
@ -913,7 +918,7 @@ void read_child_output( Command* cmd, int pipe_idx, fdb_fd_set fds ) {
}
}
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__FreeBSD__)
void watch_conf_dir( int kq, int* confd_fd, std::string confdir ) {
struct kevent ev;
std::string original = confdir;
@ -1171,7 +1176,11 @@ int main(int argc, char** argv) {
// testPathOps(); return -1;
std::string lockfile = "/var/run/fdbmonitor.pid";
#ifdef __FreeBSD__
std::string _confpath = "/usr/local/etc/foundationdb/foundationdb.conf";
#else
std::string _confpath = "/etc/foundationdb/foundationdb.conf";
#endif
std::vector<const char *> additional_watch_paths;
@ -1266,12 +1275,12 @@ int main(int argc, char** argv) {
#endif
if (daemonize) {
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__FreeBSD__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
if (daemon(0, 0)) {
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__FreeBSD__)
#pragma GCC diagnostic pop
#endif
log_err("daemon", errno, "Unable to daemonize");
@ -1330,7 +1339,7 @@ int main(int argc, char** argv) {
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__FreeBSD__)
int kq = kqueue();
if ( kq < 0 ) {
log_err( "kqueue", errno, "Unable to create kqueue" );
@ -1375,11 +1384,11 @@ int main(int argc, char** argv) {
/* normal will be restored in our main loop in the call to
pselect, but none blocks all signals while processing events */
sigprocmask(SIG_SETMASK, &full_mask, &normal_mask);
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__FreeBSD__)
sigprocmask(0, NULL, &normal_mask);
#endif
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__FreeBSD__)
struct stat st_buf;
struct timespec mtimespec;
@ -1438,7 +1447,7 @@ int main(int argc, char** argv) {
load_conf(confpath.c_str(), uid, gid, &normal_mask, &rfds, &maxfd);
reload_additional_watches = false;
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__FreeBSD__)
load_conf( confpath.c_str(), uid, gid, &normal_mask, watched_fds, &maxfd );
watch_conf_file( kq, &conff_fd, confpath.c_str() );
watch_conf_dir( kq, &confd_fd, confdir );
@ -1476,7 +1485,7 @@ int main(int argc, char** argv) {
if(nfds == 0) {
reload = true;
}
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__FreeBSD__)
int nev = 0;
if(timeout < 0) {
nev = kevent( kq, NULL, 0, &ev, 1, NULL );

View File

@ -49,7 +49,16 @@ if(APPLE)
list(APPEND FDBRPC_THIRD_PARTY_SRCS libcoroutine/asm.S)
endif()
if(NOT WIN32)
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
find_library(EIO eio)
if(EIO)
list(APPEND FDBRPC_THIRD_PARTY_SRCS libcoroutine/context.c)
else()
list(APPEND FDBRPC_THIRD_PARTY_SRCS libcoroutine/context.c libeio/eio.c)
endif()
else()
list(APPEND FDBRPC_THIRD_PARTY_SRCS libcoroutine/context.c libeio/eio.c)
endif()
endif()
add_library(thirdparty STATIC ${FDBRPC_THIRD_PARTY_SRCS})

142
fdbrpc/libeio/config.h.FreeBSD Executable file
View File

@ -0,0 +1,142 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* fdatasync(2) is available */
#define HAVE_FDATASYNC 1
/* futimes(2) is available */
#define HAVE_FUTIMES 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* fallocate(2) is available */
/* #undef HAVE_LINUX_FALLOCATE */
/* Define to 1 if you have the <linux/fiemap.h> header file. */
/* #undef HAVE_LINUX_FIEMAP_H */
/* Define to 1 if you have the <linux/fs.h> header file. */
/* #undef HAVE_LINUX_FS_H */
/* splice/vmsplice/tee(2) are available */
/* #undef HAVE_LINUX_SPLICE */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* posix_fadvise(2) is available */
#define HAVE_POSIX_FADVISE 1
/* posix_madvise(2) is available */
#define HAVE_POSIX_MADVISE 1
/* prctl(PR_SET_NAME) is available */
/* #undef HAVE_PRCTL_SET_NAME */
/* readahead(2) is available (linux) */
/* #undef HAVE_READAHEAD */
/* sendfile(2) is available and supported */
#define HAVE_SENDFILE 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* sync_file_range(2) is available */
/* #undef HAVE_SYNC_FILE_RANGE */
/* Define to 1 if you have the <sys/prctl.h> header file. */
/* #undef HAVE_SYS_PRCTL_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* syscall(__NR_syncfs) is available */
/* #undef HAVE_SYS_SYNCFS */
/* Define to 1 if you have the <sys/syscall.h> header file. */
#define HAVE_SYS_SYSCALL_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* utimes(2) is available */
#define HAVE_UTIMES 1
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "libeio"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Version number of package */
#define VERSION "1.0"
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */

View File

@ -39,6 +39,8 @@
#ifdef __linux__
#include "config.h.linux"
#elif defined(__FreeBSD__)
#include "config.h.FreeBSD"
#elif defined(__APPLE__)
#include "config.h.osx"
#endif

View File

@ -461,7 +461,7 @@ void ServerKnobs::initialize(bool randomize, ClientKnobs* clientKnobs, bool isSi
init( SPRING_BYTES_TLOG_BATCH, 300e6 ); if( smallTlogTarget ) SPRING_BYTES_TLOG_BATCH = 150e3;
init( TLOG_SPILL_THRESHOLD, 1500e6 ); if( smallTlogTarget ) TLOG_SPILL_THRESHOLD = 1500e3; if( randomize && BUGGIFY ) TLOG_SPILL_THRESHOLD = 0;
init( REFERENCE_SPILL_UPDATE_STORAGE_BYTE_LIMIT, 20e6 ); if( (randomize && BUGGIFY) || smallTlogTarget ) REFERENCE_SPILL_UPDATE_STORAGE_BYTE_LIMIT = 1e6;
init( TLOG_HARD_LIMIT_BYTES, 3000e6 ); if( smallTlogTarget ) TLOG_HARD_LIMIT_BYTES = 3000e3;
init( TLOG_HARD_LIMIT_BYTES, 3000e6 ); if( smallTlogTarget ) TLOG_HARD_LIMIT_BYTES = 30e6;
init( TLOG_RECOVER_MEMORY_LIMIT, TARGET_BYTES_PER_TLOG + SPRING_BYTES_TLOG );
init( MAX_TRANSACTIONS_PER_BYTE, 1000 );
@ -569,7 +569,7 @@ void ServerKnobs::initialize(bool randomize, ClientKnobs* clientKnobs, bool isSi
// Fast Restore
init( FASTRESTORE_FAILURE_TIMEOUT, 3600 );
init( FASTRESTORE_HEARTBEAT_INTERVAL, 60 );
init( FASTRESTORE_SAMPLING_PERCENT, 1 ); if( randomize && BUGGIFY ) { FASTRESTORE_SAMPLING_PERCENT = deterministicRandom()->random01() * 100; }
init( FASTRESTORE_SAMPLING_PERCENT, 80 ); if( randomize && BUGGIFY ) { FASTRESTORE_SAMPLING_PERCENT = deterministicRandom()->random01() * 100; }
init( FASTRESTORE_NUM_LOADERS, 3 ); if( randomize && BUGGIFY ) { FASTRESTORE_NUM_LOADERS = deterministicRandom()->random01() * 10 + 1; }
init( FASTRESTORE_NUM_APPLIERS, 3 ); if( randomize && BUGGIFY ) { FASTRESTORE_NUM_APPLIERS = deterministicRandom()->random01() * 10 + 1; }
init( FASTRESTORE_TXN_BATCH_MAX_BYTES, 512.0 ); if( randomize && BUGGIFY ) { FASTRESTORE_TXN_BATCH_MAX_BYTES = deterministicRandom()->random01() * 1024.0 * 1024.0 + 1.0; }
@ -583,7 +583,7 @@ void ServerKnobs::initialize(bool randomize, ClientKnobs* clientKnobs, bool isSi
init( FASTRESTORE_APPLYING_PARALLELISM, 100 ); if( randomize && BUGGIFY ) { FASTRESTORE_APPLYING_PARALLELISM = deterministicRandom()->random01() * 10 + 1; }
init( FASTRESTORE_MONITOR_LEADER_DELAY, 5 ); if( randomize && BUGGIFY ) { FASTRESTORE_MONITOR_LEADER_DELAY = deterministicRandom()->random01() * 100; }
init( FASTRESTORE_STRAGGLER_THRESHOLD_SECONDS, 60 ); if( randomize && BUGGIFY ) { FASTRESTORE_STRAGGLER_THRESHOLD_SECONDS = deterministicRandom()->random01() * 240 + 10; }
init( FASTRESTORE_TRACK_REQUEST_LATENCY, true ); if( randomize && BUGGIFY ) { FASTRESTORE_TRACK_REQUEST_LATENCY = false; }
init( FASTRESTORE_TRACK_REQUEST_LATENCY, false ); if( randomize && BUGGIFY ) { FASTRESTORE_TRACK_REQUEST_LATENCY = false; }
init( FASTRESTORE_TRACK_LOADER_SEND_REQUESTS, false ); if( randomize && BUGGIFY ) { FASTRESTORE_TRACK_LOADER_SEND_REQUESTS = true; }
init( FASTRESTORE_MEMORY_THRESHOLD_MB_SOFT, 6144 ); if( randomize && BUGGIFY ) { FASTRESTORE_MEMORY_THRESHOLD_MB_SOFT = 1; }
init( FASTRESTORE_WAIT_FOR_MEMORY_LATENCY, 10 ); if( randomize && BUGGIFY ) { FASTRESTORE_WAIT_FOR_MEMORY_LATENCY = 60; }

View File

@ -347,7 +347,7 @@ ACTOR Future<Void> logRouterPeekMessages( LogRouterData* self, TLogPeekRequest r
peekId = req.sequence.get().first;
sequence = req.sequence.get().second;
if (sequence >= SERVER_KNOBS->PARALLEL_GET_MORE_REQUESTS && self->peekTracker.find(peekId) == self->peekTracker.end()) {
throw timed_out();
throw operation_obsolete();
}
auto& trackerData = self->peekTracker[peekId];
if (sequence == 0 && trackerData.sequence_version.find(0) == trackerData.sequence_version.end()) {

View File

@ -1088,6 +1088,10 @@ ACTOR Future<Void> tLogPeekMessages( TLogData* self, TLogPeekRequest req, Refere
state UID peekId;
state double queueStart = now();
if(req.tag.locality == tagLocalityTxs && req.tag.id >= logData->txsTags && logData->txsTags > 0) {
req.tag.id = req.tag.id % logData->txsTags;
}
if(req.sequence.present()) {
try {
peekId = req.sequence.get().first;

View File

@ -1392,6 +1392,10 @@ ACTOR Future<Void> tLogPeekMessages( TLogData* self, TLogPeekRequest req, Refere
state UID peekId;
state double queueStart = now();
if(req.tag.locality == tagLocalityTxs && req.tag.id >= logData->txsTags && logData->txsTags > 0) {
req.tag.id = req.tag.id % logData->txsTags;
}
if(req.sequence.present()) {
try {
peekId = req.sequence.get().first;

View File

@ -112,7 +112,7 @@ ACTOR static Future<Void> handleSendMutationVectorRequest(RestoreSendVersionedMu
// Note: Insert new items into processedFileState will not invalidate the reference.
state NotifiedVersion& curMsgIndex = batchData->processedFileState[req.asset];
TraceEvent(SevDebug, "FastRestoreApplierPhaseReceiveMutations", self->id())
TraceEvent(SevInfo, "FastRestoreApplierPhaseReceiveMutations", self->id())
.detail("BatchIndex", req.batchIndex)
.detail("RestoreAsset", req.asset.toString())
.detail("RestoreAssetMesssageIndex", curMsgIndex.get())
@ -156,7 +156,7 @@ ACTOR static Future<Void> handleSendMutationVectorRequest(RestoreSendVersionedMu
}
req.reply.send(RestoreCommonReply(self->id(), isDuplicated));
TraceEvent(SevDebug, "FastRestoreApplierPhaseReceiveMutationsDone", self->id())
TraceEvent(SevInfo, "FastRestoreApplierPhaseReceiveMutationsDone", self->id())
.detail("BatchIndex", req.batchIndex)
.detail("RestoreAsset", req.asset.toString())
.detail("ProcessedMessageIndex", curMsgIndex.get())

View File

@ -603,7 +603,7 @@ ACTOR Future<Void> sendMutationsToApplier(VersionedMutationsMap* pkvOps, int bat
void splitMutation(std::map<Key, UID>* pRangeToApplier, MutationRef m, Arena& mvector_arena,
VectorRef<MutationRef>& mvector, Arena& nodeIDs_arena, VectorRef<UID>& nodeIDs) {
TraceEvent(SevWarn, "FastRestoreSplitMutation").detail("Mutation", m.toString());
TraceEvent(SevDebug, "FastRestoreSplitMutation").detail("Mutation", m.toString());
// mvector[i] should be mapped to nodeID[i]
ASSERT(mvector.empty());
ASSERT(nodeIDs.empty());

View File

@ -196,7 +196,7 @@ ACTOR Future<Void> startProcessRestoreRequests(Reference<RestoreMasterData> self
state int numTries = 0;
state int restoreIndex = 0;
TraceEvent("FastRestoreMasterWaitOnRestoreRequests", self->id());
TraceEvent("FastRestoreMasterWaitOnRestoreRequests", self->id()).detail("RestoreRequests", restoreRequests.size());
// DB has been locked where restore request is submitted
wait(clearDB(cx));
@ -636,6 +636,8 @@ ACTOR static Future<Standalone<VectorRef<RestoreRequest>>> collectRestoreRequest
TraceEvent("FastRestoreMasterPhaseCollectRestoreRequests")
.detail("RestoreRequest", restoreRequests.back().toString());
}
} else {
TraceEvent(SevWarnAlways, "FastRestoreMasterPhaseCollectRestoreRequestsEmptyRequests");
}
break;
}

View File

@ -100,6 +100,7 @@ void updateProcessStats(Reference<RestoreRoleData> self) {
// in increasing order of their version batch.
ACTOR Future<Void> isSchedulable(Reference<RestoreRoleData> self, int actorBatchIndex, std::string name) {
self->delayedActors++;
state double memoryThresholdBytes = SERVER_KNOBS->FASTRESTORE_MEMORY_THRESHOLD_MB_SOFT * 1024 * 1024;
loop {
double memory = getSystemStatistics().processMemory;
if (g_network->isSimulated() && BUGGIFY) {
@ -107,13 +108,13 @@ ACTOR Future<Void> isSchedulable(Reference<RestoreRoleData> self, int actorBatch
// memory will be larger than threshold when deterministicRandom()->random01() > 1/2
memory = SERVER_KNOBS->FASTRESTORE_MEMORY_THRESHOLD_MB_SOFT * 2 * deterministicRandom()->random01();
}
if (memory < SERVER_KNOBS->FASTRESTORE_MEMORY_THRESHOLD_MB_SOFT ||
self->finishedBatch.get() + 1 == actorBatchIndex) {
if (memory >= SERVER_KNOBS->FASTRESTORE_MEMORY_THRESHOLD_MB_SOFT) {
if (memory < memoryThresholdBytes || self->finishedBatch.get() + 1 == actorBatchIndex) {
if (memory >= memoryThresholdBytes) {
TraceEvent(SevWarn, "FastRestoreMemoryUsageAboveThreshold")
.detail("BatchIndex", actorBatchIndex)
.detail("FinishedBatch", self->finishedBatch.get())
.detail("Actor", name);
.detail("Actor", name)
.detail("Memory", memory);
}
self->delayedActors--;
break;

View File

@ -1405,6 +1405,10 @@ ACTOR Future<Void> tLogPeekMessages( TLogData* self, TLogPeekRequest req, Refere
state UID peekId;
state double queueStart = now();
if(req.tag.locality == tagLocalityTxs && req.tag.id >= logData->txsTags && logData->txsTags > 0) {
req.tag.id = req.tag.id % logData->txsTags;
}
if(req.sequence.present()) {
try {
peekId = req.sequence.get().first;

View File

@ -60,7 +60,7 @@
#include "fdbmonitor/SimpleIni.h"
#ifdef __linux__
#if defined(__linux__) || defined(__FreeBSD__)
#include <execinfo.h>
#include <signal.h>
#ifdef ALLOC_INSTRUMENTATION
@ -75,6 +75,7 @@
#endif
#include "flow/SimpleOpt.h"
#include <fstream>
#include "flow/actorcompiler.h" // This must be the last #include.
// clang-format off
@ -291,7 +292,7 @@ public:
throw platform_error();
}
permission.set_permissions( &sa );
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
// There is nothing to do here, since the default permissions are fine
#else
#error Port me!
@ -301,7 +302,7 @@ public:
virtual ~WorldReadablePermissions() {
#ifdef _WIN32
LocalFree( sa.lpSecurityDescriptor );
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
// There is nothing to do here, since the default permissions are fine
#else
#error Port me!

View File

@ -48,6 +48,8 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#if defined(__linux__) || defined(__FreeBSD__)
#ifdef USE_GPERFTOOLS
#include "gperftools/profiler.h"
#include "gperftools/heap-profiler.h"
@ -526,7 +528,7 @@ ACTOR Future<Void> registrationClient(
}
}
#if defined(__linux__) && defined(USE_GPERFTOOLS)
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(USE_GPERFTOOLS)
//A set of threads that should be profiled
std::set<std::thread::id> profiledThreads;
@ -538,7 +540,7 @@ int filter_in_thread(void *arg) {
//Enables the calling thread to be profiled
void registerThreadForProfiling() {
#if defined(__linux__) && defined(USE_GPERFTOOLS)
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(USE_GPERFTOOLS)
//Not sure if this is actually needed, but a call to backtrace was advised here:
//http://groups.google.com/group/google-perftools/browse_thread/thread/0dfd74532e038eb8/2686d9f24ac4365f?pli=1
profiledThreads.insert(std::this_thread::get_id());
@ -552,7 +554,7 @@ void registerThreadForProfiling() {
void updateCpuProfiler(ProfilerRequest req) {
switch (req.type) {
case ProfilerRequest::Type::GPROF:
#if defined(__linux__) && defined(USE_GPERFTOOLS) && !defined(VALGRIND)
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(USE_GPERFTOOLS) && !defined(VALGRIND)
switch (req.action) {
case ProfilerRequest::Action::ENABLE: {
const char *path = (const char*)req.outputFile.begin();

View File

@ -827,7 +827,7 @@ struct WriteDuringReadWorkload : TestWorkload {
self->addedConflicts.insert(allKeys, false);
return Void();
}
if( e.code() == error_code_not_committed || e.code() == error_code_commit_unknown_result || e.code() == error_code_transaction_too_large || e.code() == error_code_key_too_large || e.code() == error_code_value_too_large || cancelled )
if( e.code() == error_code_not_committed || e.code() == error_code_commit_unknown_result || e.code() == error_code_transaction_too_large || e.code() == error_code_key_too_large || e.code() == error_code_value_too_large || e.code() == error_code_too_many_watches || cancelled )
throw not_committed();
try {
wait( tr.onError(e) );

View File

@ -94,6 +94,13 @@ elseif(WIN32)
target_link_libraries(flow PUBLIC winmm.lib)
target_link_libraries(flow PUBLIC psapi.lib)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set (FLOW_LIBS ${FLOW_LIBS} execinfo devstat)
find_library(EIO eio)
if(EIO)
target_link_libraries(flow PUBLIC ${EIO})
endif()
endif()
target_link_libraries(flow PRIVATE ${FLOW_LIBS})
if(USE_VALGRIND)
target_link_libraries(flow PUBLIC Valgrind)

View File

@ -41,6 +41,10 @@
#include <linux/mman.h>
#endif
#ifdef __FreeBSD__
#include <sys/mman.h>
#endif
#define FAST_ALLOCATOR_DEBUG 0
#ifdef _MSC_VER
@ -54,6 +58,8 @@
#elif defined(__GNUG__)
#ifdef __linux__
#define INIT_SEG __attribute__ ((init_priority (1000)))
#elif defined(__FreeBSD__)
#define INIT_SEG __attribute__ ((init_priority (1000)))
#elif defined(__APPLE__)
#pragma message "init_priority is not supported on this platform; will this be a problem?"
#define INIT_SEG

View File

@ -55,7 +55,7 @@ intptr_t g_stackYieldLimit = 0;
using namespace boost::asio::ip;
#if defined(__linux__)
#if defined(__linux__) || defined(__FreeBSD__)
#include <execinfo.h>
std::atomic<int64_t> net2RunLoopIterations(0);

View File

@ -104,6 +104,39 @@
#include <sys/sysmacros.h>
#endif
#ifdef __FreeBSD__
/* Needed for processor affinity */
#include <sys/sched.h>
/* Needed for getProcessorTime and setpriority */
#include <sys/syscall.h>
/* Needed for setpriority */
#include <sys/resource.h>
/* Needed for crash handler */
#include <sys/signal.h>
/* Needed for proc info */
#include <sys/user.h>
/* Needed for vm info */
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <sys/cpuset.h>
#include <sys/resource.h>
/* Needed for sysctl info */
#include <sys/sysctl.h>
#include <sys/fcntl.h>
/* Needed for network info */
#include <net/if.h>
#include <net/if_mib.h>
#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/tcp_var.h>
/* Needed for device info */
#include <devstat.h>
#include <kvm.h>
#include <libutil.h>
#endif
#ifdef __APPLE__
#include <sys/uio.h>
#include <sys/syslimits.h>
@ -203,7 +236,7 @@ double getProcessorTimeThread() {
throw platform_error();
}
return FiletimeAsInt64(ftKernel) / double(1e7) + FiletimeAsInt64(ftUser) / double(1e7);
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
return getProcessorTimeGeneric(RUSAGE_THREAD);
#elif defined(__APPLE__)
/* No RUSAGE_THREAD so we use the lower level interface */
@ -255,6 +288,29 @@ uint64_t getResidentMemoryUsage() {
rssize *= sysconf(_SC_PAGESIZE);
return rssize;
#elif defined(__FreeBSD__)
uint64_t rssize = 0;
int status;
pid_t ppid = getpid();
int pidinfo[4];
pidinfo[0] = CTL_KERN;
pidinfo[1] = KERN_PROC;
pidinfo[2] = KERN_PROC_PID;
pidinfo[3] = (int)ppid;
struct kinfo_proc procstk;
size_t len = sizeof(procstk);
status = sysctl(pidinfo, nitems(pidinfo), &procstk, &len, NULL, 0);
if (status < 0){
TraceEvent(SevError, "GetResidentMemoryUsage").GetLastError();
throw platform_error();
}
rssize = (uint64_t)procstk.ki_rssize;
return rssize;
#elif defined(_WIN32)
PROCESS_MEMORY_COUNTERS_EX pmc;
@ -292,6 +348,29 @@ uint64_t getMemoryUsage() {
vmsize *= sysconf(_SC_PAGESIZE);
return vmsize;
#elif defined(__FreeBSD__)
uint64_t vmsize = 0;
int status;
pid_t ppid = getpid();
int pidinfo[4];
pidinfo[0] = CTL_KERN;
pidinfo[1] = KERN_PROC;
pidinfo[2] = KERN_PROC_PID;
pidinfo[3] = (int)ppid;
struct kinfo_proc procstk;
size_t len = sizeof(procstk);
status = sysctl(pidinfo, nitems(pidinfo), &procstk, &len, NULL, 0);
if (status < 0){
TraceEvent(SevError, "GetMemoryUsage").GetLastError();
throw platform_error();
}
vmsize = (uint64_t)procstk.ki_size >> PAGE_SHIFT;
return vmsize;
#elif defined(_WIN32)
PROCESS_MEMORY_COUNTERS_EX pmc;
@ -401,6 +480,52 @@ void getMachineRAMInfo(MachineRAMInfo& memInfo) {
memInfo.available = 1024 * (std::max<int64_t>(0, (memFree-lowWatermark) + std::max(pageCache-lowWatermark, pageCache/2) + std::max(slabReclaimable-lowWatermark, slabReclaimable/2)) - usedSwap);
}
memInfo.committed = memInfo.total - memInfo.available;
#elif defined(__FreeBSD__)
int status;
u_int page_size;
u_int free_count;
u_int active_count;
u_int inactive_count;
u_int wire_count;
size_t uint_size;
uint_size = sizeof(page_size);
status = sysctlbyname("vm.stats.vm.v_page_size", &page_size, &uint_size, NULL, 0);
if (status < 0){
TraceEvent(SevError, "GetMachineMemInfo").GetLastError();
throw platform_error();
}
status = sysctlbyname("vm.stats.vm.v_free_count", &free_count, &uint_size, NULL, 0);
if (status < 0){
TraceEvent(SevError, "GetMachineMemInfo").GetLastError();
throw platform_error();
}
status = sysctlbyname("vm.stats.vm.v_active_count", &active_count, &uint_size, NULL, 0);
if (status < 0){
TraceEvent(SevError, "GetMachineMemInfo").GetLastError();
throw platform_error();
}
status = sysctlbyname("vm.stats.vm.v_inactive_count", &inactive_count, &uint_size, NULL, 0);
if (status < 0){
TraceEvent(SevError, "GetMachineMemInfo").GetLastError();
throw platform_error();
}
status = sysctlbyname("vm.stats.vm.v_wire_count", &wire_count, &uint_size, NULL, 0);
if (status < 0){
TraceEvent(SevError, "GetMachineMemInfo").GetLastError();
throw platform_error();
}
memInfo.total = (int64_t)((free_count + active_count + inactive_count + wire_count) * (u_int64_t)(page_size));
memInfo.available = (int64_t)(free_count * (u_int64_t)(page_size));
memInfo.committed = memInfo.total - memInfo.available;
#elif defined(_WIN32)
MEMORYSTATUSEX mem_status;
@ -456,7 +581,7 @@ Error systemErrorCodeToError() {
void getDiskBytes(std::string const& directory, int64_t& free, int64_t& total) {
INJECT_FAULT( platform_error, "getDiskBytes" );
#if defined(__unixish__)
#ifdef __linux__
#if defined (__linux__) || defined (__FreeBSD__)
struct statvfs buf;
if (statvfs(directory.c_str(), &buf)) {
Error e = systemErrorCodeToError();
@ -755,6 +880,196 @@ dev_t getDeviceId(std::string path) {
#endif
#if defined(__FreeBSD__)
void getNetworkTraffic(const IPAddress ip, uint64_t& bytesSent, uint64_t& bytesReceived,
uint64_t& outSegs, uint64_t& retransSegs) {
INJECT_FAULT( platform_error, "getNetworkTraffic" );
const char* ifa_name = nullptr;
try {
ifa_name = getInterfaceName(ip);
}
catch(Error &e) {
if(e.code() != error_code_platform_error) {
throw;
}
}
if (!ifa_name)
return;
struct ifaddrs *interfaces = NULL;
if (getifaddrs(&interfaces))
{
TraceEvent(SevError, "GetNetworkTrafficError").GetLastError();
throw platform_error();
}
int if_count, i;
int mib[6];
size_t ifmiblen;
struct ifmibdata ifmd;
mib[0] = CTL_NET;
mib[1] = PF_LINK;
mib[2] = NETLINK_GENERIC;
mib[3] = IFMIB_IFDATA;
mib[4] = IFMIB_IFCOUNT;
mib[5] = IFDATA_GENERAL;
ifmiblen = sizeof(ifmd);
for (i = 1; i <= if_count; i++)
{
mib[4] = i;
sysctl(mib, 6, &ifmd, &ifmiblen, (void *)0, 0);
if (!strcmp(ifmd.ifmd_name, ifa_name))
{
bytesSent = ifmd.ifmd_data.ifi_obytes;
bytesReceived = ifmd.ifmd_data.ifi_ibytes;
break;
}
}
freeifaddrs(interfaces);
struct tcpstat tcpstat;
size_t stat_len;
stat_len = sizeof(tcpstat);
int tcpstatus = sysctlbyname("net.inet.tcp.stats", &tcpstat, &stat_len, NULL, 0);
if (tcpstatus < 0) {
TraceEvent(SevError, "GetNetworkTrafficError").GetLastError();
throw platform_error();
}
outSegs = tcpstat.tcps_sndtotal;
retransSegs = tcpstat.tcps_sndrexmitpack;
}
void getMachineLoad(uint64_t& idleTime, uint64_t& totalTime, bool logDetails) {
INJECT_FAULT( platform_error, "getMachineLoad" );
long cur[CPUSTATES], last[CPUSTATES];
size_t cur_sz = sizeof cur;
int cpustate;
long sum;
memset(last, 0, sizeof last);
if (sysctlbyname("kern.cp_time", &cur, &cur_sz, NULL, 0) < 0)
{
TraceEvent(SevError, "GetMachineLoad").GetLastError();
throw platform_error();
}
sum = 0;
for (cpustate = 0; cpustate < CPUSTATES; cpustate++)
{
long tmp = cur[cpustate];
cur[cpustate] -= last[cpustate];
last[cpustate] = tmp;
sum += cur[cpustate];
}
totalTime = (uint64_t)(cur[CP_USER] + cur[CP_NICE] + cur[CP_SYS] + cur[CP_IDLE]);
idleTime = (uint64_t)(cur[CP_IDLE]);
//need to add logging here to TraceEvent
}
void getDiskStatistics(std::string const& directory, uint64_t& currentIOs, uint64_t& busyTicks, uint64_t& reads, uint64_t& writes, uint64_t& writeSectors, uint64_t& readSectors) {
INJECT_FAULT( platform_error, "getDiskStatistics" );
currentIOs = 0;
busyTicks = 0;
reads = 0;
writes = 0;
writeSectors = 0;
readSectors = 0;
struct stat buf;
if (stat(directory.c_str(), &buf)) {
TraceEvent(SevError, "GetDiskStatisticsStatError").detail("Directory", directory).GetLastError();
throw platform_error();
}
static struct statinfo dscur;
double etime;
struct timespec ts;
static int num_devices;
kvm_t *kd = NULL;
etime = ts.tv_nsec * 1e-6;;
int dn;
u_int64_t total_transfers_read, total_transfers_write;
u_int64_t total_blocks_read, total_blocks_write;
u_int64_t queue_len;
long double ms_per_transaction;
dscur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
if (dscur.dinfo == NULL) {
TraceEvent(SevError, "GetDiskStatisticsStatError").GetLastError();
throw platform_error();
}
if (devstat_getdevs(kd, &dscur) == -1) {
TraceEvent(SevError, "GetDiskStatisticsStatError").GetLastError();
throw platform_error();
}
num_devices = dscur.dinfo->numdevs;
for (dn = 0; dn < num_devices; dn++)
{
if (devstat_compute_statistics(&dscur.dinfo->devices[dn], NULL, etime,
DSM_MS_PER_TRANSACTION, &ms_per_transaction,
DSM_TOTAL_TRANSFERS_READ, &total_transfers_read,
DSM_TOTAL_TRANSFERS_WRITE, &total_transfers_write,
DSM_TOTAL_BLOCKS_READ, &total_blocks_read,
DSM_TOTAL_BLOCKS_WRITE, &total_blocks_write,
DSM_QUEUE_LENGTH, &queue_len,
DSM_NONE) != 0) {
TraceEvent(SevError, "GetDiskStatisticsStatError").GetLastError();
throw platform_error();
}
currentIOs = queue_len;
busyTicks = (u_int64_t)ms_per_transaction;
reads = total_transfers_read;
writes = total_transfers_write;
writeSectors = total_blocks_read;
readSectors = total_blocks_write;
}
}
dev_t getDeviceId(std::string path) {
struct stat statInfo;
while (true) {
int returnValue = stat(path.c_str(), &statInfo);
if (!returnValue) break;
if (errno == ENOENT) {
path = parentDirectory(path);
} else {
TraceEvent(SevError, "GetDeviceIdError").detail("Path", path).GetLastError();
throw platform_error();
}
}
return statInfo.st_dev;
}
#endif
#ifdef __APPLE__
void getNetworkTraffic(const IPAddress& ip, uint64_t& bytesSent, uint64_t& bytesReceived, uint64_t& outSegs,
uint64_t& retransSegs) {
@ -1277,7 +1592,7 @@ struct OffsetTimer {
return offset + count * secondsPerCount;
}
};
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
#define DOUBLETIME(ts) (double(ts.tv_sec) + (ts.tv_nsec * 1e-9))
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW 4 // Confirmed safe to do with glibc >= 2.11 and kernel >= 2.6.28. No promises with older glibc. Older kernel definitely breaks it.
@ -1342,7 +1657,7 @@ double timer() {
GetSystemTimeAsFileTime(&fileTime);
static_assert( sizeof(fileTime) == sizeof(uint64_t), "FILETIME size wrong" );
return (*(uint64_t*)&fileTime - FILETIME_C_EPOCH) * 100e-9;
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return double(ts.tv_sec) + (ts.tv_nsec * 1e-9);
@ -1362,7 +1677,7 @@ uint64_t timer_int() {
GetSystemTimeAsFileTime(&fileTime);
static_assert( sizeof(fileTime) == sizeof(uint64_t), "FILETIME size wrong" );
return (*(uint64_t*)&fileTime - FILETIME_C_EPOCH);
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return uint64_t(ts.tv_sec) * 1e9 + ts.tv_nsec;
@ -1412,7 +1727,7 @@ void setMemoryQuota( size_t limit ) {
}
if (!AssignProcessToJobObject( job, GetCurrentProcess() ))
TraceEvent(SevWarn, "FailedToSetMemoryLimit").GetLastError();
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
struct rlimit rlim;
if (getrlimit(RLIMIT_AS, &rlim)) {
TraceEvent(SevError, "GetMemoryLimit").GetLastError();
@ -1514,7 +1829,7 @@ static void *allocateInternal(size_t length, bool largePages) {
flags |= MAP_HUGETLB;
return mmap(NULL, length, PROT_READ|PROT_WRITE, flags, -1, 0);
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__FreeBSD__)
int flags = MAP_PRIVATE|MAP_ANON;
return mmap(NULL, length, PROT_READ|PROT_WRITE, flags, -1, 0);
@ -1588,6 +1903,11 @@ void setAffinity(int proc) {
CPU_ZERO(&set);
CPU_SET(proc, &set);
sched_setaffinity(0, sizeof(cpu_set_t), &set);
#elif defined(__FreeBSD__)
cpuset_t set;
CPU_ZERO(&set);
CPU_SET(proc, &set);
cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,sizeof(set), &set);
#endif
}
@ -1648,7 +1968,7 @@ void renameFile( std::string const& fromPath, std::string const& toPath ) {
//renamedFile();
return;
}
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
if (!rename( fromPath.c_str(), toPath.c_str() )) {
//FIXME: We cannot inject faults after renaming the file, because we could end up with two asyncFileNonDurable open for the same file
//renamedFile();
@ -1814,7 +2134,7 @@ bool createDirectory( std::string const& directory ) {
Error e = systemErrorCodeToError();
TraceEvent(SevError, "CreateDirectory").detail("Directory", directory).GetLastError().error(e);
throw e;
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
size_t sep = 0;
do {
sep = directory.find_first_of('/', sep + 1);
@ -1967,8 +2287,7 @@ std::string abspath( std::string const& path, bool resolveLinks, bool mustExist
if (*x == '/')
*x = CANONICAL_PATH_SEPARATOR;
return nameBuffer;
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
char result[PATH_MAX];
// Must resolve links, so first try realpath on the whole thing
const char *r = realpath( path.c_str(), result );
@ -2031,7 +2350,7 @@ std::string getUserHomeDirectory() {
#ifdef _WIN32
#define FILE_ATTRIBUTE_DATA DWORD
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
#define FILE_ATTRIBUTE_DATA mode_t
#else
#error Port me!
@ -2040,7 +2359,7 @@ std::string getUserHomeDirectory() {
bool acceptFile( FILE_ATTRIBUTE_DATA fileAttributes, std::string name, std::string extension ) {
#ifdef _WIN32
return !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY) && StringRef(name).endsWith(extension);
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
return S_ISREG(fileAttributes) && StringRef(name).endsWith(extension);
#else
#error Port me!
@ -2050,7 +2369,7 @@ bool acceptFile( FILE_ATTRIBUTE_DATA fileAttributes, std::string name, std::stri
bool acceptDirectory( FILE_ATTRIBUTE_DATA fileAttributes, std::string name, std::string extension ) {
#ifdef _WIN32
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
return S_ISDIR(fileAttributes);
#else
#error Port me!
@ -2086,7 +2405,7 @@ std::vector<std::string> findFiles( std::string const& directory, std::string co
}
FindClose(h);
}
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
DIR *dip;
if ((dip = opendir(directory.c_str())) != NULL) {
@ -2150,7 +2469,7 @@ void findFilesRecursively(std::string path, std::vector<std::string> &out) {
void threadSleep( double seconds ) {
#ifdef _WIN32
Sleep( (DWORD)(seconds * 1e3) );
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
struct timespec req, rem;
req.tv_sec = seconds;
@ -2201,7 +2520,7 @@ void setCloseOnExec( int fd ) {
THREAD_HANDLE startThread(void (*func) (void *), void *arg) {
return (void *)_beginthread(func, 0, arg);
}
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
THREAD_HANDLE startThread(void *(*func) (void *), void *arg) {
pthread_t t;
pthread_create(&t, NULL, func, arg);
@ -2214,7 +2533,7 @@ THREAD_HANDLE startThread(void *(*func) (void *), void *arg) {
void waitThread(THREAD_HANDLE thread) {
#ifdef _WIN32
WaitForSingleObject(thread, INFINITE);
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
pthread_join(thread, NULL);
#else
#error Port me!
@ -2256,7 +2575,7 @@ int64_t fileSize(std::string const& filename) {
return 0;
else
return file_status.st_size;
#elif (defined(__linux__) || defined(__APPLE__))
#elif (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
struct stat file_status;
if(stat(filename.c_str(), &file_status) != 0)
return 0;
@ -2395,7 +2714,7 @@ std::string getDefaultConfigPath() {
return _filepath + "\\foundationdb";
#elif defined(__linux__)
return "/etc/foundationdb";
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__FreeBSD__)
return "/usr/local/etc/foundationdb";
#else
#error Port me!
@ -2524,7 +2843,7 @@ int eraseDirectoryRecursive(std::string const& dir) {
__eraseDirectoryRecurseiveCount = 0;
#ifdef _WIN32
system( ("rd /s /q \"" + dir + "\"").c_str() );
#elif defined(__linux__) || defined(__APPLE__)
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
int error =
nftw(dir.c_str(),
[](const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) -> int {
@ -2701,7 +3020,7 @@ void* getImageOffset() { return NULL; }
#endif
bool isLibraryLoaded(const char* lib_path) {
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__FreeBSD__)
#error Port me!
#endif
@ -2717,7 +3036,7 @@ bool isLibraryLoaded(const char* lib_path) {
}
void* loadLibrary(const char* lib_path) {
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__FreeBSD__)
#error Port me!
#endif
@ -2774,6 +3093,20 @@ std::string exePath() {
} else {
throw platform_error();
}
#elif defined(__FreeBSD__)
char binPath[2048];
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
size_t len = sizeof(binPath);
if (sysctl(mib, 4, binPath, &len, NULL, 0) != 0) {
binPath[0] = '\0';
return std::string(binPath);
} else {
throw platform_error();
}
#elif defined(__APPLE__)
uint32_t bufSize = 1024;
std::unique_ptr<char[]> buf(new char[bufSize]);

View File

@ -22,7 +22,7 @@
#define FLOW_PLATFORM_H
#pragma once
#if (defined(__linux__) || defined(__APPLE__))
#if (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
#define __unixish__ 1
#endif
@ -172,6 +172,8 @@ THREAD_HANDLE startThread(void *(func) (void *), void *arg);
#define DYNAMIC_LIB_EXT ".dll"
#elif defined(__linux)
#define DYNAMIC_LIB_EXT ".so"
#elif defined(__FreeBSD__)
#define DYNAMIC_LIB_EXT ".so"
#elif defined(__APPLE__)
#define DYNAMIC_LIB_EXT ".dylib"
#else
@ -422,6 +424,16 @@ inline static uint64_t __rdtsc() {
#endif
#endif
#ifdef __FreeBSD__
#if !(__has_builtin(__rdtsc))
inline static uint64_t __rdtsc() {
uint64_t lo, hi;
asm( "rdtsc" : "=a" (lo), "=d" (hi) );
return( lo | (hi << 32) );
}
#endif
#endif
#ifdef _WIN32
#include <intrin.h>
inline static int32_t interlockedIncrement(volatile int32_t *a) { return _InterlockedIncrement((long*)a); }
@ -531,6 +543,8 @@ inline static void aligned_free(void* ptr) { free(ptr); }
#if (!defined(_ISOC11_SOURCE)) // old libc versions
inline static void* aligned_alloc(size_t alignment, size_t size) { return memalign(alignment, size); }
#endif
#elif defined(__FreeBSD__)
inline static void aligned_free(void* ptr) { free(ptr); }
#elif defined(__APPLE__)
#if !defined(HAS_ALIGNED_ALLOC)
#include <cstdlib>

View File

@ -37,7 +37,7 @@ extern std::string format( const char *form, ... );
Event::Event() {
#ifdef _WIN32
ev = CreateEvent(NULL, FALSE, FALSE, NULL);
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
int result = sem_init(&sem, 0, 0);
if (result)
criticalError(FDB_EXIT_INIT_SEMAPHORE, "UnableToInitializeSemaphore", format("Could not initialize semaphore - %s", strerror(errno)).c_str());
@ -54,7 +54,7 @@ Event::Event() {
Event::~Event() {
#ifdef _WIN32
CloseHandle(ev);
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
sem_destroy(&sem);
#elif defined(__APPLE__)
semaphore_destroy(self, sem);
@ -66,7 +66,7 @@ Event::~Event() {
void Event::set() {
#ifdef _WIN32
SetEvent(ev);
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
sem_post(&sem);
#elif defined(__APPLE__)
semaphore_signal(sem);
@ -78,7 +78,7 @@ void Event::set() {
void Event::block() {
#ifdef _WIN32
WaitForSingleObject(ev, INFINITE);
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
int ret;
do {
ret = sem_wait(&sem);

View File

@ -25,7 +25,7 @@
#include "flow/Error.h"
#include "flow/Trace.h"
#ifdef __linux__
#if defined(__linux__) || defined(__FreeBSD__)
#include <semaphore.h>
#endif
@ -115,7 +115,7 @@ public:
private:
#ifdef _WIN32
void* ev;
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
sem_t sem;
#elif defined(__APPLE__)
mach_port_t self;