Compare commits
6 Commits
T1126-MG-g
...
add-macos-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9aa18dcb77 | ||
|
|
795845ccf7 | ||
|
|
fbc2b4c99b | ||
|
|
32facac135 | ||
|
|
7181e546f5 | ||
|
|
4d9bb27db7 |
@@ -235,6 +235,12 @@ set(MG_ARCH "x86_64" CACHE STRING "Host architecture to build Memgraph on. Suppo
|
||||
|
||||
# setup external dependencies -------------------------------------------------
|
||||
|
||||
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
|
||||
set(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||
set(CMAKE_USE_WIN32_THREADS_INIT 0)
|
||||
set(CMAKE_USE_PTHREADS_INIT 1)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
|
||||
# threading
|
||||
find_package(Threads REQUIRED)
|
||||
# optional readline
|
||||
|
||||
@@ -6,7 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
source "$DIR/../util.sh"
|
||||
|
||||
check_operating_system "debian-11"
|
||||
check_architecture "arm64" "aarch64"
|
||||
check_architecture "arm64"
|
||||
|
||||
TOOLCHAIN_BUILD_DEPS=(
|
||||
coreutils gcc g++ build-essential make # generic build tools
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
source "$DIR/../util.sh"
|
||||
|
||||
check_operating_system "fedora-36"
|
||||
check_architecture "x86_64"
|
||||
|
||||
TOOLCHAIN_BUILD_DEPS=(
|
||||
coreutils-common gcc gcc-c++ make # generic build tools
|
||||
wget # used for archive download
|
||||
gnupg2 # used for archive signature verification
|
||||
tar gzip bzip2 xz unzip # used for archive unpacking
|
||||
zlib-devel # zlib library used for all builds
|
||||
expat-devel xz-devel python3-devel texinfo libbabeltrace-devel # for gdb
|
||||
curl libcurl-devel # for cmake
|
||||
readline-devel # for cmake and llvm
|
||||
libffi-devel libxml2-devel # for llvm
|
||||
libedit-devel pcre-devel automake bison # for swig
|
||||
file
|
||||
openssl-devel
|
||||
gmp-devel
|
||||
gperf
|
||||
diffutils
|
||||
libipt libipt-devel # intel
|
||||
patch
|
||||
)
|
||||
|
||||
TOOLCHAIN_RUN_DEPS=(
|
||||
make # generic build tools
|
||||
tar gzip bzip2 xz # used for archive unpacking
|
||||
zlib # zlib library used for all builds
|
||||
expat xz-libs python3 # for gdb
|
||||
readline # for cmake and llvm
|
||||
libffi libxml2 # for llvm
|
||||
openssl-devel
|
||||
perl # for openssl
|
||||
)
|
||||
|
||||
MEMGRAPH_BUILD_DEPS=(
|
||||
git # source code control
|
||||
make pkgconf-pkg-config # build system
|
||||
wget # for downloading libs
|
||||
libuuid-devel java-11-openjdk # required by antlr
|
||||
readline-devel # for memgraph console
|
||||
python3-devel # for query modules
|
||||
openssl-devel
|
||||
libseccomp-devel
|
||||
python3 python3-pip python3-virtualenv python3-virtualenvwrapper python3-pyyaml nmap-ncat # for tests
|
||||
libcurl-devel # mg-requests
|
||||
rpm-build rpmlint # for RPM package building
|
||||
doxygen graphviz # source documentation generators
|
||||
which nodejs golang zip unzip java-11-openjdk-devel # for driver tests
|
||||
sbcl # for custom Lisp C++ preprocessing
|
||||
autoconf # for jemalloc code generation
|
||||
libtool # for protobuf code generation
|
||||
)
|
||||
|
||||
list() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
check() {
|
||||
local missing=""
|
||||
for pkg in $1; do
|
||||
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||
missing="$pkg $missing"
|
||||
fi
|
||||
done
|
||||
if [ "$missing" != "" ]; then
|
||||
echo "MISSING PACKAGES: $missing"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
install() {
|
||||
cd "$DIR"
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root."
|
||||
exit 1
|
||||
fi
|
||||
# If GitHub Actions runner is installed, append LANG to the environment.
|
||||
# Python related tests don't work without the LANG export.
|
||||
if [ -d "/home/gh/actions-runner" ]; then
|
||||
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
|
||||
else
|
||||
echo "NOTE: export LANG=en_US.utf8"
|
||||
fi
|
||||
dnf update -y
|
||||
for pkg in $1; do
|
||||
dnf install -y "$pkg"
|
||||
done
|
||||
}
|
||||
|
||||
deps=$2"[*]"
|
||||
"$1" "${!deps}"
|
||||
23
environment/os/macos-12.sh
Executable file
23
environment/os/macos-12.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#/bin/bash
|
||||
|
||||
brew install bash
|
||||
brew install cmake
|
||||
brew install clisp sbcl
|
||||
brew install boost gflags fmt jemalloc openssl
|
||||
brew install openssl@1.1
|
||||
|
||||
brew install cyrus-sasl
|
||||
# cyrus-sasl is keg-only, which means it was not symlinked into /opt/homebrew,
|
||||
# because macOS already provides this software and installing another version in
|
||||
# parallel can cause all kinds of trouble.
|
||||
# If you need to have cyrus-sasl first in your PATH, run:
|
||||
# echo 'export PATH="/opt/homebrew/opt/cyrus-sasl/sbin:$PATH"' >> ~/.zshrc
|
||||
# For compilers to find cyrus-sasl you may need to set:
|
||||
# export LDFLAGS="-L/opt/homebrew/opt/cyrus-sasl/lib"
|
||||
# export CPPFLAGS="-I/opt/homebrew/opt/cyrus-sasl/include"
|
||||
|
||||
# TODO(gitbuda): memgraph::utils::SpinLock
|
||||
# TODO(gitbuda): memgraph::utils::AsyncTimer
|
||||
# TODO(gitbuda): memgraph::utils::RWLock
|
||||
# TODO(gitbuda): memgraph::utils::ThreadSetName
|
||||
# TODO(gitbuda): RocksDB 7.7.2 compiles fine
|
||||
1
environment/toolchain/.gitignore
vendored
1
environment/toolchain/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
*.tar.gz
|
||||
@@ -10,14 +10,6 @@ cd "$DIR"
|
||||
source "$DIR/../util.sh"
|
||||
DISTRO="$(operating_system)"
|
||||
|
||||
function log_tool_name () {
|
||||
echo ""
|
||||
echo ""
|
||||
echo "#### $1 ####"
|
||||
echo ""
|
||||
echo ""
|
||||
}
|
||||
|
||||
for_arm=false
|
||||
if [[ "$#" -eq 1 ]]; then
|
||||
if [[ "$1" == "--for-arm" ]]; then
|
||||
@@ -28,11 +20,9 @@ if [[ "$#" -eq 1 ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
TOOLCHAIN_STDCXX="${TOOLCHAIN_STDCXX:-libstdc++}"
|
||||
if [[ "$TOOLCHAIN_STDCXX" != "libstdc++" && "$TOOLCHAIN_STDCXX" != "libc++" ]]; then
|
||||
echo "Only GCC (libstdc++) or LLVM (libc++) C++ standard library implementations are supported."
|
||||
exit 1
|
||||
fi
|
||||
os="$1"
|
||||
|
||||
# toolchain version
|
||||
TOOLCHAIN_VERSION=4
|
||||
|
||||
# package versions used
|
||||
@@ -109,8 +99,6 @@ if [ ! -f llvm-$LLVM_VERSION.src.tar.xz ]; then
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/clang-tools-extra-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/compiler-rt-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libunwind-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxx-$LLVM_VERSION.src.tar.xz
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxxabi-$LLVM_VERSION.src.tar.xz
|
||||
fi
|
||||
if [ ! -f pahole-gdb-master.zip ]; then
|
||||
wget https://github.com/PhilArmstrong/pahole-gdb/archive/master.zip -O pahole-gdb-master.zip
|
||||
@@ -168,8 +156,6 @@ if [ ! -f llvm-$LLVM_VERSION.src.tar.xz.sig ]; then
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/clang-tools-extra-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/compiler-rt-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libunwind-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxx-$LLVM_VERSION.src.tar.xz.sig
|
||||
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/libcxxabi-$LLVM_VERSION.src.tar.xz.sig
|
||||
fi
|
||||
# list of valid llvm gnupg keys: https://releases.llvm.org/download.html
|
||||
$GPG --keyserver $KEYSERVER --recv-keys 0x474E22316ABF4785A88C6E8EA2C794A986419D8A
|
||||
@@ -179,8 +165,6 @@ $GPG --verify lld-$LLVM_VERSION.src.tar.xz.sig lld-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify clang-tools-extra-$LLVM_VERSION.src.tar.xz.sig clang-tools-extra-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify compiler-rt-$LLVM_VERSION.src.tar.xz.sig compiler-rt-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify libunwind-$LLVM_VERSION.src.tar.xz.sig libunwind-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify libcxx-$LLVM_VERSION.src.tar.xz.sig libcxx-$LLVM_VERSION.src.tar.xz
|
||||
$GPG --verify libcxxabi-$LLVM_VERSION.src.tar.xz.sig libcxxabi-$LLVM_VERSION.src.tar.xz
|
||||
|
||||
popd
|
||||
|
||||
@@ -188,7 +172,7 @@ popd
|
||||
mkdir -p build
|
||||
pushd build
|
||||
|
||||
log_tool_name "GCC $GCC_VERSION"
|
||||
# compile gcc
|
||||
if [ ! -f $PREFIX/bin/gcc ]; then
|
||||
if [ -d gcc-$GCC_VERSION ]; then
|
||||
rm -rf gcc-$GCC_VERSION
|
||||
@@ -279,7 +263,7 @@ fi
|
||||
export PATH=$PREFIX/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$PREFIX/lib64
|
||||
|
||||
log_tool_name "binutils $BINUTILS_VERSION"
|
||||
# compile binutils
|
||||
if [ ! -f $PREFIX/bin/ld.gold ]; then
|
||||
if [ -d binutils-$BINUTILS_VERSION ]; then
|
||||
rm -rf binutils-$BINUTILS_VERSION
|
||||
@@ -343,7 +327,7 @@ if [ ! -f $PREFIX/bin/ld.gold ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "GDB $GDB_VERSION"
|
||||
# compile gdb
|
||||
if [ ! -f $PREFIX/bin/gdb ]; then
|
||||
if [ -d gdb-$GDB_VERSION ]; then
|
||||
rm -rf gdb-$GDB_VERSION
|
||||
@@ -414,13 +398,13 @@ if [ ! -f $PREFIX/bin/gdb ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "install pahole"
|
||||
# install pahole
|
||||
if [ ! -d $PREFIX/share/pahole-gdb ]; then
|
||||
unzip ../archives/pahole-gdb-master.zip
|
||||
mv pahole-gdb-master $PREFIX/share/pahole-gdb
|
||||
fi
|
||||
|
||||
log_tool_name "setup system gdbinit"
|
||||
# setup system gdbinit
|
||||
if [ ! -f $PREFIX/etc/gdb/gdbinit ]; then
|
||||
mkdir -p $PREFIX/etc/gdb
|
||||
cat >$PREFIX/etc/gdb/gdbinit <<EOF
|
||||
@@ -446,7 +430,7 @@ end
|
||||
EOF
|
||||
fi
|
||||
|
||||
log_tool_name "cmake $CMAKE_VERSION"
|
||||
# compile cmake
|
||||
if [ ! -f $PREFIX/bin/cmake ]; then
|
||||
if [ -d cmake-$CMAKE_VERSION ]; then
|
||||
rm -rf cmake-$CMAKE_VERSION
|
||||
@@ -472,7 +456,7 @@ if [ ! -f $PREFIX/bin/cmake ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "cppcheck $CPPCHECK_VERSION"
|
||||
# compile cppcheck
|
||||
if [ ! -f $PREFIX/bin/cppcheck ]; then
|
||||
if [ -d cppcheck-$CPPCHECK_VERSION ]; then
|
||||
rm -rf cppcheck-$CPPCHECK_VERSION
|
||||
@@ -496,7 +480,7 @@ if [ ! -f $PREFIX/bin/cppcheck ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "swig $SWIG_VERSION"
|
||||
# compile swig
|
||||
if [ ! -d swig-$SWIG_VERSION/install ]; then
|
||||
if [ -d swig-$SWIG_VERSION ]; then
|
||||
rm -rf swig-$SWIG_VERSION
|
||||
@@ -512,7 +496,7 @@ if [ ! -d swig-$SWIG_VERSION/install ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "LLVM $LLVM_VERSION"
|
||||
# compile llvm
|
||||
if [ ! -f $PREFIX/bin/clang ]; then
|
||||
if [ -d llvm-$LLVM_VERSION ]; then
|
||||
rm -rf llvm-$LLVM_VERSION
|
||||
@@ -529,19 +513,8 @@ if [ ! -f $PREFIX/bin/clang ]; then
|
||||
mv compiler-rt-$LLVM_VERSION.src/ llvm-$LLVM_VERSION/projects/compiler-rt
|
||||
tar -xvf ../archives/libunwind-$LLVM_VERSION.src.tar.xz
|
||||
mv libunwind-$LLVM_VERSION.src/include/mach-o llvm-$LLVM_VERSION/tools/lld/include
|
||||
|
||||
# The following is required because of libc++
|
||||
tar -xvf ../archives/libcxx-$LLVM_VERSION.src.tar.xz
|
||||
mv libcxx-$LLVM_VERSION.src llvm-$LLVM_VERSION/projects/libcxx
|
||||
tar -xvf ../archives/libcxxabi-$LLVM_VERSION.src.tar.xz
|
||||
mv libcxxabi-$LLVM_VERSION.src llvm-$LLVM_VERSION/projects/libcxxabi
|
||||
# NOTE: We moved part of the libunwind in one of the previous step.
|
||||
rm -r libunwind-$LLVM_VERSION.src
|
||||
tar -xvf ../archives/libunwind-$LLVM_VERSION.src.tar.xz
|
||||
mv libunwind-$LLVM_VERSION.src llvm-$LLVM_VERSION/projects/libunwind
|
||||
|
||||
pushd llvm-$LLVM_VERSION
|
||||
mkdir -p build && pushd build
|
||||
mkdir build && pushd build
|
||||
# activate swig
|
||||
export PATH=$DIR/build/swig-$SWIG_VERSION/install/bin:$PATH
|
||||
# influenced by: https://buildd.debian.org/status/fetch.php?pkg=llvm-toolchain-7&arch=amd64&ver=1%3A7.0.1%7E%2Brc2-1%7Eexp1&stamp=1541506173&raw=0
|
||||
@@ -847,11 +820,7 @@ source $PREFIX/activate
|
||||
export CC=$PREFIX/bin/clang
|
||||
export CXX=$PREFIX/bin/clang++
|
||||
export CFLAGS="$CFLAGS -fPIC"
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
else
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC -stdlib=libc++"
|
||||
fi
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
COMMON_CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=$PREFIX
|
||||
-DCMAKE_PREFIX_PATH=$PREFIX
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
@@ -865,7 +834,7 @@ COMMON_CMAKE_FLAGS="-DCMAKE_INSTALL_PREFIX=$PREFIX
|
||||
COMMON_CONFIGURE_FLAGS="--enable-shared=no --prefix=$PREFIX"
|
||||
COMMON_MAKE_INSTALL_FLAGS="-j$CPUS BUILD_SHARED=no PREFIX=$PREFIX install"
|
||||
|
||||
log_tool_name "bzip2 $BZIP2_VERSION"
|
||||
# install bzip2
|
||||
if [ ! -f $PREFIX/include/bzlib.h ]; then
|
||||
if [ -d bzip2-$BZIP2_VERSION ]; then
|
||||
rm -rf bzip2-$BZIP2_VERSION
|
||||
@@ -876,7 +845,7 @@ if [ ! -f $PREFIX/include/bzlib.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "fmt $FMT_VERSION"
|
||||
# install fmt
|
||||
if [ ! -d $PREFIX/include/fmt ]; then
|
||||
if [ -d fmt-$FMT_VERSION ]; then
|
||||
rm -rf fmt-$FMT_VERSION
|
||||
@@ -889,7 +858,7 @@ if [ ! -d $PREFIX/include/fmt ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "lz4 $LZ4_VERSION"
|
||||
# install lz4
|
||||
if [ ! -f $PREFIX/include/lz4.h ]; then
|
||||
if [ -d lz4-$LZ4_VERSION ]; then
|
||||
rm -rf lz4-$LZ4_VERSION
|
||||
@@ -900,7 +869,7 @@ if [ ! -f $PREFIX/include/lz4.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "xz $XZ_VERSION"
|
||||
# install xz
|
||||
if [ ! -f $PREFIX/include/lzma.h ]; then
|
||||
if [ -d xz-$XZ_VERSION ]; then
|
||||
rm -rf xz-$XZ_VERSION
|
||||
@@ -912,7 +881,7 @@ if [ ! -f $PREFIX/include/lzma.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "zlib $ZLIB_VERSION"
|
||||
# install zlib
|
||||
if [ ! -f $PREFIX/include/zlib.h ]; then
|
||||
if [ -d zlib-$ZLIB_VERSION ]; then
|
||||
rm -rf zlib-$ZLIB_VERSION
|
||||
@@ -926,7 +895,7 @@ if [ ! -f $PREFIX/include/zlib.h ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "zstd $ZSTD_VERSION"
|
||||
# install zstd
|
||||
if [ ! -f $PREFIX/include/zstd.h ]; then
|
||||
if [ -d zstd-$ZSTD_VERSION ]; then
|
||||
rm -rf zstd-$ZSTD_VERSION
|
||||
@@ -941,8 +910,7 @@ if [ ! -f $PREFIX/include/zstd.h ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# TODO(gitbuda): Freeze jmalloc version.
|
||||
log_tool_name "jmalloc"
|
||||
#install jemalloc
|
||||
if [ ! -d $PREFIX/include/jemalloc ]; then
|
||||
if [ -d jemalloc ]; then
|
||||
rm -rf jemalloc
|
||||
@@ -959,7 +927,7 @@ if [ ! -d $PREFIX/include/jemalloc ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "BOOST $BOOST_VERSION"
|
||||
# install boost
|
||||
if [ ! -d $PREFIX/include/boost ]; then
|
||||
if [ -d boost_$BOOST_VERSION_UNDERSCORES ]; then
|
||||
rm -rf boost_$BOOST_VERSION_UNDERSCORES
|
||||
@@ -967,24 +935,15 @@ if [ ! -d $PREFIX/include/boost ]; then
|
||||
tar -xzf ../archives/boost_$BOOST_VERSION_UNDERSCORES.tar.gz
|
||||
pushd boost_$BOOST_VERSION_UNDERSCORES
|
||||
./bootstrap.sh --prefix=$PREFIX --with-toolset=clang --with-python=python3 --without-icu
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
./b2 toolset=clang -j$CPUS install variant=release link=static cxxstd=20 --disable-icu \
|
||||
-sZLIB_SOURCE="$PREFIX" -sZLIB_INCLUDE="$PREFIX/include" -sZLIB_LIBPATH="$PREFIX/lib" \
|
||||
-sBZIP2_SOURCE="$PREFIX" -sBZIP2_INCLUDE="$PREFIX/include" -sBZIP2_LIBPATH="$PREFIX/lib" \
|
||||
-sLZMA_SOURCE="$PREFIX" -sLZMA_INCLUDE="$PREFIX/include" -sLZMA_LIBPATH="$PREFIX/lib" \
|
||||
-sZSTD_SOURCE="$PREFIX" -sZSTD_INCLUDE="$PREFIX/include" -sZSTD_LIBPATH="$PREFIX/lib"
|
||||
else
|
||||
./b2 toolset=clang -j$CPUS install variant=release link=static cxxstd=20 --disable-icu \
|
||||
cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" \
|
||||
-sZLIB_SOURCE="$PREFIX" -sZLIB_INCLUDE="$PREFIX/include" -sZLIB_LIBPATH="$PREFIX/lib" \
|
||||
-sBZIP2_SOURCE="$PREFIX" -sBZIP2_INCLUDE="$PREFIX/include" -sBZIP2_LIBPATH="$PREFIX/lib" \
|
||||
-sLZMA_SOURCE="$PREFIX" -sLZMA_INCLUDE="$PREFIX/include" -sLZMA_LIBPATH="$PREFIX/lib" \
|
||||
-sZSTD_SOURCE="$PREFIX" -sZSTD_INCLUDE="$PREFIX/include" -sZSTD_LIBPATH="$PREFIX/lib"
|
||||
fi
|
||||
./b2 toolset=clang -j$CPUS install variant=release link=static cxxstd=20 --disable-icu \
|
||||
-sZLIB_SOURCE="$PREFIX" -sZLIB_INCLUDE="$PREFIX/include" -sZLIB_LIBPATH="$PREFIX/lib" \
|
||||
-sBZIP2_SOURCE="$PREFIX" -sBZIP2_INCLUDE="$PREFIX/include" -sBZIP2_LIBPATH="$PREFIX/lib" \
|
||||
-sLZMA_SOURCE="$PREFIX" -sLZMA_INCLUDE="$PREFIX/include" -sLZMA_LIBPATH="$PREFIX/lib" \
|
||||
-sZSTD_SOURCE="$PREFIX" -sZSTD_INCLUDE="$PREFIX/include" -sZSTD_LIBPATH="$PREFIX/lib"
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "double-conversion $DOUBLE_CONVERSION_VERSION"
|
||||
# install double-conversion
|
||||
if [ ! -d $PREFIX/include/double-conversion ]; then
|
||||
if [ -d double-conversion-$DOUBLE_CONVERSION_VERSION ]; then
|
||||
rm -rf double-conversion-$DOUBLE_CONVERSION_VERSION
|
||||
@@ -999,8 +958,7 @@ if [ ! -d $PREFIX/include/double-conversion ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
# TODO(gitbuda): Freeze gflags version.
|
||||
log_tool_name "gflags"
|
||||
# install gflags
|
||||
if [ ! -d $PREFIX/include/gflags ]; then
|
||||
if [ -d gflags ]; then
|
||||
rm -rf gflags
|
||||
@@ -1019,7 +977,7 @@ if [ ! -d $PREFIX/include/gflags ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "libunwind $LIBUNWIND_VERSION"
|
||||
# install libunwind
|
||||
if [ ! -f $PREFIX/include/libunwind.h ]; then
|
||||
if [ -d libunwind-$LIBUNWIND_VERSION ]; then
|
||||
rm -rf libunwind-$LIBUNWIND_VERSION
|
||||
@@ -1032,7 +990,7 @@ if [ ! -f $PREFIX/include/libunwind.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "glog $GLOG_VERSION"
|
||||
# install glog
|
||||
if [ ! -d $PREFIX/include/glog ]; then
|
||||
if [ -d glog-$GLOG_VERSION ]; then
|
||||
rm -rf glog-$GLOG_VERSION
|
||||
@@ -1046,7 +1004,7 @@ if [ ! -d $PREFIX/include/glog ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "libevent $LIBEVENT_VERSION"
|
||||
# install libevent
|
||||
if [ ! -d $PREFIX/include/event2 ]; then
|
||||
if [ -d libevent-$LIBEVENT_VERSION ]; then
|
||||
rm -rf libevent-$LIBEVENT_VERSION
|
||||
@@ -1065,7 +1023,7 @@ if [ ! -d $PREFIX/include/event2 ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "snappy $SNAPPY_VERSION"
|
||||
# install snappy
|
||||
if [ ! -f $PREFIX/include/snappy.h ]; then
|
||||
if [ -d snappy-$SNAPPY_VERSION ]; then
|
||||
rm -rf snappy-$SNAPPY_VERSION
|
||||
@@ -1083,7 +1041,7 @@ if [ ! -f $PREFIX/include/snappy.h ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "libsodium $LIBSODIUM_VERSION"
|
||||
# install libsodium
|
||||
if [ ! -f $PREFIX/include/sodium.h ]; then
|
||||
if [ -d libsodium-$LIBSODIUM_VERSION ]; then
|
||||
rm -rf libsodium-$LIBSODIUM_VERSION
|
||||
@@ -1095,7 +1053,7 @@ if [ ! -f $PREFIX/include/sodium.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "libaio $LIBAIO_VERSION"
|
||||
# install libaio
|
||||
if [ ! -f $PREFIX/include/libaio.h ]; then
|
||||
if [ -d libaio-$LIBAIO_VERSION ]; then
|
||||
rm -rf libaio-$LIBAIO_VERSION
|
||||
@@ -1106,7 +1064,7 @@ if [ ! -f $PREFIX/include/libaio.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "folly $FBLIBS_VERSION"
|
||||
# install folly
|
||||
if [ ! -d $PREFIX/include/folly ]; then
|
||||
if [ -d folly-$FBLIBS_VERSION ]; then
|
||||
rm -rf folly-$FBLIBS_VERSION
|
||||
@@ -1127,7 +1085,7 @@ if [ ! -d $PREFIX/include/folly ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "fizz $FBLIBS_VERSION"
|
||||
# install fizz
|
||||
if [ ! -d $PREFIX/include/fizz ]; then
|
||||
if [ -d fizz-$FBLIBS_VERSION ]; then
|
||||
rm -rf fizz-$FBLIBS_VERSION
|
||||
@@ -1146,7 +1104,7 @@ if [ ! -d $PREFIX/include/fizz ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "wangle FBLIBS_VERSION"
|
||||
# install wangle
|
||||
if [ ! -d $PREFIX/include/wangle ]; then
|
||||
if [ -d wangle-$FBLIBS_VERSION ]; then
|
||||
rm -rf wangle-$FBLIBS_VERSION
|
||||
@@ -1165,7 +1123,7 @@ if [ ! -d $PREFIX/include/wangle ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "proxygen $FBLIBS_VERSION"
|
||||
# install proxygen
|
||||
if [ ! -d $PREFIX/include/proxygen ]; then
|
||||
if [ -d proxygen-$FBLIBS_VERSION ]; then
|
||||
rm -rf proxygen-$FBLIBS_VERSION
|
||||
@@ -1186,7 +1144,7 @@ if [ ! -d $PREFIX/include/proxygen ]; then
|
||||
popd && popd
|
||||
fi
|
||||
|
||||
log_tool_name "flex $FBLIBS_VERSION"
|
||||
# install flex
|
||||
if [ ! -f $PREFIX/include/FlexLexer.h ]; then
|
||||
if [ -d flex-$FLEX_VERSION ]; then
|
||||
rm -rf flex-$FLEX_VERSION
|
||||
@@ -1198,7 +1156,7 @@ if [ ! -f $PREFIX/include/FlexLexer.h ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
log_tool_name "fbthrift $FBLIBS_VERSION"
|
||||
# install fbthrift
|
||||
if [ ! -d $PREFIX/include/thrift ]; then
|
||||
if [ -d fbthrift-$FBLIBS_VERSION ]; then
|
||||
rm -rf fbthrift-$FBLIBS_VERSION
|
||||
@@ -1208,15 +1166,10 @@ if [ ! -d $PREFIX/include/thrift ]; then
|
||||
# build is used by facebook builder
|
||||
mkdir _build
|
||||
pushd _build
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
CMAKE_CXX_FLAGS="-fsized-deallocation"
|
||||
else
|
||||
CMAKE_CXX_FLAGS="-fsized-deallocation -stdlib=libc++"
|
||||
fi
|
||||
cmake .. $COMMON_CMAKE_FLAGS \
|
||||
-Denable_tests=OFF \
|
||||
-DGFLAGS_NOTHREADS=OFF \
|
||||
-DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS"
|
||||
-DCMAKE_CXX_FLAGS=-fsized-deallocation
|
||||
make -j$CPUS install
|
||||
popd
|
||||
fi
|
||||
@@ -1239,12 +1192,7 @@ if [ ! -f $NAME-binaries-$DISTRO.tar.gz ]; then
|
||||
DISTRO_FULL_NAME="$DISTRO_FULL_NAME-amd64"
|
||||
fi
|
||||
fi
|
||||
if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then
|
||||
# Pass because infra scripts assume there is not C++ standard lib in the name.
|
||||
echo "NOTE: Not adding anything to the archive name that GCC C++ standard lib is used."
|
||||
else
|
||||
DISTRO_FULL_NAME="$DISTRO_FULL_NAME-libc++"
|
||||
fi
|
||||
|
||||
tar --owner=root --group=root -cpvzf $NAME-binaries-$DISTRO_FULL_NAME.tar.gz -C /opt $NAME
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
function operating_system() {
|
||||
operating_system() {
|
||||
grep -E '^(VERSION_)?ID=' /etc/os-release | \
|
||||
sort | cut -d '=' -f 2- | sed 's/"//g' | paste -s -d '-'
|
||||
}
|
||||
|
||||
function check_operating_system() {
|
||||
check_operating_system() {
|
||||
if [ "$(operating_system)" != "$1" ]; then
|
||||
echo "Not the right operating system!"
|
||||
exit 1
|
||||
@@ -14,22 +14,20 @@ function check_operating_system() {
|
||||
fi
|
||||
}
|
||||
|
||||
function architecture() {
|
||||
architecture() {
|
||||
uname -m
|
||||
}
|
||||
|
||||
check_architecture() {
|
||||
for arch in "$@"; do
|
||||
if [ "$(architecture)" = "$arch" ]; then
|
||||
echo "The right architecture!"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
echo "Not the right architecture!"
|
||||
exit 1
|
||||
if [ "$(architecture)" != "$1" ]; then
|
||||
echo "Not the right architecture!"
|
||||
exit 1
|
||||
else
|
||||
echo "The right architecture."
|
||||
fi
|
||||
}
|
||||
|
||||
function check_all_yum() {
|
||||
check_all_yum() {
|
||||
local missing=""
|
||||
for pkg in $1; do
|
||||
if ! yum list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||
@@ -42,7 +40,7 @@ function check_all_yum() {
|
||||
fi
|
||||
}
|
||||
|
||||
function check_all_dpkg() {
|
||||
check_all_dpkg() {
|
||||
local missing=""
|
||||
for pkg in $1; do
|
||||
if ! dpkg -s "$pkg" >/dev/null 2>/dev/null; then
|
||||
@@ -55,7 +53,7 @@ function check_all_dpkg() {
|
||||
fi
|
||||
}
|
||||
|
||||
function check_all_dnf() {
|
||||
check_all_dnf() {
|
||||
local missing=""
|
||||
for pkg in $1; do
|
||||
if ! dnf list installed "$pkg" >/dev/null 2>/dev/null; then
|
||||
@@ -67,8 +65,7 @@ function check_all_dnf() {
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function install_all_apt() {
|
||||
install_all_apt() {
|
||||
for pkg in $1; do
|
||||
apt install -y "$pkg"
|
||||
done
|
||||
|
||||
94
init
94
init
@@ -1,13 +1,10 @@
|
||||
#!/bin/bash -e
|
||||
#!/opt/homebrew/Cellar/bash/5.1.16/bin/bash -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd "$DIR"
|
||||
|
||||
source "$DIR/environment/util.sh"
|
||||
|
||||
DISTRO=$(operating_system)
|
||||
ARCHITECTURE=$(architecture)
|
||||
|
||||
function print_help () {
|
||||
echo "Usage: $0 [OPTION]"
|
||||
echo -e "Check for missing packages and setup the project.\n"
|
||||
@@ -67,14 +64,16 @@ else
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "${ARCHITECTURE}" = "arm64" ] || [ "${ARCHITECTURE}" = "aarch64" ]; then
|
||||
OS_SCRIPT=$DIR/environment/os/$DISTRO-arm.sh
|
||||
else
|
||||
OS_SCRIPT=$DIR/environment/os/$DISTRO.sh
|
||||
fi
|
||||
echo "ALL BUILD PACKAGES: $($OS_SCRIPT list MEMGRAPH_BUILD_DEPS)"
|
||||
$OS_SCRIPT check MEMGRAPH_BUILD_DEPS
|
||||
echo "All packages are in-place..."
|
||||
# DISTRO=$(operating_system)
|
||||
# ARCHITECTURE=$(architecture)
|
||||
# if [ "${ARCHITECTURE}" = "arm64" ] || [ "${ARCHITECTURE}" = "aarch64" ]; then
|
||||
# OS_SCRIPT=$DIR/environment/os/$DISTRO-arm.sh
|
||||
# else
|
||||
# OS_SCRIPT=$DIR/environment/os/$DISTRO.sh
|
||||
# fi
|
||||
# echo "ALL BUILD PACKAGES: $($OS_SCRIPT list MEMGRAPH_BUILD_DEPS)"
|
||||
# $OS_SCRIPT check MEMGRAPH_BUILD_DEPS
|
||||
# echo "All packages are in-place..."
|
||||
|
||||
# create a default build directory
|
||||
mkdir -p ./build
|
||||
@@ -94,7 +93,8 @@ if [[ ! -f "${quicklisp_install_dir}/setup.lisp" ]]; then
|
||||
" | sbcl --script || exit 1
|
||||
rm -rf quicklisp.lisp || exit 1
|
||||
fi
|
||||
ln -Tfs "$DIR/src/lisp" "${quicklisp_install_dir}/local-projects/lcp"
|
||||
# TODO(gitbuda): -T doesn't work on Mac
|
||||
ln -fs "$DIR/src/lisp" "${quicklisp_install_dir}/local-projects/lcp"
|
||||
# Install LCP dependencies
|
||||
# TODO: We should at some point cache or have a mirror of packages we use.
|
||||
# TODO: move the installation of LCP's dependencies into ./setup.sh
|
||||
@@ -112,40 +112,34 @@ if [[ "$setup_libs" == "true" ]]; then
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# Fix for centos 7 during release
|
||||
if [ "${ARCHITECTURE}" = "centos-7" ]; then
|
||||
python3 -m pip uninstall virtualenv
|
||||
python3 -m pip install virtualenv
|
||||
fi
|
||||
|
||||
# setup gql_behave dependencies
|
||||
setup_virtualenv tests/gql_behave
|
||||
|
||||
# setup stress dependencies
|
||||
setup_virtualenv tests/stress
|
||||
|
||||
# setup integration/ldap dependencies
|
||||
setup_virtualenv tests/integration/ldap
|
||||
|
||||
# Setup tests dependencies.
|
||||
# cd tests
|
||||
# ./setup.sh
|
||||
# cd ..
|
||||
# TODO(gitbuda): Remove setup_virtualenv, replace it with tests/ve3. Take care
|
||||
# of the build order because tests/setup.py builds pymgclient which depends on
|
||||
# mgclient which is build after this script by calling make.
|
||||
|
||||
echo "Done installing dependencies for Memgraph"
|
||||
|
||||
echo "Linking git hooks"
|
||||
for hook in $(find $DIR/.githooks -type f -printf "%f\n"); do
|
||||
ln -s -f "$DIR/.githooks/$hook" "$DIR/.git/hooks/$hook"
|
||||
echo "Added $hook hook"
|
||||
done;
|
||||
|
||||
# Install precommit hook
|
||||
python3 -m pip install pre-commit
|
||||
python3 -m pre_commit install
|
||||
|
||||
# Link `include/mgp.py` with `release/mgp/mgp.py`
|
||||
ln -v -f include/mgp.py release/mgp/mgp.py
|
||||
# # setup gql_behave dependencies
|
||||
# setup_virtualenv tests/gql_behave
|
||||
#
|
||||
# # setup stress dependencies
|
||||
# setup_virtualenv tests/stress
|
||||
#
|
||||
# # setup integration/ldap dependencies
|
||||
# setup_virtualenv tests/integration/ldap
|
||||
#
|
||||
# # Setup tests dependencies.
|
||||
# # cd tests
|
||||
# # ./setup.sh
|
||||
# # cd ..
|
||||
# # TODO(gitbuda): Remove setup_virtualenv, replace it with tests/ve3. Take care
|
||||
# # of the build order because tests/setup.py builds pymgclient which depends on
|
||||
# # mgclient which is build after this script by calling make.
|
||||
#
|
||||
# echo "Done installing dependencies for Memgraph"
|
||||
#
|
||||
# echo "Linking git hooks"
|
||||
# for hook in $(find $DIR/.githooks -type f -printf "%f\n"); do
|
||||
# ln -s -f "$DIR/.githooks/$hook" "$DIR/.git/hooks/$hook"
|
||||
# echo "Added $hook hook"
|
||||
# done;
|
||||
#
|
||||
# # Install precommit hook
|
||||
# python3 -m pip install pre-commit
|
||||
# python3 -m pre_commit install
|
||||
#
|
||||
# # Link `include/mgp.py` with `release/mgp/mgp.py`
|
||||
# ln -v -f include/mgp.py release/mgp/mgp.py
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash -e
|
||||
#!/opt/homebrew/Cellar/bash/5.1.16/bin/bash -e
|
||||
|
||||
# Download external dependencies.
|
||||
# Don't forget to add/update the license in release/third-party-licenses of added/updated libs!
|
||||
@@ -201,7 +201,7 @@ popd
|
||||
# mgclient
|
||||
mgclient_tag="v1.4.0" # (2022-06-14)
|
||||
repo_clone_try_double "${primary_urls[mgclient]}" "${secondary_urls[mgclient]}" "mgclient" "$mgclient_tag"
|
||||
sed -i 's/\${CMAKE_INSTALL_LIBDIR}/lib/' mgclient/src/CMakeLists.txt
|
||||
sed -e 's/\${CMAKE_INSTALL_LIBDIR}/lib/' mgclient/src/CMakeLists.txt
|
||||
|
||||
# pymgclient
|
||||
pymgclient_tag="4f85c179e56302d46a1e3e2cf43509db65f062b3" # (2021-01-15)
|
||||
@@ -233,6 +233,7 @@ git apply ../pulsar.patch
|
||||
popd
|
||||
|
||||
#librdtsc
|
||||
# TODO(gitbuda): __always_inline doesn't work on Apple Clang 14
|
||||
librdtsc_tag="v0.3"
|
||||
repo_clone_try_double "${primary_urls[librdtsc]}" "${secondary_urls[librdtsc]}" "librdtsc" "$librdtsc_tag" true
|
||||
pushd librdtsc
|
||||
|
||||
@@ -36,7 +36,7 @@ ADDITIONAL USE GRANT: You may use the Licensed Work in accordance with the
|
||||
3. using the Licensed Work to create a work or solution
|
||||
which competes (or might reasonably be expected to
|
||||
compete) with the Licensed Work.
|
||||
CHANGE DATE: 2026-07-10
|
||||
CHANGE DATE: 2026-27-04
|
||||
CHANGE LICENSE: Apache License, Version 2.0
|
||||
|
||||
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.
|
||||
|
||||
@@ -72,8 +72,6 @@ make_package () {
|
||||
docker exec "$build_container" bash -c "/memgraph/environment/os/$os.sh install MEMGRAPH_BUILD_DEPS"
|
||||
|
||||
echo "Building targeted package..."
|
||||
# Fix issue with git marking directory as not safe
|
||||
docker exec "$build_container" bash -c "cd /memgraph && git config --global --add safe.directory '*'"
|
||||
docker exec "$build_container" bash -c "cd /memgraph && $ACTIVATE_TOOLCHAIN && ./init"
|
||||
docker exec "$build_container" bash -c "cd $container_build_dir && rm -rf ./*"
|
||||
if [[ "$os" == "debian-11-arm" ]]; then
|
||||
|
||||
@@ -4,7 +4,8 @@ set(auth_src_files
|
||||
models.cpp
|
||||
module.cpp)
|
||||
|
||||
find_package(Seccomp REQUIRED)
|
||||
# TODO(gitbuda): Deal with the MacOS specific setup around Seccomp.
|
||||
# find_package(Seccomp REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(gflags REQUIRED)
|
||||
|
||||
|
||||
@@ -646,7 +646,7 @@ void AuthQueryHandler::EditPermissions(
|
||||
#ifdef MG_ENTERPRISE
|
||||
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
|
||||
for (const auto &label_privilege : label_privileges) {
|
||||
edit_fine_grained_permissions_fun(role->fine_grained_access_handler().label_permissions(), label_privilege);
|
||||
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(), label_privilege);
|
||||
}
|
||||
for (const auto &edge_type_privilege : edge_type_privileges) {
|
||||
edit_fine_grained_permissions_fun(role->fine_grained_access_handler().edge_type_permissions(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
// Copyright 2023 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
@@ -718,6 +718,7 @@ int main(int argc, char **argv) {
|
||||
auto gil = memgraph::py::EnsureGIL();
|
||||
// NOLINTNEXTLINE(hicpp-signed-bitwise)
|
||||
auto *flag = PyLong_FromLong(RTLD_NOW | RTLD_DEEPBIND);
|
||||
// TODO(gitbuda): This is Unix specific -> https://docs.python.org/3/library/sys.html#sys.setdlopenflags
|
||||
auto *setdl = PySys_GetObject("setdlopenflags");
|
||||
MG_ASSERT(setdl);
|
||||
auto *arg = PyTuple_New(1);
|
||||
|
||||
@@ -314,12 +314,6 @@ class DbAccessor final {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<EdgeAccessor> FindEdge(storage::Gid edge_id, storage::Gid vertex_id) {
|
||||
auto maybe_edge = accessor_->FindEdge(edge_id, vertex_id);
|
||||
if (maybe_edge) return EdgeAccessor(*maybe_edge);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void FinalizeTransaction() { accessor_->FinalizeTransaction(); }
|
||||
|
||||
VerticesIterable Vertices(storage::View view) { return VerticesIterable(accessor_->Vertices(view)); }
|
||||
@@ -489,8 +483,6 @@ class SubgraphDbAccessor final {
|
||||
|
||||
std::optional<VertexAccessor> FindVertex(storage::Gid gid, storage::View view);
|
||||
|
||||
std::optional<EdgeAccessor> FindEdge(storage::Gid gid);
|
||||
|
||||
Graph *getGraph();
|
||||
};
|
||||
|
||||
|
||||
@@ -650,19 +650,6 @@ TypedValue Labels(const TypedValue *args, int64_t nargs, const FunctionContext &
|
||||
return TypedValue(std::move(labels));
|
||||
}
|
||||
|
||||
TypedValue GetEdgeById(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
|
||||
FType<Or<Null, Integer>, Or<Null, Integer>>("edge_id", args, nargs);
|
||||
auto *dba = ctx.db_accessor;
|
||||
|
||||
if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory);
|
||||
auto edge_id = args[0].ValueInt();
|
||||
auto vertex_id = args[1].ValueInt();
|
||||
auto maybe_edge = dba->FindEdge(storage::Gid::FromUint(edge_id), storage::Gid::FromUint(vertex_id));
|
||||
if (!maybe_edge) throw query::QueryRuntimeException("Edge doesn't exist.");
|
||||
|
||||
return TypedValue(*maybe_edge, ctx.memory);
|
||||
}
|
||||
|
||||
TypedValue Nodes(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
|
||||
FType<Or<Null, Path>>("nodes", args, nargs);
|
||||
if (args[0].IsNull()) return TypedValue(ctx.memory);
|
||||
@@ -1284,8 +1271,6 @@ std::function<TypedValue(const TypedValue *, int64_t, const FunctionContext &ctx
|
||||
if (function_name == "RELATIONSHIPS") return Relationships;
|
||||
if (function_name == "TAIL") return Tail;
|
||||
if (function_name == "UNIFORMSAMPLE") return UniformSample;
|
||||
if (function_name == "GET_EDGE_BY_ID") return GetEdgeById;
|
||||
// if (function_name == "GET_EDGES_BY_ID") return GetEdgesById;
|
||||
|
||||
// Mathematical functions - numeric
|
||||
if (function_name == "ABS") return Abs;
|
||||
|
||||
@@ -1846,8 +1846,7 @@ mgp_error mgp_vertex_label_at(mgp_vertex *v, size_t i, mgp_label *result) {
|
||||
"Expected LabelToName to return a pointer or reference, so we "
|
||||
"don't have to take a copy and manage memory.");
|
||||
|
||||
const auto &name = std::visit(
|
||||
[label](const auto *impl) -> const std::string & { return impl->LabelToName(label); }, v->graph->impl);
|
||||
const auto &name = std::visit([label](const auto *impl) { return impl->LabelToName(label); }, v->graph->impl);
|
||||
return name.c_str();
|
||||
},
|
||||
&result->name);
|
||||
@@ -2124,7 +2123,10 @@ mgp_error mgp_edges_iterator_next(mgp_edges_iterator *it, mgp_edge **result) {
|
||||
return &*it->current_e;
|
||||
};
|
||||
if (it->in_it) {
|
||||
return next(true);
|
||||
auto *result = next(true);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return next(false);
|
||||
},
|
||||
@@ -2155,9 +2157,8 @@ mgp_error mgp_edge_equal(mgp_edge *e1, mgp_edge *e2, int *result) {
|
||||
mgp_error mgp_edge_get_type(mgp_edge *e, mgp_edge_type *result) {
|
||||
return WrapExceptions(
|
||||
[e] {
|
||||
const auto &name = std::visit(
|
||||
[e](const auto *impl) -> const std::string & { return impl->EdgeTypeToName(e->impl.EdgeType()); },
|
||||
e->from.graph->impl);
|
||||
const auto &name =
|
||||
std::visit([e](const auto *impl) { return impl->EdgeTypeToName(e->impl.EdgeType()); }, e->from.graph->impl);
|
||||
return name.c_str();
|
||||
},
|
||||
&result->name);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "storage/v2/temporal.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/fnv.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
|
||||
namespace memgraph::query {
|
||||
|
||||
@@ -216,8 +215,7 @@ TypedValue::TypedValue(const TypedValue &other, utils::MemoryResource *memory) :
|
||||
new (&duration_v) utils::Duration(other.duration_v);
|
||||
return;
|
||||
case Type::Graph:
|
||||
auto *graph_ptr = utils::Allocator<Graph>(memory_).new_object<Graph>(*other.graph_v);
|
||||
new (&graph_v) std::unique_ptr<Graph>(graph_ptr);
|
||||
new (&graph_v) Graph(other.graph_v, memory_);
|
||||
return;
|
||||
}
|
||||
LOG_FATAL("Unsupported TypedValue::Type");
|
||||
@@ -269,12 +267,7 @@ TypedValue::TypedValue(TypedValue &&other, utils::MemoryResource *memory) : memo
|
||||
new (&duration_v) utils::Duration(other.duration_v);
|
||||
break;
|
||||
case Type::Graph:
|
||||
if (other.GetMemoryResource() == memory_) {
|
||||
new (&graph_v) std::unique_ptr<Graph>(std::move(other.graph_v));
|
||||
} else {
|
||||
auto *graph_ptr = utils::Allocator<Graph>(memory_).new_object<Graph>(std::move(*other.graph_v));
|
||||
new (&graph_v) std::unique_ptr<Graph>(graph_ptr);
|
||||
}
|
||||
new (&graph_v) Graph(std::move(other.graph_v), memory_);
|
||||
}
|
||||
other.DestroyValue();
|
||||
}
|
||||
@@ -343,22 +336,7 @@ DEFINE_VALUE_AND_TYPE_GETTERS(utils::Date, Date, date_v)
|
||||
DEFINE_VALUE_AND_TYPE_GETTERS(utils::LocalTime, LocalTime, local_time_v)
|
||||
DEFINE_VALUE_AND_TYPE_GETTERS(utils::LocalDateTime, LocalDateTime, local_date_time_v)
|
||||
DEFINE_VALUE_AND_TYPE_GETTERS(utils::Duration, Duration, duration_v)
|
||||
|
||||
Graph &TypedValue::ValueGraph() {
|
||||
if (type_ != Type::Graph) {
|
||||
throw TypedValueException("TypedValue is of type '{}', not '{}'", type_, Type::Graph);
|
||||
}
|
||||
return *graph_v;
|
||||
}
|
||||
|
||||
const Graph &TypedValue::ValueGraph() const {
|
||||
if (type_ != Type::Graph) {
|
||||
throw TypedValueException("TypedValue is of type '{}', not '{}'", type_, Type::Graph);
|
||||
}
|
||||
return *graph_v;
|
||||
}
|
||||
|
||||
bool TypedValue::IsGraph() const { return type_ == Type::Graph; }
|
||||
DEFINE_VALUE_AND_TYPE_GETTERS(Graph, Graph, graph_v)
|
||||
|
||||
#undef DEFINE_VALUE_AND_TYPE_GETTERS
|
||||
|
||||
@@ -552,11 +530,9 @@ TypedValue &TypedValue::operator=(const TypedValue &other) {
|
||||
case TypedValue::Type::Path:
|
||||
new (&path_v) Path(other.path_v, memory_);
|
||||
return *this;
|
||||
case TypedValue::Type::Graph: {
|
||||
auto *graph_ptr = utils::Allocator<Graph>(memory_).new_object<Graph>(*other.graph_v);
|
||||
new (&graph_v) std::unique_ptr<Graph>(graph_ptr);
|
||||
case TypedValue::Type::Graph:
|
||||
new (&graph_v) Graph(other.graph_v, memory_);
|
||||
return *this;
|
||||
}
|
||||
case Type::Date:
|
||||
new (&date_v) utils::Date(other.date_v);
|
||||
return *this;
|
||||
@@ -629,12 +605,7 @@ TypedValue &TypedValue::operator=(TypedValue &&other) noexcept(false) {
|
||||
new (&duration_v) utils::Duration(other.duration_v);
|
||||
break;
|
||||
case Type::Graph:
|
||||
if (other.GetMemoryResource() == memory_) {
|
||||
new (&graph_v) std::unique_ptr<Graph>(std::move(other.graph_v));
|
||||
} else {
|
||||
auto *graph_ptr = utils::Allocator<Graph>(memory_).new_object<Graph>(std::move(*other.graph_v));
|
||||
new (&graph_v) std::unique_ptr<Graph>(graph_ptr);
|
||||
}
|
||||
new (&graph_v) Graph(std::move(other.graph_v), memory_);
|
||||
break;
|
||||
}
|
||||
other.DestroyValue();
|
||||
@@ -654,36 +625,31 @@ void TypedValue::DestroyValue() {
|
||||
// we need to call destructors for non primitive types since we used
|
||||
// placement new
|
||||
case Type::String:
|
||||
std::destroy_at(&string_v);
|
||||
string_v.~TString();
|
||||
break;
|
||||
case Type::List:
|
||||
std::destroy_at(&list_v);
|
||||
list_v.~TVector();
|
||||
break;
|
||||
case Type::Map:
|
||||
std::destroy_at(&map_v);
|
||||
map_v.~TMap();
|
||||
break;
|
||||
case Type::Vertex:
|
||||
std::destroy_at(&vertex_v);
|
||||
vertex_v.~VertexAccessor();
|
||||
break;
|
||||
case Type::Edge:
|
||||
std::destroy_at(&edge_v);
|
||||
edge_v.~EdgeAccessor();
|
||||
break;
|
||||
case Type::Path:
|
||||
std::destroy_at(&path_v);
|
||||
path_v.~Path();
|
||||
break;
|
||||
case Type::Date:
|
||||
case Type::LocalTime:
|
||||
case Type::LocalDateTime:
|
||||
case Type::Duration:
|
||||
break;
|
||||
case Type::Graph: {
|
||||
auto *graph = graph_v.release();
|
||||
std::destroy_at(&graph_v);
|
||||
if (graph) {
|
||||
utils::Allocator<Graph>(memory_).delete_object(graph);
|
||||
}
|
||||
case Type::Graph:
|
||||
graph_v.~Graph();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
type_ = TypedValue::Type::Null;
|
||||
|
||||
@@ -416,8 +416,7 @@ class TypedValue {
|
||||
* element-wise move and graph is not guaranteed to be empty.
|
||||
*/
|
||||
TypedValue(Graph &&graph, utils::MemoryResource *memory) : memory_(memory), type_(Type::Graph) {
|
||||
auto *graph_ptr = utils::Allocator<Graph>(memory_).new_object<Graph>(std::move(graph));
|
||||
new (&graph_v) std::unique_ptr<Graph>(graph_ptr);
|
||||
new (&graph_v) Graph(std::move(graph), memory_);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -548,8 +547,7 @@ class TypedValue {
|
||||
utils::LocalTime local_time_v;
|
||||
utils::LocalDateTime local_date_time_v;
|
||||
utils::Duration duration_v;
|
||||
// As the unique_ptr is not allocator aware, it requires special attention when copying or moving graphs
|
||||
std::unique_ptr<Graph> graph_v;
|
||||
Graph graph_v;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <variant>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
@@ -28,7 +26,6 @@
|
||||
#include "storage/v2/durability/snapshot.hpp"
|
||||
#include "storage/v2/durability/wal.hpp"
|
||||
#include "storage/v2/edge_accessor.hpp"
|
||||
#include "storage/v2/edge_ref.hpp"
|
||||
#include "storage/v2/indices.hpp"
|
||||
#include "storage/v2/mvcc.hpp"
|
||||
#include "storage/v2/replication/config.hpp"
|
||||
@@ -527,30 +524,6 @@ std::optional<VertexAccessor> Storage::Accessor::FindVertex(Gid gid, View view)
|
||||
return VertexAccessor::Create(&*it, &transaction_, &storage_->indices_, &storage_->constraints_, config_, view);
|
||||
}
|
||||
|
||||
std::optional<EdgeAccessor> Storage::Accessor::FindEdge(Gid edge_id, Gid vertex_id) {
|
||||
auto vertex_acc = storage_->vertices_.access();
|
||||
auto vertex = &*vertex_acc.find(vertex_id);
|
||||
auto it_in_edges =
|
||||
std::ranges::find_if(vertex->in_edges.begin(), vertex->in_edges.end(), [edge_id](const auto &item) {
|
||||
return (get<2>(item).ptr && get<2>(item).ptr->gid == edge_id) || get<2>(item).gid == edge_id;
|
||||
});
|
||||
|
||||
if (it_in_edges != vertex->in_edges.end())
|
||||
return EdgeAccessor{get<2>(*it_in_edges), get<0>(*it_in_edges), get<1>(*it_in_edges), vertex,
|
||||
&transaction_, &storage_->indices_, &storage_->constraints_, config_};
|
||||
|
||||
auto it_out_edges =
|
||||
std::ranges::find_if(vertex->out_edges.begin(), vertex->out_edges.end(), [edge_id](const auto &item) {
|
||||
return (get<2>(item).ptr && get<2>(item).ptr->gid == edge_id) || get<2>(item).gid == edge_id;
|
||||
});
|
||||
|
||||
if (it_out_edges != vertex->out_edges.end())
|
||||
return EdgeAccessor{get<2>(*it_out_edges), get<0>(*it_out_edges), vertex, get<1>(*it_out_edges), &transaction_,
|
||||
&storage_->indices_, &storage_->constraints_, config_};
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Result<std::optional<VertexAccessor>> Storage::Accessor::DeleteVertex(VertexAccessor *vertex) {
|
||||
MG_ASSERT(vertex->transaction_ == &transaction_,
|
||||
"VertexAccessor must be from the same transaction as the storage "
|
||||
|
||||
@@ -216,8 +216,6 @@ class Storage final {
|
||||
|
||||
std::optional<VertexAccessor> FindVertex(Gid gid, View view);
|
||||
|
||||
std::optional<EdgeAccessor> FindEdge(Gid edge_id, Gid vertex_id);
|
||||
|
||||
VerticesIterable Vertices(View view) {
|
||||
return VerticesIterable(AllVerticesIterable(storage_->vertices_.access(), &transaction_, view,
|
||||
&storage_->indices_, &storage_->constraints_,
|
||||
|
||||
@@ -11,188 +11,15 @@
|
||||
|
||||
#include "utils/async_timer.hpp"
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "utils/skip_list.hpp"
|
||||
#include "utils/spin_lock.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
inline constexpr uint64_t kInvalidFlagId = 0U;
|
||||
// std::numeric_limits<time_t>::max() cannot be represented precisely as a double, so the next smallest value is the
|
||||
// maximum number of seconds the timer can be used with
|
||||
const double max_seconds_as_double = std::nexttoward(std::numeric_limits<time_t>::max(), 0.0);
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::atomic<uint64_t> expiration_flag_counter{kInvalidFlagId + 1U};
|
||||
|
||||
struct ExpirationFlagInfo {
|
||||
uint64_t id{0U};
|
||||
std::weak_ptr<std::atomic<bool>> flag{};
|
||||
};
|
||||
|
||||
bool operator==(const ExpirationFlagInfo &lhs, const ExpirationFlagInfo &rhs) { return lhs.id == rhs.id; }
|
||||
bool operator<(const ExpirationFlagInfo &lhs, const ExpirationFlagInfo &rhs) { return lhs.id < rhs.id; }
|
||||
bool operator==(const ExpirationFlagInfo &flag_info, const uint64_t id) { return flag_info.id == id; }
|
||||
bool operator<(const ExpirationFlagInfo &flag_info, const uint64_t id) { return flag_info.id < id; }
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
memgraph::utils::SkipList<ExpirationFlagInfo> expiration_flags{};
|
||||
|
||||
uint64_t AddFlag(std::weak_ptr<std::atomic<bool>> flag) {
|
||||
const auto id = expiration_flag_counter.fetch_add(1, std::memory_order_relaxed);
|
||||
expiration_flags.access().insert({id, std::move(flag)});
|
||||
return id;
|
||||
}
|
||||
|
||||
void EraseFlag(uint64_t flag_id) { expiration_flags.access().remove(flag_id); }
|
||||
|
||||
std::weak_ptr<std::atomic<bool>> GetFlag(uint64_t flag_id) {
|
||||
const auto flag_accessor = expiration_flags.access();
|
||||
const auto it = flag_accessor.find(flag_id);
|
||||
if (it == flag_accessor.end()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return it->flag;
|
||||
}
|
||||
|
||||
void MarkDone(const uint64_t flag_id) {
|
||||
const auto weak_flag = GetFlag(flag_id);
|
||||
if (weak_flag.expired()) {
|
||||
return;
|
||||
}
|
||||
auto flag = weak_flag.lock();
|
||||
if (flag != nullptr) {
|
||||
flag->store(true, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
namespace {
|
||||
struct ThreadInfo {
|
||||
pid_t thread_id;
|
||||
std::atomic<bool> setup_done{false};
|
||||
};
|
||||
|
||||
void *TimerBackgroundWorker(void *args) {
|
||||
auto *thread_info = static_cast<ThreadInfo *>(args);
|
||||
thread_info->thread_id = syscall(SYS_gettid);
|
||||
thread_info->setup_done.store(true, std::memory_order_release);
|
||||
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGTIMER);
|
||||
sigprocmask(SIG_BLOCK, &ss, nullptr);
|
||||
|
||||
while (true) {
|
||||
siginfo_t si;
|
||||
int result = sigwaitinfo(&ss, &si);
|
||||
|
||||
if (result <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (si.si_code == SI_TIMER) {
|
||||
auto flag_id = kInvalidFlagId;
|
||||
std::memcpy(&flag_id, &si.si_value.sival_ptr, sizeof(flag_id));
|
||||
MarkDone(flag_id);
|
||||
} else if (si.si_code == SI_TKILL) {
|
||||
pthread_exit(nullptr);
|
||||
}
|
||||
}
|
||||
AsyncTimer::AsyncTimer(double seconds) {
|
||||
// TODO(gitbuda): Implement AsyncTimer constructor.
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AsyncTimer::AsyncTimer() : flag_id_{kInvalidFlagId} {};
|
||||
|
||||
AsyncTimer::AsyncTimer(double seconds)
|
||||
: expiration_flag_{std::make_shared<std::atomic<bool>>(false)}, flag_id_{kInvalidFlagId}, timer_id_{} {
|
||||
MG_ASSERT(seconds <= max_seconds_as_double,
|
||||
"The AsyncTimer cannot handle larger time values than {:f}, the specified value: {:f}",
|
||||
max_seconds_as_double, seconds);
|
||||
MG_ASSERT(seconds >= 0.0, "The AsyncTimer cannot handle negative time values: {:f}", seconds);
|
||||
|
||||
static pthread_t background_timer_thread;
|
||||
static ThreadInfo thread_info;
|
||||
static std::once_flag timer_thread_setup_flag;
|
||||
|
||||
std::call_once(timer_thread_setup_flag, [] {
|
||||
pthread_create(&background_timer_thread, nullptr, TimerBackgroundWorker, &thread_info);
|
||||
while (!thread_info.setup_done.load(std::memory_order_acquire))
|
||||
;
|
||||
});
|
||||
|
||||
flag_id_ = AddFlag(std::weak_ptr<std::atomic<bool>>{expiration_flag_});
|
||||
|
||||
sigevent notification_settings{};
|
||||
notification_settings.sigev_notify = SIGEV_THREAD_ID;
|
||||
notification_settings.sigev_signo = SIGTIMER;
|
||||
notification_settings._sigev_un._tid = thread_info.thread_id;
|
||||
static_assert(sizeof(void *) == sizeof(flag_id_), "ID size must be equal to pointer size!");
|
||||
std::memcpy(¬ification_settings.sigev_value.sival_ptr, &flag_id_, sizeof(flag_id_));
|
||||
MG_ASSERT(timer_create(CLOCK_MONOTONIC, ¬ification_settings, &timer_id_) == 0, "Couldn't create timer: ({}) {}",
|
||||
errno, strerror(errno));
|
||||
|
||||
static constexpr auto kSecondsToNanos = 1000 * 1000 * 1000;
|
||||
// Casting will truncate down, but that's exactly what we want.
|
||||
const auto second_as_time_t = static_cast<time_t>(seconds);
|
||||
const auto remaining_nano_seconds = static_cast<time_t>((seconds - second_as_time_t) * kSecondsToNanos);
|
||||
|
||||
struct itimerspec spec;
|
||||
spec.it_interval.tv_sec = 0;
|
||||
spec.it_interval.tv_nsec = 0;
|
||||
spec.it_value.tv_sec = second_as_time_t;
|
||||
spec.it_value.tv_nsec = remaining_nano_seconds;
|
||||
|
||||
MG_ASSERT(timer_settime(timer_id_, 0, &spec, nullptr) == 0, "Couldn't set timer: ({}) {}", errno, strerror(errno));
|
||||
}
|
||||
|
||||
AsyncTimer::~AsyncTimer() { ReleaseResources(); }
|
||||
|
||||
AsyncTimer::AsyncTimer(AsyncTimer &&other) noexcept
|
||||
: expiration_flag_{std::move(other.expiration_flag_)}, flag_id_{other.flag_id_}, timer_id_{other.timer_id_} {
|
||||
other.flag_id_ = kInvalidFlagId;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE (hicpp-noexcept-move)
|
||||
AsyncTimer &AsyncTimer::operator=(AsyncTimer &&other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReleaseResources();
|
||||
|
||||
expiration_flag_ = std::move(other.expiration_flag_);
|
||||
flag_id_ = std::exchange(other.flag_id_, kInvalidFlagId);
|
||||
timer_id_ = other.timer_id_;
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
bool AsyncTimer::IsExpired() const noexcept {
|
||||
if (expiration_flag_ != nullptr) {
|
||||
return expiration_flag_->load(std::memory_order_relaxed);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsyncTimer::ReleaseResources() {
|
||||
if (expiration_flag_ != nullptr) {
|
||||
timer_delete(timer_id_);
|
||||
EraseFlag(flag_id_);
|
||||
flag_id_ = kInvalidFlagId;
|
||||
expiration_flag_ = std::shared_ptr<std::atomic<bool>>{};
|
||||
}
|
||||
// TODO(gitbuda): Implement AsyncTimer::IsExpired
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace memgraph::utils
|
||||
|
||||
@@ -10,39 +10,21 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#pragma once
|
||||
#include <time.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
#define SIGTIMER (SIGRTMAX - 2)
|
||||
|
||||
class AsyncTimer {
|
||||
public:
|
||||
AsyncTimer();
|
||||
explicit AsyncTimer(double seconds);
|
||||
~AsyncTimer();
|
||||
AsyncTimer(AsyncTimer &&other) noexcept;
|
||||
// NOLINTNEXTLINE (hicpp-noexcept-move)
|
||||
AsyncTimer &operator=(AsyncTimer &&other);
|
||||
|
||||
AsyncTimer() = default;
|
||||
~AsyncTimer() = default;
|
||||
AsyncTimer(AsyncTimer &&other) = default;
|
||||
AsyncTimer &operator=(AsyncTimer &&other) = default;
|
||||
AsyncTimer(const AsyncTimer &) = delete;
|
||||
AsyncTimer &operator=(const AsyncTimer &) = delete;
|
||||
|
||||
// Returns false if the object isn't associated with any timer.
|
||||
bool IsExpired() const noexcept;
|
||||
|
||||
private:
|
||||
void ReleaseResources();
|
||||
|
||||
// If the expiration_flag_ is nullptr, then the object is not associated with any timer, therefore no clean up
|
||||
// is necessary. Furthermore, the the POSIX API doesn't specify any value as "invalid" for timer_t, so the timer_id_
|
||||
// cannot be used to determine whether the object is associated with any timer or not.
|
||||
std::shared_ptr<std::atomic<bool>> expiration_flag_;
|
||||
uint64_t flag_id_;
|
||||
timer_t timer_id_;
|
||||
};
|
||||
} // namespace memgraph::utils
|
||||
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ void Reader::TryInitializeHeader() {
|
||||
}
|
||||
|
||||
if (header->empty()) {
|
||||
throw CsvReadException("CSV file {} empty!", path_);
|
||||
throw CsvReadException("CSV file {} empty!", path_.string());
|
||||
}
|
||||
|
||||
number_of_columns_ = header->size();
|
||||
|
||||
@@ -52,7 +52,7 @@ void EnsureDirOrDie(const std::filesystem::path &dir) {
|
||||
MG_ASSERT(EnsureDir(dir),
|
||||
"Couldn't create directory '{}' due to a permission issue or the "
|
||||
"path exists and isn't a directory!",
|
||||
dir);
|
||||
dir.string());
|
||||
}
|
||||
|
||||
bool DirExists(const std::filesystem::path &dir) {
|
||||
@@ -82,7 +82,8 @@ bool RenamePath(const std::filesystem::path &src, const std::filesystem::path &d
|
||||
return !error_code;
|
||||
}
|
||||
|
||||
static_assert(std::is_same_v<off_t, ssize_t>, "off_t must fit into ssize_t!");
|
||||
// TODO(gitbuda): Port static_assert(off_t = ssize_t)
|
||||
// static_assert(std::is_same_v<off_t, ssize_t>, "off_t must fit into ssize_t!");
|
||||
|
||||
InputFile::~InputFile() { Close(); }
|
||||
|
||||
@@ -248,7 +249,7 @@ void InputFile::Close() noexcept {
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
spdlog::error("While trying to close {} an error occured: {} ({})", path_, strerror(errno), errno);
|
||||
spdlog::error("While trying to close {} an error occured: {} ({})", path_.string(), strerror(errno), errno);
|
||||
}
|
||||
|
||||
fd_ = -1;
|
||||
@@ -321,7 +322,7 @@ void OutputFile::Open(const std::filesystem::path &path, Mode mode) {
|
||||
MG_ASSERT(!IsOpen(),
|
||||
"While trying to open {} for writing the database"
|
||||
" used a handle that already has {} opened in it!",
|
||||
path, path_);
|
||||
path.string(), path_.string());
|
||||
path_ = path;
|
||||
written_since_last_sync_ = 0;
|
||||
|
||||
@@ -341,7 +342,7 @@ void OutputFile::Open(const std::filesystem::path &path, Mode mode) {
|
||||
}
|
||||
}
|
||||
|
||||
MG_ASSERT(fd_ != -1, "While trying to open {} for writing an error occured: {} ({})", path_, strerror(errno), errno);
|
||||
MG_ASSERT(fd_ != -1, "While trying to open {} for writing an error occured: {} ({})", path_.string(), strerror(errno), errno);
|
||||
}
|
||||
|
||||
bool OutputFile::IsOpen() const { return fd_ != -1; }
|
||||
@@ -390,7 +391,7 @@ size_t OutputFile::SeekFile(const Position position, const ssize_t offset) {
|
||||
if (pos == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
MG_ASSERT(pos >= 0, "While trying to set the position in {} an error occured: {} ({})", path_, strerror(errno),
|
||||
MG_ASSERT(pos >= 0, "While trying to set the position in {} an error occured: {} ({})", path_.string(), strerror(errno),
|
||||
errno);
|
||||
return pos;
|
||||
}
|
||||
@@ -467,7 +468,7 @@ void OutputFile::Sync() {
|
||||
MG_ASSERT(ret == 0,
|
||||
"While trying to sync {}, an error occurred: {} ({}). Possibly {} "
|
||||
"bytes from previous write calls were lost.",
|
||||
path_, strerror(errno), errno, written_since_last_sync_);
|
||||
path_.string(), strerror(errno), errno, written_since_last_sync_);
|
||||
|
||||
// Reset the counter.
|
||||
written_since_last_sync_ = 0;
|
||||
@@ -492,7 +493,7 @@ void OutputFile::Close() noexcept {
|
||||
MG_ASSERT(ret == 0,
|
||||
"While trying to close {}, an error occurred: {} ({}). Possibly {} "
|
||||
"bytes from previous write calls were lost.",
|
||||
path_, strerror(errno), errno, written_since_last_sync_);
|
||||
path_.string(), strerror(errno), errno, written_since_last_sync_);
|
||||
|
||||
fd_ = -1;
|
||||
written_since_last_sync_ = 0;
|
||||
@@ -512,7 +513,7 @@ void OutputFile::FlushBufferInternal() {
|
||||
MG_ASSERT(buffer_position_ <= kFileBufferSize,
|
||||
"While trying to write to {} more file was written to the "
|
||||
"buffer than the buffer has space!",
|
||||
path_);
|
||||
path_.string());
|
||||
|
||||
auto *buffer = buffer_;
|
||||
auto buffer_position = buffer_position_.load();
|
||||
@@ -526,7 +527,7 @@ void OutputFile::FlushBufferInternal() {
|
||||
"while trying to write to {} an error occurred: {} ({}). "
|
||||
"Possibly {} bytes of data were lost from this call and "
|
||||
"possibly {} bytes were lost from previous calls.",
|
||||
path_, strerror(errno), errno, buffer_position_, written_since_last_sync_);
|
||||
path_.string(), strerror(errno), errno, buffer_position_, written_since_last_sync_);
|
||||
|
||||
buffer_position -= written;
|
||||
buffer += written;
|
||||
|
||||
@@ -10,14 +10,17 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include "utils/file_locker.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
namespace {
|
||||
void DeleteFromSystem(const std::filesystem::path &path) {
|
||||
if (!utils::DeleteFile(path)) {
|
||||
spdlog::warn("Couldn't delete file {}!", path);
|
||||
spdlog::warn("Couldn't delete file {}!", path.string());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -25,7 +28,7 @@ void DeleteFromSystem(const std::filesystem::path &path) {
|
||||
////// FileRetainer //////
|
||||
void FileRetainer::DeleteFile(const std::filesystem::path &path) {
|
||||
if (!std::filesystem::exists(path)) {
|
||||
spdlog::info("File {} doesn't exist.", path);
|
||||
spdlog::info("File {} doesn't exist.", path.string());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
|
||||
129
src/utils/lock/linux_rw_lock.hpp
Normal file
129
src/utils/lock/linux_rw_lock.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
/// @file
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils::lock {
|
||||
|
||||
/// A wrapper around `pthread_rwlock_t`, useful because it is not possible to
|
||||
/// choose read or write priority for `std::shared_mutex`.
|
||||
class RWLock {
|
||||
public:
|
||||
/// By passing the appropriate parameter to the `RWLock` constructor, it is
|
||||
/// possible to control the behavior of `RWLock` while shared lock is held. If
|
||||
/// the priority is set to `READ`, new shared (read) locks can be obtained
|
||||
/// even though there is a thread waiting for an exclusive (write) lock, which
|
||||
/// can lead to writer starvation. If the priority is set to `WRITE`, readers
|
||||
/// will be blocked from obtaining new shared locks while there are writers
|
||||
/// waiting, which can lead to reader starvation.
|
||||
enum class Priority { READ, WRITE };
|
||||
|
||||
/// Construct a RWLock object with chosen priority. See comment above
|
||||
/// `RWLockPriority` for details.
|
||||
explicit RWLock(Priority priority) {
|
||||
pthread_rwlockattr_t attr;
|
||||
|
||||
MG_ASSERT(pthread_rwlockattr_init(&attr) == 0, "Couldn't initialize utils::RWLock!");
|
||||
|
||||
switch (priority) {
|
||||
case Priority::READ:
|
||||
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_READER_NP);
|
||||
break;
|
||||
case Priority::WRITE:
|
||||
// There is also `PTHREAD_RWLOCK_PREFER_WRITER_NP` but it is not
|
||||
// providing the desired behavior.
|
||||
//
|
||||
// From `man 7 pthread_rwlockattr_setkind_np`:
|
||||
// "Setting the value read-write lock kind to
|
||||
// PTHREAD_RWLOCK_PREFER_WRITER_NP results in the same behavior as
|
||||
// setting the value to PTHREAD_RWLOCK_PREFER_READER_NP. As long as a
|
||||
// reader thread holds the lock, the thread holding a write lock will be
|
||||
// starved. Setting the lock kind to
|
||||
// PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP allows writers to run,
|
||||
// but, as the name implies a writer may not lock recursively."
|
||||
//
|
||||
// For this reason, `RWLock` should not be used recursively.
|
||||
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
|
||||
break;
|
||||
}
|
||||
|
||||
MG_ASSERT(pthread_rwlock_init(&lock_, &attr) == 0, "Couldn't initialize utils::RWLock!");
|
||||
pthread_rwlockattr_destroy(&attr);
|
||||
}
|
||||
|
||||
RWLock(const RWLock &) = delete;
|
||||
RWLock &operator=(const RWLock &) = delete;
|
||||
RWLock(RWLock &&) = delete;
|
||||
RWLock &operator=(RWLock &&) = delete;
|
||||
|
||||
~RWLock() { pthread_rwlock_destroy(&lock_); }
|
||||
|
||||
void lock() { MG_ASSERT(pthread_rwlock_wrlock(&lock_) == 0, "Couldn't lock utils::RWLock!"); }
|
||||
|
||||
bool try_lock() {
|
||||
int err = pthread_rwlock_trywrlock(&lock_);
|
||||
if (err == 0) return true;
|
||||
MG_ASSERT(err == EBUSY, "Couldn't try lock utils::RWLock!");
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlock() { MG_ASSERT(pthread_rwlock_unlock(&lock_) == 0, "Couldn't unlock utils::RWLock!"); }
|
||||
|
||||
void lock_shared() {
|
||||
int err;
|
||||
while (true) {
|
||||
err = pthread_rwlock_rdlock(&lock_);
|
||||
if (err == 0) {
|
||||
return;
|
||||
} else if (err == EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
LOG_FATAL("Couldn't lock shared utils::RWLock!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_shared() {
|
||||
int err;
|
||||
while (true) {
|
||||
err = pthread_rwlock_tryrdlock(&lock_);
|
||||
if (err == 0) {
|
||||
return true;
|
||||
} else if (err == EBUSY) {
|
||||
return false;
|
||||
} else if (err == EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
LOG_FATAL("Couldn't try lock shared utils::RWLock!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared() { MG_ASSERT(pthread_rwlock_unlock(&lock_) == 0, "Couldn't unlock shared utils::RWLock!"); }
|
||||
|
||||
private:
|
||||
pthread_rwlock_t lock_ = PTHREAD_RWLOCK_INITIALIZER;
|
||||
};
|
||||
|
||||
class WritePrioritizedRWLock final : public RWLock {
|
||||
public:
|
||||
WritePrioritizedRWLock() : RWLock{Priority::WRITE} {};
|
||||
};
|
||||
|
||||
} // namespace memgraph::utils
|
||||
78
src/utils/lock/linux_spin_lock.hpp
Normal file
78
src/utils/lock/linux_spin_lock.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils::lock {
|
||||
|
||||
/// This class is a wrapper around the `pthread_spinlock_t`. It provides a
|
||||
/// generic spin lock. The lock should be used in cases where you know that the
|
||||
/// lock will be contended only for short periods of time. This lock doesn't
|
||||
/// make any kernel calls (like sleep, or context switching) during its wait for
|
||||
/// the lock to be acquired. This property is only useful when the lock will be
|
||||
/// held for short periods of time and you don't want to introduce the extra
|
||||
/// delays of a sleep or context switch. On the assembly level
|
||||
/// `pthread_spinlock_t` is optimized to use less power, reduce branch
|
||||
/// mispredictions, etc... The explanation can be seen here:
|
||||
/// https://stackoverflow.com/questions/26583433/c11-implementation-of-spinlock-using-atomic/29195378#29195378
|
||||
/// https://software.intel.com/en-us/node/524249
|
||||
class SpinLock {
|
||||
public:
|
||||
SpinLock() {
|
||||
// `pthread_spin_init` returns -1 only when there isn't enough memory to
|
||||
// initialize the lock. That should never occur because the
|
||||
// `pthread_spinlock_t` is an `int` and memory isn't allocated by this init.
|
||||
// The message is probably here to suit all other platforms...
|
||||
MG_ASSERT(pthread_spin_init(&lock_, PTHREAD_PROCESS_PRIVATE) == 0, "Couldn't construct utils::SpinLock!");
|
||||
}
|
||||
|
||||
SpinLock(SpinLock &&other) noexcept : lock_(other.lock_) {
|
||||
MG_ASSERT(pthread_spin_init(&other.lock_, PTHREAD_PROCESS_PRIVATE) == 0, "Couldn't construct utils::SpinLock!");
|
||||
}
|
||||
|
||||
SpinLock &operator=(SpinLock &&other) noexcept {
|
||||
MG_ASSERT(pthread_spin_destroy(&lock_) == 0, "Couldn't destruct utils::SpinLock!");
|
||||
lock_ = other.lock_;
|
||||
MG_ASSERT(pthread_spin_init(&other.lock_, PTHREAD_PROCESS_PRIVATE) == 0, "Couldn't construct utils::SpinLock!");
|
||||
return *this;
|
||||
}
|
||||
|
||||
SpinLock(const SpinLock &) = delete;
|
||||
SpinLock &operator=(const SpinLock &) = delete;
|
||||
|
||||
~SpinLock() { MG_ASSERT(pthread_spin_destroy(&lock_) == 0, "Couldn't destruct utils::SpinLock!"); }
|
||||
|
||||
void lock() {
|
||||
// `pthread_spin_lock` returns -1 only when there is a deadlock detected
|
||||
// (errno EDEADLOCK).
|
||||
MG_ASSERT(pthread_spin_lock(&lock_) == 0, "Couldn't lock utils::SpinLock!");
|
||||
}
|
||||
|
||||
bool try_lock() {
|
||||
// `pthread_spin_trylock` returns -1 only when the lock is already locked
|
||||
// (errno EBUSY).
|
||||
return pthread_spin_trylock(&lock_) == 0;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
// `pthread_spin_unlock` has no documented error codes that it could return,
|
||||
// so any error is a fatal error.
|
||||
MG_ASSERT(pthread_spin_unlock(&lock_) == 0, "Couldn't unlock utils::SpinLock!");
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_spinlock_t lock_;
|
||||
};
|
||||
} // namespace memgraph::utils
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
static_assert(std::is_same_v<uint64_t, unsigned long>,
|
||||
static_assert(std::is_same_v<uint64_t, unsigned long long>,
|
||||
"utils::Log requires uint64_t to be implemented as unsigned long.");
|
||||
|
||||
/// This function computes the log2 function on integer types. It is faster than
|
||||
|
||||
@@ -87,7 +87,8 @@ void MonotonicBufferResource::Release() {
|
||||
|
||||
void *MonotonicBufferResource::DoAllocate(size_t bytes, size_t alignment) {
|
||||
static_assert(std::is_same_v<size_t, uintptr_t>);
|
||||
static_assert(std::is_same_v<size_t, uint64_t>);
|
||||
// TODO(gitbuda): Fix huge static_assert that size_t == uint64_t
|
||||
//static_assert(std::is_same_v<size_t, uint64_t>);
|
||||
auto push_current_buffer = [this, bytes, alignment](size_t next_size) {
|
||||
// Set size so that the bytes fit.
|
||||
const size_t size = next_size > bytes ? next_size : bytes;
|
||||
|
||||
@@ -12,113 +12,47 @@
|
||||
/// @file
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
/// A wrapper around `pthread_rwlock_t`, useful because it is not possible to
|
||||
/// choose read or write priority for `std::shared_mutex`.
|
||||
class RWLock {
|
||||
public:
|
||||
/// By passing the appropriate parameter to the `RWLock` constructor, it is
|
||||
/// possible to control the behavior of `RWLock` while shared lock is held. If
|
||||
/// the priority is set to `READ`, new shared (read) locks can be obtained
|
||||
/// even though there is a thread waiting for an exclusive (write) lock, which
|
||||
/// can lead to writer starvation. If the priority is set to `WRITE`, readers
|
||||
/// will be blocked from obtaining new shared locks while there are writers
|
||||
/// waiting, which can lead to reader starvation.
|
||||
enum class Priority { READ, WRITE };
|
||||
|
||||
/// Construct a RWLock object with chosen priority. See comment above
|
||||
/// `RWLockPriority` for details.
|
||||
explicit RWLock(Priority priority) {
|
||||
pthread_rwlockattr_t attr;
|
||||
|
||||
MG_ASSERT(pthread_rwlockattr_init(&attr) == 0, "Couldn't initialize utils::RWLock!");
|
||||
|
||||
switch (priority) {
|
||||
case Priority::READ:
|
||||
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_READER_NP);
|
||||
break;
|
||||
case Priority::WRITE:
|
||||
// There is also `PTHREAD_RWLOCK_PREFER_WRITER_NP` but it is not
|
||||
// providing the desired behavior.
|
||||
//
|
||||
// From `man 7 pthread_rwlockattr_setkind_np`:
|
||||
// "Setting the value read-write lock kind to
|
||||
// PTHREAD_RWLOCK_PREFER_WRITER_NP results in the same behavior as
|
||||
// setting the value to PTHREAD_RWLOCK_PREFER_READER_NP. As long as a
|
||||
// reader thread holds the lock, the thread holding a write lock will be
|
||||
// starved. Setting the lock kind to
|
||||
// PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP allows writers to run,
|
||||
// but, as the name implies a writer may not lock recursively."
|
||||
//
|
||||
// For this reason, `RWLock` should not be used recursively.
|
||||
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
|
||||
break;
|
||||
}
|
||||
|
||||
MG_ASSERT(pthread_rwlock_init(&lock_, &attr) == 0, "Couldn't initialize utils::RWLock!");
|
||||
pthread_rwlockattr_destroy(&attr);
|
||||
// TODO(gitbuda): Implement RWLock::RWLock(Priority)
|
||||
}
|
||||
|
||||
RWLock(const RWLock &) = delete;
|
||||
RWLock &operator=(const RWLock &) = delete;
|
||||
RWLock(RWLock &&) = delete;
|
||||
RWLock &operator=(RWLock &&) = delete;
|
||||
~RWLock() = default;
|
||||
|
||||
~RWLock() { pthread_rwlock_destroy(&lock_); }
|
||||
|
||||
void lock() { MG_ASSERT(pthread_rwlock_wrlock(&lock_) == 0, "Couldn't lock utils::RWLock!"); }
|
||||
void lock() {
|
||||
// TODO(gitbuda): Implement RWLock::lock
|
||||
}
|
||||
|
||||
bool try_lock() {
|
||||
int err = pthread_rwlock_trywrlock(&lock_);
|
||||
if (err == 0) return true;
|
||||
MG_ASSERT(err == EBUSY, "Couldn't try lock utils::RWLock!");
|
||||
// TODO(gitbuda): Implement RWLock::try_lock
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlock() { MG_ASSERT(pthread_rwlock_unlock(&lock_) == 0, "Couldn't unlock utils::RWLock!"); }
|
||||
void unlock() {
|
||||
// TODO(gitbuda): Implement RWLock::unlock
|
||||
}
|
||||
|
||||
void lock_shared() {
|
||||
int err;
|
||||
while (true) {
|
||||
err = pthread_rwlock_rdlock(&lock_);
|
||||
if (err == 0) {
|
||||
return;
|
||||
} else if (err == EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
LOG_FATAL("Couldn't lock shared utils::RWLock!");
|
||||
}
|
||||
}
|
||||
// TODO(gitbuda): Implement RWLock::lock_shared
|
||||
}
|
||||
|
||||
bool try_lock_shared() {
|
||||
int err;
|
||||
while (true) {
|
||||
err = pthread_rwlock_tryrdlock(&lock_);
|
||||
if (err == 0) {
|
||||
return true;
|
||||
} else if (err == EBUSY) {
|
||||
return false;
|
||||
} else if (err == EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
LOG_FATAL("Couldn't try lock shared utils::RWLock!");
|
||||
}
|
||||
}
|
||||
// TODO(gitbuda): Implement RWLock::try_lock_shared
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlock_shared() { MG_ASSERT(pthread_rwlock_unlock(&lock_) == 0, "Couldn't unlock shared utils::RWLock!"); }
|
||||
|
||||
private:
|
||||
pthread_rwlock_t lock_ = PTHREAD_RWLOCK_INITIALIZER;
|
||||
void unlock_shared() {
|
||||
// TODO(gitbuda): Implement RWLock::try_lock_shared
|
||||
}
|
||||
};
|
||||
|
||||
class WritePrioritizedRWLock final : public RWLock {
|
||||
|
||||
@@ -11,68 +11,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
/// This class is a wrapper around the `pthread_spinlock_t`. It provides a
|
||||
/// generic spin lock. The lock should be used in cases where you know that the
|
||||
/// lock will be contended only for short periods of time. This lock doesn't
|
||||
/// make any kernel calls (like sleep, or context switching) during its wait for
|
||||
/// the lock to be acquired. This property is only useful when the lock will be
|
||||
/// held for short periods of time and you don't want to introduce the extra
|
||||
/// delays of a sleep or context switch. On the assembly level
|
||||
/// `pthread_spinlock_t` is optimized to use less power, reduce branch
|
||||
/// mispredictions, etc... The explanation can be seen here:
|
||||
/// https://stackoverflow.com/questions/26583433/c11-implementation-of-spinlock-using-atomic/29195378#29195378
|
||||
/// https://software.intel.com/en-us/node/524249
|
||||
class SpinLock {
|
||||
public:
|
||||
SpinLock() {
|
||||
// `pthread_spin_init` returns -1 only when there isn't enough memory to
|
||||
// initialize the lock. That should never occur because the
|
||||
// `pthread_spinlock_t` is an `int` and memory isn't allocated by this init.
|
||||
// The message is probably here to suit all other platforms...
|
||||
MG_ASSERT(pthread_spin_init(&lock_, PTHREAD_PROCESS_PRIVATE) == 0, "Couldn't construct utils::SpinLock!");
|
||||
}
|
||||
|
||||
SpinLock(SpinLock &&other) noexcept : lock_(other.lock_) {
|
||||
MG_ASSERT(pthread_spin_init(&other.lock_, PTHREAD_PROCESS_PRIVATE) == 0, "Couldn't construct utils::SpinLock!");
|
||||
}
|
||||
|
||||
SpinLock &operator=(SpinLock &&other) noexcept {
|
||||
MG_ASSERT(pthread_spin_destroy(&lock_) == 0, "Couldn't destruct utils::SpinLock!");
|
||||
lock_ = other.lock_;
|
||||
MG_ASSERT(pthread_spin_init(&other.lock_, PTHREAD_PROCESS_PRIVATE) == 0, "Couldn't construct utils::SpinLock!");
|
||||
return *this;
|
||||
}
|
||||
SpinLock() {}
|
||||
|
||||
SpinLock(SpinLock &&other) = default;
|
||||
SpinLock &operator=(SpinLock &&other) = default;
|
||||
SpinLock(const SpinLock &) = delete;
|
||||
SpinLock &operator=(const SpinLock &) = delete;
|
||||
|
||||
~SpinLock() { MG_ASSERT(pthread_spin_destroy(&lock_) == 0, "Couldn't destruct utils::SpinLock!"); }
|
||||
~SpinLock() = default;
|
||||
|
||||
void lock() {
|
||||
// `pthread_spin_lock` returns -1 only when there is a deadlock detected
|
||||
// (errno EDEADLOCK).
|
||||
MG_ASSERT(pthread_spin_lock(&lock_) == 0, "Couldn't lock utils::SpinLock!");
|
||||
// TODO(gitbuda): Implement SpinLock::lock
|
||||
}
|
||||
|
||||
bool try_lock() {
|
||||
// `pthread_spin_trylock` returns -1 only when the lock is already locked
|
||||
// (errno EBUSY).
|
||||
return pthread_spin_trylock(&lock_) == 0;
|
||||
// TODO(gitbuda): Implement SpinLock::try_lock
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
// `pthread_spin_unlock` has no documented error codes that it could return,
|
||||
// so any error is a fatal error.
|
||||
MG_ASSERT(pthread_spin_unlock(&lock_) == 0, "Couldn't unlock utils::SpinLock!");
|
||||
// TODO(gitbuda): Implement SpinLock::unlock
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_spinlock_t lock_;
|
||||
};
|
||||
|
||||
} // namespace memgraph::utils
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <execinfo.h>
|
||||
#include <fmt/format.h>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/on_scope_exit.hpp"
|
||||
|
||||
|
||||
@@ -37,10 +37,11 @@ std::optional<T> ParseNumber(const std::string_view string, const size_t size) {
|
||||
}
|
||||
|
||||
T value{};
|
||||
if (const auto [p, ec] = std::from_chars(string.data(), string.data() + size, value);
|
||||
ec != std::errc() || p != string.data() + size) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// TODO(gitbuda): Figure out what to do with deleted std::from_chars function
|
||||
// if (const auto [p, ec] = std::from_chars(string.data(), string.data() + size, value);
|
||||
// ec != std::errc() || p != string.data() + size) {
|
||||
// return std::nullopt;
|
||||
// }
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -11,19 +11,10 @@
|
||||
|
||||
#include "utils/thread.hpp"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
void ThreadSetName(const std::string &name) {
|
||||
static constexpr auto max_name_length = GetMaxThreadNameSize();
|
||||
MG_ASSERT(name.size() <= max_name_length, "Thread name '{}' is too long", max_name_length);
|
||||
|
||||
if (prctl(PR_SET_NAME, name.c_str()) != 0) {
|
||||
spdlog::warn("Couldn't set thread name: {}!", name);
|
||||
}
|
||||
// TODO(gitbuda): Implement cross platform ThreadSetName func
|
||||
}
|
||||
|
||||
} // namespace memgraph::utils
|
||||
|
||||
29
src/utils/thread/linux_thread.cpp
Normal file
29
src/utils/thread/linux_thread.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include "utils/thread.hpp"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
void ThreadSetName(const std::string &name) {
|
||||
static constexpr auto max_name_length = GetMaxThreadNameSize();
|
||||
MG_ASSERT(name.size() <= max_name_length, "Thread name '{}' is too long", max_name_length);
|
||||
|
||||
if (prctl(PR_SET_NAME, name.c_str()) != 0) {
|
||||
spdlog::warn("Couldn't set thread name: {}!", name);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace memgraph::utils
|
||||
25
src/utils/thread/linux_thread.hpp
Normal file
25
src/utils/thread/linux_thread.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
/// @file
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
constexpr size_t GetMaxThreadNameSize() { return 16; }
|
||||
|
||||
/// This function sets the thread name of the calling thread.
|
||||
/// Beware, the name length limit is 16 characters!
|
||||
void ThreadSetName(const std::string &name);
|
||||
|
||||
}; // namespace memgraph::utils
|
||||
198
src/utils/timer/linux_async_timer.cpp
Normal file
198
src/utils/timer/linux_async_timer.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include "utils/timer/linux_async_timer.hpp"
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "utils/skip_list.hpp"
|
||||
#include "utils/spin_lock.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
inline constexpr uint64_t kInvalidFlagId = 0U;
|
||||
// std::numeric_limits<time_t>::max() cannot be represented precisely as a double, so the next smallest value is the
|
||||
// maximum number of seconds the timer can be used with
|
||||
const double max_seconds_as_double = std::nexttoward(std::numeric_limits<time_t>::max(), 0.0);
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::atomic<uint64_t> expiration_flag_counter{kInvalidFlagId + 1U};
|
||||
|
||||
struct ExpirationFlagInfo {
|
||||
uint64_t id{0U};
|
||||
std::weak_ptr<std::atomic<bool>> flag{};
|
||||
};
|
||||
|
||||
bool operator==(const ExpirationFlagInfo &lhs, const ExpirationFlagInfo &rhs) { return lhs.id == rhs.id; }
|
||||
bool operator<(const ExpirationFlagInfo &lhs, const ExpirationFlagInfo &rhs) { return lhs.id < rhs.id; }
|
||||
bool operator==(const ExpirationFlagInfo &flag_info, const uint64_t id) { return flag_info.id == id; }
|
||||
bool operator<(const ExpirationFlagInfo &flag_info, const uint64_t id) { return flag_info.id < id; }
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
memgraph::utils::SkipList<ExpirationFlagInfo> expiration_flags{};
|
||||
|
||||
uint64_t AddFlag(std::weak_ptr<std::atomic<bool>> flag) {
|
||||
const auto id = expiration_flag_counter.fetch_add(1, std::memory_order_relaxed);
|
||||
expiration_flags.access().insert({id, std::move(flag)});
|
||||
return id;
|
||||
}
|
||||
|
||||
void EraseFlag(uint64_t flag_id) { expiration_flags.access().remove(flag_id); }
|
||||
|
||||
std::weak_ptr<std::atomic<bool>> GetFlag(uint64_t flag_id) {
|
||||
const auto flag_accessor = expiration_flags.access();
|
||||
const auto it = flag_accessor.find(flag_id);
|
||||
if (it == flag_accessor.end()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return it->flag;
|
||||
}
|
||||
|
||||
void MarkDone(const uint64_t flag_id) {
|
||||
const auto weak_flag = GetFlag(flag_id);
|
||||
if (weak_flag.expired()) {
|
||||
return;
|
||||
}
|
||||
auto flag = weak_flag.lock();
|
||||
if (flag != nullptr) {
|
||||
flag->store(true, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
namespace {
|
||||
struct ThreadInfo {
|
||||
pid_t thread_id;
|
||||
std::atomic<bool> setup_done{false};
|
||||
};
|
||||
|
||||
void *TimerBackgroundWorker(void *args) {
|
||||
auto *thread_info = static_cast<ThreadInfo *>(args);
|
||||
thread_info->thread_id = syscall(SYS_gettid);
|
||||
thread_info->setup_done.store(true, std::memory_order_release);
|
||||
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGTIMER);
|
||||
sigprocmask(SIG_BLOCK, &ss, nullptr);
|
||||
|
||||
while (true) {
|
||||
siginfo_t si;
|
||||
int result = sigwaitinfo(&ss, &si);
|
||||
|
||||
if (result <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (si.si_code == SI_TIMER) {
|
||||
auto flag_id = kInvalidFlagId;
|
||||
std::memcpy(&flag_id, &si.si_value.sival_ptr, sizeof(flag_id));
|
||||
MarkDone(flag_id);
|
||||
} else if (si.si_code == SI_TKILL) {
|
||||
pthread_exit(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AsyncTimer::AsyncTimer() : flag_id_{kInvalidFlagId} {};
|
||||
|
||||
AsyncTimer::AsyncTimer(double seconds)
|
||||
: expiration_flag_{std::make_shared<std::atomic<bool>>(false)}, flag_id_{kInvalidFlagId}, timer_id_{} {
|
||||
MG_ASSERT(seconds <= max_seconds_as_double,
|
||||
"The AsyncTimer cannot handle larger time values than {:f}, the specified value: {:f}",
|
||||
max_seconds_as_double, seconds);
|
||||
MG_ASSERT(seconds >= 0.0, "The AsyncTimer cannot handle negative time values: {:f}", seconds);
|
||||
|
||||
static pthread_t background_timer_thread;
|
||||
static ThreadInfo thread_info;
|
||||
static std::once_flag timer_thread_setup_flag;
|
||||
|
||||
std::call_once(timer_thread_setup_flag, [] {
|
||||
pthread_create(&background_timer_thread, nullptr, TimerBackgroundWorker, &thread_info);
|
||||
while (!thread_info.setup_done.load(std::memory_order_acquire))
|
||||
;
|
||||
});
|
||||
|
||||
flag_id_ = AddFlag(std::weak_ptr<std::atomic<bool>>{expiration_flag_});
|
||||
|
||||
sigevent notification_settings{};
|
||||
notification_settings.sigev_notify = SIGEV_THREAD_ID;
|
||||
notification_settings.sigev_signo = SIGTIMER;
|
||||
notification_settings._sigev_un._tid = thread_info.thread_id;
|
||||
static_assert(sizeof(void *) == sizeof(flag_id_), "ID size must be equal to pointer size!");
|
||||
std::memcpy(¬ification_settings.sigev_value.sival_ptr, &flag_id_, sizeof(flag_id_));
|
||||
MG_ASSERT(timer_create(CLOCK_MONOTONIC, ¬ification_settings, &timer_id_) == 0, "Couldn't create timer: ({}) {}",
|
||||
errno, strerror(errno));
|
||||
|
||||
static constexpr auto kSecondsToNanos = 1000 * 1000 * 1000;
|
||||
// Casting will truncate down, but that's exactly what we want.
|
||||
const auto second_as_time_t = static_cast<time_t>(seconds);
|
||||
const auto remaining_nano_seconds = static_cast<time_t>((seconds - second_as_time_t) * kSecondsToNanos);
|
||||
|
||||
struct itimerspec spec;
|
||||
spec.it_interval.tv_sec = 0;
|
||||
spec.it_interval.tv_nsec = 0;
|
||||
spec.it_value.tv_sec = second_as_time_t;
|
||||
spec.it_value.tv_nsec = remaining_nano_seconds;
|
||||
|
||||
MG_ASSERT(timer_settime(timer_id_, 0, &spec, nullptr) == 0, "Couldn't set timer: ({}) {}", errno, strerror(errno));
|
||||
}
|
||||
|
||||
AsyncTimer::~AsyncTimer() { ReleaseResources(); }
|
||||
|
||||
AsyncTimer::AsyncTimer(AsyncTimer &&other) noexcept
|
||||
: expiration_flag_{std::move(other.expiration_flag_)}, flag_id_{other.flag_id_}, timer_id_{other.timer_id_} {
|
||||
other.flag_id_ = kInvalidFlagId;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE (hicpp-noexcept-move)
|
||||
AsyncTimer &AsyncTimer::operator=(AsyncTimer &&other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReleaseResources();
|
||||
|
||||
expiration_flag_ = std::move(other.expiration_flag_);
|
||||
flag_id_ = std::exchange(other.flag_id_, kInvalidFlagId);
|
||||
timer_id_ = other.timer_id_;
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
bool AsyncTimer::IsExpired() const noexcept {
|
||||
if (expiration_flag_ != nullptr) {
|
||||
return expiration_flag_->load(std::memory_order_relaxed);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsyncTimer::ReleaseResources() {
|
||||
if (expiration_flag_ != nullptr) {
|
||||
timer_delete(timer_id_);
|
||||
EraseFlag(flag_id_);
|
||||
flag_id_ = kInvalidFlagId;
|
||||
expiration_flag_ = std::shared_ptr<std::atomic<bool>>{};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace memgraph::utils
|
||||
48
src/utils/timer/linux_async_timer.hpp
Normal file
48
src/utils/timer/linux_async_timer.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::utils::timer {
|
||||
|
||||
#define SIGTIMER (SIGRTMAX - 2)
|
||||
|
||||
class AsyncTimer {
|
||||
public:
|
||||
explicit AsyncTimer(double seconds);
|
||||
AsyncTimer();
|
||||
~AsyncTimer();
|
||||
AsyncTimer(AsyncTimer &&other) noexcept;
|
||||
// NOLINTNEXTLINE (hicpp-noexcept-move)
|
||||
AsyncTimer &operator=(AsyncTimer &&other);
|
||||
AsyncTimer(const AsyncTimer &) = delete;
|
||||
AsyncTimer &operator=(const AsyncTimer &) = delete;
|
||||
|
||||
// Returns false if the object isn't associated with any timer.
|
||||
bool IsExpired() const noexcept;
|
||||
|
||||
private:
|
||||
void ReleaseResources();
|
||||
|
||||
// If the expiration_flag_ is nullptr, then the object is not associated with any timer, therefore no clean up
|
||||
// is necessary. Furthermore, the the POSIX API doesn't specify any value as "invalid" for timer_t, so the timer_id_
|
||||
// cannot be used to determine whether the object is associated with any timer or not.
|
||||
std::shared_ptr<std::atomic<bool>> expiration_flag_;
|
||||
uint64_t flag_id_;
|
||||
timer_t timer_id_;
|
||||
};
|
||||
} // namespace memgraph::utils
|
||||
@@ -254,22 +254,6 @@ class GraphSession {
|
||||
Execute(fmt::format("MATCH ()-[e]->() WHERE e.id > {} AND e.id < {} SET e.value = {}", lo, hi, num));
|
||||
}
|
||||
|
||||
void CheckGraphProjection() {
|
||||
uint64_t vertex_id = *vertices_.rbegin();
|
||||
uint64_t lo = std::floor(GetRandom() * vertex_id);
|
||||
uint64_t hi = std::floor(lo + vertex_id * 0.01);
|
||||
|
||||
Execute(fmt::format(
|
||||
"MATCH p=()-[e]->() WHERE e.id > {} AND e.id < {} WITH project(p) as graph WITH graph.nodes as nodes "
|
||||
"UNWIND nodes as n RETURN n.x "
|
||||
"as x ORDER BY x DESC",
|
||||
lo, hi));
|
||||
Execute(fmt::format(
|
||||
"MATCH p=()-[e]->() WHERE e.id > {} AND e.id < {} WITH project(p) as graph WITH graph.edges as edges "
|
||||
"UNWIND edges as e RETURN e.prop as y ORDER BY y DESC",
|
||||
lo, hi));
|
||||
}
|
||||
|
||||
/** Checks if the local info corresponds to DB state */
|
||||
void VerifyGraph() {
|
||||
// helper lambda for set verification
|
||||
@@ -373,7 +357,6 @@ class GraphSession {
|
||||
} else {
|
||||
CreateVertices(1);
|
||||
}
|
||||
CheckGraphProjection();
|
||||
}
|
||||
|
||||
// final verification
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "query/graph.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "storage/v2/storage.hpp"
|
||||
|
||||
@@ -49,13 +48,8 @@ class AllTypesFixture : public testing::Test {
|
||||
{"e", TypedValue()}});
|
||||
auto vertex = dba.InsertVertex();
|
||||
values_.emplace_back(vertex);
|
||||
auto edge = *dba.InsertEdge(&vertex, &vertex, dba.NameToEdgeType("et"));
|
||||
values_.emplace_back(edge);
|
||||
values_.emplace_back(*dba.InsertEdge(&vertex, &vertex, dba.NameToEdgeType("et")));
|
||||
values_.emplace_back(memgraph::query::Path(dba.InsertVertex()));
|
||||
memgraph::query::Graph graph{memgraph::utils::NewDeleteResource()};
|
||||
graph.InsertVertex(vertex);
|
||||
graph.InsertEdge(edge);
|
||||
values_.emplace_back(std::move(graph));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -539,18 +533,6 @@ TEST_F(AllTypesFixture, PropagationOfMemoryOnConstruction) {
|
||||
EXPECT_EQ(copied.vertices(), original.vertices());
|
||||
EXPECT_EQ(copied.edges(), original.edges());
|
||||
EXPECT_EQ(copied.GetMemoryResource(), &monotonic_memory);
|
||||
} else if (value.type() == TypedValue::Type::Graph) {
|
||||
ASSERT_EQ(move_constructed_value.type(), value.type());
|
||||
const auto &original = value.ValueGraph();
|
||||
const auto &moved = move_constructed_value.ValueGraph();
|
||||
const auto &copied = copy_constructed_value.ValueGraph();
|
||||
EXPECT_EQ(original.GetMemoryResource(), memgraph::utils::NewDeleteResource());
|
||||
EXPECT_EQ(moved.vertices(), original.vertices());
|
||||
EXPECT_EQ(moved.edges(), original.edges());
|
||||
EXPECT_EQ(moved.GetMemoryResource(), &monotonic_memory);
|
||||
EXPECT_EQ(copied.vertices(), original.vertices());
|
||||
EXPECT_EQ(copied.edges(), original.edges());
|
||||
EXPECT_EQ(copied.GetMemoryResource(), &monotonic_memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user