Merge branch 'master' of github.com:yandex/ClickHouse

This commit is contained in:
Alexey Milovidov 2016-09-29 04:28:08 +03:00
commit ac45711219
715 changed files with 24571 additions and 10424 deletions

31
.gitignore vendored
View File

@ -154,6 +154,34 @@ libs/libzkutil/src/tests/zkutil_zookeeper_holder
utils/zookeeper-create-entry-to-download-part/zookeeper-create-entry-to-download-part utils/zookeeper-create-entry-to-download-part/zookeeper-create-entry-to-download-part
utils/zookeeper-dump-tree/zookeeper-dump-tree utils/zookeeper-dump-tree/zookeeper-dump-tree
utils/zookeeper-remove-by-list/zookeeper-remove-by-list utils/zookeeper-remove-by-list/zookeeper-remove-by-list
dbms/src/Storages/tests/remove_symlink_directory
dbms/tests/queries/1_stateful
debian/clickhouse-benchmark-metrika-yandex.postinst
debian/clickhouse-benchmark.docs
debian/clickhouse-client-metrika-yandex.postinst
debian/clickhouse-client.docs
debian/clickhouse-server-base.docs
debian/clickhouse-server-common.docs
debian/clickhouse-server-metrika-yandex.postinst
debian/clickhouse-server-metrika.docs
debian/clickhouse-server.docs
debian/compressor-metrika-yandex.postinst
debian/compressor.docs
debian/config-processor-metrika-yandex.postinst
debian/config-processor.docs
debian/control
debian/copyright
debian/tmp/
libs/libcommon/src/tests/json_test
utils/compressor/zstd_test
utils/wikistat-loader/wikistat-loader
dbms/src/Common/tests/pod_array
debian/clickhouse-benchmark/
debian/clickhouse-client/
debian/clickhouse-server-base/
debian/clickhouse-server-common/
debian/clickhouse-server-metrika/
debian/files
dbms/src/Server/data/* dbms/src/Server/data/*
dbms/src/Server/metadata/* dbms/src/Server/metadata/*
@ -195,3 +223,6 @@ config-preprocessed.xml
# Protobuf # Protobuf
*.pb.cpp *.pb.cpp
*.pb.h *.pb.h
# Ignore symlink to private repository
/private

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "private"]
path = private
url = git@github.yandex-team.ru:Metrika/ClickHouse_private.git

2
.vimrc Normal file
View File

@ -0,0 +1,2 @@
au BufRead,BufNewFile ./* set ts=4 sw=4 noexpandtab tags=tags,../tags

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.6)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# require at least gcc 5 # require at least gcc 5
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5) if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
message(FATAL_ERROR "GCC version must be at least 5! For example, if GCC 5 is available under gcc-5, g++-5 names, do the following: export CC=gcc-5 CXX=g++-5; rm -rf CMakeCache.txt CMakeFiles; and re run cmake.") message(FATAL_ERROR "GCC version must be at least 5! For example, if GCC 5 is available under gcc-5, g++-5 names, do the following: export CC=gcc-5 CXX=g++-5; rm -rf CMakeCache.txt CMakeFiles; and re run cmake or ./release.")
endif() endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# require at least clang 3.8 # require at least clang 3.8
@ -26,7 +26,11 @@ IF(NOT CMAKE_BUILD_TYPE)
ENDIF() ENDIF()
MESSAGE( STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE} ) MESSAGE( STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE} )
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Debug;Release;MinSizeRel" CACHE STRING "" FORCE) # ASan - build type with address sanitizer
# UBSan - build type with undefined behaviour sanitizer
# TSan is not supported due to false positive errors in libstdc++ and necessity to rebuild libstdc++ with TSan
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Debug;Release;MinSizeRel;ASan;UBSan" CACHE STRING "" FORCE)
IF (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") IF (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)")
SET(AARCH64 1) SET(AARCH64 1)
@ -36,22 +40,46 @@ IF (NOT AARCH64)
SET(MACHINE_FLAGS "-msse4 -mpopcnt") SET(MACHINE_FLAGS "-msse4 -mpopcnt")
ENDIF() ENDIF()
SET(COMMON_WARNING_FLAGS "-Wall -Werror")
SET(CXX_WARNING_FLAGS "-Wnon-virtual-dtor -Wold-style-cast")
set (GLIBC_COMPATIBILITY FALSE CACHE BOOL "Set to TRUE to enable compatibility with older glibc libraries")
if ($ENV{GLIBC_COMPATIBILITY})
set (GLIBC_COMPATIBILITY TRUE)
endif()
if (GLIBC_COMPATIBILITY)
SET(GLIBC_COMPATIBILITY_COMPILE_FLAGS "-include ${ClickHouse_SOURCE_DIR}/libs/libcommon/include/common/glibc_compatibility.h")
SET(GLIBC_COMPATIBILITY_LINK_FLAGS "-Wl,--wrap=memcpy")
endif()
if (DISABLE_CXX11_ABI)
SET(CXX11_ABI "-D_GLIBCXX_USE_CXX11_ABI=0")
endif()
SET(CMAKE_BUILD_COLOR_MAKEFILE ON) SET(CMAKE_BUILD_COLOR_MAKEFILE ON)
SET(CMAKE_CXX_FLAGS "-std=gnu++1y -Wall -Werror -Wnon-virtual-dtor ${MACHINE_FLAGS}") SET(CMAKE_CXX_FLAGS "-std=gnu++1y -fno-omit-frame-pointer ${COMMON_WARNING_FLAGS} ${CXX_WARNING_FLAGS} ${MACHINE_FLAGS} ${GLIBC_COMPATIBILITY_COMPILE_FLAGS} ${CXX11_ABI}")
SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g")
SET(CMAKE_C_FLAGS "-Wall -Werror ${MACHINE_FLAGS}") SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -ggdb3 -fno-inline")
SET(CMAKE_C_FLAGS "-fno-omit-frame-pointer ${COMMON_WARNING_FLAGS} ${MACHINE_FLAGS} ${GLIBC_COMPATIBILITY_COMPILE_FLAGS} ${CXX11_ABI}")
SET(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") SET(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g") SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g")
SET(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++") SET(CMAKE_C_FLAGS_DEBUG "-O0 -g3 -ggdb3 -fno-inline")
# cmake -DCMAKE_BUILD_TYPE=Debug .. SET(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ ${GLIBC_COMPATIBILITY_LINK_FLAGS} ${CXX11_ABI}")
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
SET(CMAKE_CXX_FLAGS_ASAN "-O3 -g -fsanitize=address -fno-omit-frame-pointer ${CXX11_ABI}")
SET(CMAKE_CXX_FLAGS_UBSAN "-O3 -g -fsanitize=undefined -fno-omit-frame-pointer ${CXX11_ABI}")
SET(CMAKE_C_FLAGS_ASAN "-O3 -g -fsanitize=address -fno-omit-frame-pointer ${CXX11_ABI}")
SET(CMAKE_C_FLAGS_UBSAN "-O3 -g -fsanitize=undefined -fno-omit-frame-pointer ${CXX11_ABI}")
# Флаги для test coverage # Флаги для test coverage
SET(TEST_COVERAGE TRUE CACHE BOOL "Add compliler flags for test coverage")
IF (TEST_COVERAGE) IF (TEST_COVERAGE)
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -fprofile-arcs -ftest-coverage -fPIC -DIS_DEBUG") SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -fprofile-arcs -ftest-coverage -fPIC -DIS_DEBUG ${CXX11_ABI}")
ENDIF(TEST_COVERAGE) ENDIF(TEST_COVERAGE)
# Собирать тесты? # Собирать тесты?
@ -68,9 +96,6 @@ ENDIF(TESTS)
# Префикс для установки # Префикс для установки
SET(CMAKE_INSTALL_PREFIX /usr) SET(CMAKE_INSTALL_PREFIX /usr)
# Директория для файлов, специфичных для Яндекса
SET(CLICKHOUSE_PRIVATE_DIR ${ClickHouse_SOURCE_DIR}/private/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libcityhash/include/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libcityhash/include/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/liblz4/include/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/liblz4/include/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libdivide/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libdivide/)
@ -82,7 +107,7 @@ include_directories (${ClickHouse_SOURCE_DIR}/contrib/libmetrohash/src)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libsparsehash/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libsparsehash/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libre2/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libre2/)
include_directories (${ClickHouse_BINARY_DIR}/contrib/libre2/) include_directories (${ClickHouse_BINARY_DIR}/contrib/libre2/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libboost-threadpool/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libzookeeper/include/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libpoco/Foundation/include/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libpoco/Foundation/include/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libpoco/Util/include/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libpoco/Util/include/)
include_directories (${ClickHouse_SOURCE_DIR}/contrib/libpoco/Net/include/) include_directories (${ClickHouse_SOURCE_DIR}/contrib/libpoco/Net/include/)
@ -120,8 +145,17 @@ include_directories (/usr/local/include/)
link_directories (/usr/local/lib) link_directories (/usr/local/lib)
# Directory for Yandex specific files
SET(CLICKHOUSE_PRIVATE_DIR ${ClickHouse_SOURCE_DIR}/private/)
add_subdirectory (contrib) add_subdirectory (contrib)
add_subdirectory (libs) add_subdirectory (libs)
add_subdirectory (utils) add_subdirectory (utils)
add_subdirectory (dbms) add_subdirectory (dbms)
IF (EXISTS ${CLICKHOUSE_PRIVATE_DIR})
add_subdirectory (private) add_subdirectory (private)
ENDIF()
message(STATUS "C_FLAGS: =${CMAKE_C_FLAGS}")
message(STATUS "CXX_FLAGS:=${CMAKE_CXX_FLAGS}")

View File

@ -1,3 +1,5 @@
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-old-style-cast")
add_subdirectory (libcityhash) add_subdirectory (libcityhash)
add_subdirectory (liblz4) add_subdirectory (liblz4)
add_subdirectory (libdouble-conversion) add_subdirectory (libdouble-conversion)
@ -6,8 +8,8 @@ add_subdirectory (libfarmhash)
add_subdirectory (libmetrohash) add_subdirectory (libmetrohash)
add_subdirectory (libpoco) add_subdirectory (libpoco)
add_subdirectory (libre2) add_subdirectory (libre2)
add_subdirectory (libboost-threadpool)
add_subdirectory (libtcmalloc) add_subdirectory (libtcmalloc)
add_subdirectory (libzookeeper)
IF (NOT AARCH64) IF (NOT AARCH64)
add_subdirectory (libcpuid) add_subdirectory (libcpuid)

View File

@ -1,5 +0,0 @@
Copyright (c) 2005-2007 Philipp Henkel
Use, modification, and distribution are subject to the
Boost Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,23 +0,0 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,28 +0,0 @@
/*! \file
* \brief Main include.
*
* This is the only file you have to include in order to use the
* complete threadpool library.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_HPP_INCLUDED
#define THREADPOOL_HPP_INCLUDED
#include "threadpool/future.hpp"
#include "threadpool/pool.hpp"
#include "threadpool/pool_adaptors.hpp"
#include "threadpool/task_adaptors.hpp"
#endif // THREADPOOL_HPP_INCLUDED

View File

@ -1,215 +0,0 @@
/*! \file
* \brief TODO.
*
* TODO.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_DETAIL_FUTURE_IMPL_HPP_INCLUDED
#define THREADPOOL_DETAIL_FUTURE_IMPL_HPP_INCLUDED
#include "locking_ptr.hpp"
#include <boost/smart_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
namespace boost { namespace threadpool { namespace detail
{
template<class Result>
class future_impl
{
public:
typedef Result const & result_type; //!< Indicates the functor's result type.
typedef Result future_result_type; //!< Indicates the future's result type.
typedef future_impl<future_result_type> future_type;
private:
volatile bool m_ready;
volatile future_result_type m_result;
mutable mutex m_monitor;
mutable condition m_condition_ready;
volatile bool m_is_cancelled;
volatile bool m_executing;
public:
public:
future_impl()
: m_ready(false)
, m_is_cancelled(false)
{
}
bool ready() const volatile
{
return m_ready;
}
void wait() const volatile
{
const future_type* self = const_cast<const future_type*>(this);
mutex::scoped_lock lock(self->m_monitor);
while(!m_ready)
{
self->m_condition_ready.wait(lock);
}
}
bool timed_wait(boost::xtime const & timestamp) const
{
const future_type* self = const_cast<const future_type*>(this);
mutex::scoped_lock lock(self->m_monitor);
while(!m_ready)
{
if(!self->m_condition_ready.timed_wait(lock, timestamp)) return false;
}
return true;
}
result_type operator()() const volatile
{
wait();
/*
if( throw_exception_ != 0 )
{
throw_exception_( this );
}
*/
return *(const_cast<const future_result_type*>(&m_result));
}
void set_value(future_result_type const & r) volatile
{
locking_ptr<future_type, mutex> lockedThis(*this, m_monitor);
if(!m_ready && !m_is_cancelled)
{
lockedThis->m_result = r;
lockedThis->m_ready = true;
lockedThis->m_condition_ready.notify_all();
}
}
/*
template<class E> void set_exception() // throw()
{
m_impl->template set_exception<E>();
}
template<class E> void set_exception( char const * what ) // throw()
{
m_impl->template set_exception<E>( what );
}
*/
bool cancel() volatile
{
if(!m_ready || m_executing)
{
m_is_cancelled = true;
return true;
}
else
{
return false;
}
}
bool is_cancelled() const volatile
{
return m_is_cancelled;
}
void set_execution_status(bool executing) volatile
{
m_executing = executing;
}
};
template<
template <typename> class Future,
typename Function
>
class future_impl_task_func
{
public:
typedef void result_type; //!< Indicates the functor's result type.
typedef Function function_type; //!< Indicates the function's type.
typedef typename result_of<function_type()>::type future_result_type; //!< Indicates the future's result type.
typedef Future<future_result_type> future_type; //!< Indicates the future's type.
// The task is required to be a nullary function.
BOOST_STATIC_ASSERT(function_traits<function_type()>::arity == 0);
// The task function's result type is required not to be void.
BOOST_STATIC_ASSERT(!is_void<future_result_type>::value);
private:
function_type m_function;
shared_ptr<future_type> m_future;
public:
future_impl_task_func(function_type const & function, shared_ptr<future_type> const & future)
: m_function(function)
, m_future(future)
{
}
void operator()()
{
if(m_function)
{
m_future->set_execution_status(true);
if(!m_future->is_cancelled())
{
// TODO future exeception handling
m_future->set_value(m_function());
}
m_future->set_execution_status(false); // TODO consider exceptions
}
}
};
} } } // namespace boost::threadpool::detail
#endif // THREADPOOL_DETAIL_FUTURE_IMPL_HPP_INCLUDED

View File

@ -1,102 +0,0 @@
/*! \file
* \brief The locking_ptr is smart pointer with a scoped locking mechanism.
*
* The class is a wrapper for a volatile pointer. It enables synchronized access to the
* internal pointer by locking the passed mutex.
* locking_ptr is based on Andrei Alexandrescu's LockingPtr. For more information
* see article "volatile - Multithreaded Programmer's Best Friend" by A. Alexandrescu.
*
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_DETAIL_LOCKING_PTR_HPP_INCLUDED
#define THREADPOOL_DETAIL_LOCKING_PTR_HPP_INCLUDED
#include <boost/utility.hpp>
// Support for old boost::thread
//**********************************************
#include <boost/thread/mutex.hpp>
#ifndef BOOST_THREAD_MUTEX_HPP
#include <boost/thread/detail/lock.hpp>
#endif
//**********************************************
namespace boost { namespace threadpool { namespace detail
{
/*! \brief Smart pointer with a scoped locking mechanism.
*
* This class is a wrapper for a volatile pointer. It enables synchronized access to the
* internal pointer by locking the passed mutex.
*/
template <typename T, typename Mutex>
class locking_ptr
: private noncopyable
{
T* m_obj; //!< The instance pointer.
Mutex & m_mutex; //!< Mutex is used for scoped locking.
public:
/// Constructor.
locking_ptr(volatile T& obj, const volatile Mutex& mtx)
: m_obj(const_cast<T*>(&obj))
, m_mutex(*const_cast<Mutex*>(&mtx))
{
// Lock mutex
#ifndef BOOST_THREAD_MUTEX_HPP
// Support for old boost::thread
boost::detail::thread::lock_ops<Mutex>::lock(m_mutex);
#else
m_mutex.lock();
#endif
}
/// Destructor.
~locking_ptr()
{
// Unlock mutex
#ifndef BOOST_THREAD_MUTEX_HPP
// Support for old boost::thread
boost::detail::thread::lock_ops<Mutex>::unlock(m_mutex);
#else
m_mutex.unlock();
#endif
}
/*! Returns a reference to the stored instance.
* \return The instance's reference.
*/
T& operator*() const
{
return *m_obj;
}
/*! Returns a pointer to the stored instance.
* \return The instance's pointer.
*/
T* operator->() const
{
return m_obj;
}
};
} } } // namespace boost::threadpool::detail
#endif // THREADPOOL_DETAIL_LOCKING_PTR_HPP_INCLUDED

View File

@ -1,453 +0,0 @@
/*! \file
* \brief Thread pool core.
*
* This file contains the threadpool's core class: pool<Task, SchedulingPolicy>.
*
* Thread pools are a mechanism for asynchronous and parallel processing
* within the same process. The pool class provides a convenient way
* for dispatching asynchronous tasks as functions objects. The scheduling
* of these tasks can be easily controlled by using customized schedulers.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_POOL_CORE_HPP_INCLUDED
#define THREADPOOL_POOL_CORE_HPP_INCLUDED
#include "locking_ptr.hpp"
#include "worker_thread.hpp"
#include "../task_adaptors.hpp"
#include <boost/thread.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <vector>
/// The namespace threadpool contains a thread pool and related utility classes.
namespace boost { namespace threadpool { namespace detail
{
/*! \brief Thread pool.
*
* Thread pools are a mechanism for asynchronous and parallel processing
* within the same process. The pool class provides a convenient way
* for dispatching asynchronous tasks as functions objects. The scheduling
* of these tasks can be easily controlled by using customized schedulers.
* A task must not throw an exception.
*
* A pool_impl is DefaultConstructible and NonCopyable.
*
* \param Task A function object which implements the operator 'void operator() (void) const'. The operator () is called by the pool to execute the task. Exceptions are ignored.
* \param Scheduler A task container which determines how tasks are scheduled. It is guaranteed that this container is accessed only by one thread at a time. The scheduler shall not throw exceptions.
*
* \remarks The pool class is thread-safe.
*
* \see Tasks: task_func, prio_task_func
* \see Scheduling policies: fifo_scheduler, lifo_scheduler, prio_scheduler
*/
template <
typename Task,
template <typename> class SchedulingPolicy,
template <typename> class SizePolicy,
template <typename> class SizePolicyController,
template <typename> class ShutdownPolicy
>
class pool_core
: public enable_shared_from_this< pool_core<Task, SchedulingPolicy, SizePolicy, SizePolicyController, ShutdownPolicy > >
, private noncopyable
{
public: // Type definitions
typedef Task task_type; //!< Indicates the task's type.
typedef SchedulingPolicy<task_type> scheduler_type; //!< Indicates the scheduler's type.
typedef pool_core<Task,
SchedulingPolicy,
SizePolicy,
SizePolicyController,
ShutdownPolicy > pool_type; //!< Indicates the thread pool's type.
typedef SizePolicy<pool_type> size_policy_type; //!< Indicates the sizer's type.
//typedef typename size_policy_type::size_controller size_controller_type;
typedef SizePolicyController<pool_type> size_controller_type;
// typedef SizePolicy<pool_type>::size_controller size_controller_type;
typedef ShutdownPolicy<pool_type> shutdown_policy_type;//!< Indicates the shutdown policy's type.
typedef worker_thread<pool_type> worker_type;
// The task is required to be a nullary function.
BOOST_STATIC_ASSERT(function_traits<task_type()>::arity == 0);
// The task function's result type is required to be void.
BOOST_STATIC_ASSERT(is_void<typename result_of<task_type()>::type >::value);
private: // Friends
friend class worker_thread<pool_type>;
#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x580) // Tested with CC: Sun C++ 5.8 Patch 121018-08 2006/12/06
friend class SizePolicy;
friend class ShutdownPolicy;
#else
friend class SizePolicy<pool_type>;
friend class ShutdownPolicy<pool_type>;
#endif
private: // The following members may be accessed by _multiple_ threads at the same time:
volatile size_t m_worker_count;
volatile size_t m_target_worker_count;
volatile size_t m_active_worker_count;
private: // The following members are accessed only by _one_ thread at the same time:
scheduler_type m_scheduler;
scoped_ptr<size_policy_type> m_size_policy; // is never null
bool m_terminate_all_workers; // Indicates if termination of all workers was triggered.
std::vector<shared_ptr<worker_type> > m_terminated_workers; // List of workers which are terminated but not fully destructed.
private: // The following members are implemented thread-safe:
mutable recursive_mutex m_monitor;
mutable condition m_worker_idle_or_terminated_event; // A worker is idle or was terminated.
mutable condition m_task_or_terminate_workers_event; // Task is available OR total worker count should be reduced.
public:
/// Constructor.
pool_core()
: m_worker_count(0)
, m_target_worker_count(0)
, m_active_worker_count(0)
, m_terminate_all_workers(false)
{
pool_type volatile & self_ref = *this;
m_size_policy.reset(new size_policy_type(self_ref));
m_scheduler.clear();
}
/// Destructor.
~pool_core()
{
}
/*! Gets the size controller which manages the number of threads in the pool.
* \return The size controller.
* \see SizePolicy
*/
size_controller_type size_controller()
{
return size_controller_type(*m_size_policy, this->shared_from_this());
}
/*! Gets the number of threads in the pool.
* \return The number of threads.
*/
size_t size() const volatile
{
return m_worker_count;
}
// TODO is only called once
void shutdown()
{
ShutdownPolicy<pool_type>::shutdown(*this);
}
/*! Schedules a task for asynchronous execution. The task will be executed once only.
* \param task The task function object. It should not throw execeptions.
* \return true, if the task could be scheduled and false otherwise.
*/
bool schedule(task_type const & task) volatile
{
locking_ptr<pool_type, recursive_mutex> lockedThis(*this, m_monitor);
if(lockedThis->m_scheduler.push(task))
{
lockedThis->m_task_or_terminate_workers_event.notify_one();
return true;
}
else
{
return false;
}
}
/*! Returns the number of tasks which are currently executed.
* \return The number of active tasks.
*/
size_t active() const volatile
{
return m_active_worker_count;
}
/*! Returns the number of tasks which are ready for execution.
* \return The number of pending tasks.
*/
size_t pending() const volatile
{
locking_ptr<const pool_type, recursive_mutex> lockedThis(*this, m_monitor);
return lockedThis->m_scheduler.size();
}
/*! Removes all pending tasks from the pool's scheduler.
*/
void clear() volatile
{
locking_ptr<pool_type, recursive_mutex> lockedThis(*this, m_monitor);
lockedThis->m_scheduler.clear();
}
/*! Indicates that there are no tasks pending.
* \return true if there are no tasks ready for execution.
* \remarks This function is more efficient that the check 'pending() == 0'.
*/
bool empty() const volatile
{
locking_ptr<const pool_type, recursive_mutex> lockedThis(*this, m_monitor);
return lockedThis->m_scheduler.empty();
}
/*! The current thread of execution is blocked until the sum of all active
* and pending tasks is equal or less than a given threshold.
* \param task_threshold The maximum number of tasks in pool and scheduler.
*/
void wait(size_t const task_threshold = 0) const volatile
{
const pool_type* self = const_cast<const pool_type*>(this);
recursive_mutex::scoped_lock lock(self->m_monitor);
if(0 == task_threshold)
{
while(0 != self->m_active_worker_count || !self->m_scheduler.empty())
{
self->m_worker_idle_or_terminated_event.wait(lock);
}
}
else
{
while(task_threshold < self->m_active_worker_count + self->m_scheduler.size())
{
self->m_worker_idle_or_terminated_event.wait(lock);
}
}
}
/*! The current thread of execution is blocked until the timestamp is met
* or the sum of all active and pending tasks is equal or less
* than a given threshold.
* \param timestamp The time when function returns at the latest.
* \param task_threshold The maximum number of tasks in pool and scheduler.
* \return true if the task sum is equal or less than the threshold, false otherwise.
*/
bool wait(xtime const & timestamp, size_t const task_threshold = 0) const volatile
{
const pool_type* self = const_cast<const pool_type*>(this);
recursive_mutex::scoped_lock lock(self->m_monitor);
if(0 == task_threshold)
{
while(0 != self->m_active_worker_count || !self->m_scheduler.empty())
{
if(!self->m_worker_idle_or_terminated_event.timed_wait(lock, timestamp)) return false;
}
}
else
{
while(task_threshold < self->m_active_worker_count + self->m_scheduler.size())
{
if(!self->m_worker_idle_or_terminated_event.timed_wait(lock, timestamp)) return false;
}
}
return true;
}
private:
void terminate_all_workers(bool const wait) volatile
{
pool_type* self = const_cast<pool_type*>(this);
recursive_mutex::scoped_lock lock(self->m_monitor);
self->m_terminate_all_workers = true;
m_target_worker_count = 0;
self->m_task_or_terminate_workers_event.notify_all();
if(wait)
{
while(m_worker_count > 0)
{
self->m_worker_idle_or_terminated_event.wait(lock);
}
for(typename std::vector<shared_ptr<worker_type> >::iterator it = self->m_terminated_workers.begin();
it != self->m_terminated_workers.end();
++it)
{
(*it)->join();
}
self->m_terminated_workers.clear();
}
}
/*! Changes the number of worker threads in the pool. The resizing
* is handled by the SizePolicy.
* \param threads The new number of worker threads.
* \return true, if pool will be resized and false if not.
*/
bool resize(size_t const worker_count) volatile
{
locking_ptr<pool_type, recursive_mutex> lockedThis(*this, m_monitor);
if(!m_terminate_all_workers)
{
m_target_worker_count = worker_count;
}
else
{
return false;
}
if(m_worker_count <= m_target_worker_count)
{ // increase worker count
while(m_worker_count < m_target_worker_count)
{
try
{
worker_thread<pool_type>::create_and_attach(lockedThis->shared_from_this());
m_worker_count++;
m_active_worker_count++;
}
catch(thread_resource_error)
{
return false;
}
}
}
else
{ // decrease worker count
lockedThis->m_task_or_terminate_workers_event.notify_all(); // TODO: Optimize number of notified workers
}
return true;
}
// worker died with unhandled exception
void worker_died_unexpectedly(shared_ptr<worker_type> worker) volatile
{
locking_ptr<pool_type, recursive_mutex> lockedThis(*this, m_monitor);
m_worker_count--;
m_active_worker_count--;
lockedThis->m_worker_idle_or_terminated_event.notify_all();
if(m_terminate_all_workers)
{
lockedThis->m_terminated_workers.push_back(worker);
}
else
{
lockedThis->m_size_policy->worker_died_unexpectedly(m_worker_count);
}
}
void worker_destructed(shared_ptr<worker_type> worker) volatile
{
locking_ptr<pool_type, recursive_mutex> lockedThis(*this, m_monitor);
m_worker_count--;
m_active_worker_count--;
lockedThis->m_worker_idle_or_terminated_event.notify_all();
if(m_terminate_all_workers)
{
lockedThis->m_terminated_workers.push_back(worker);
}
}
bool execute_task() volatile
{
function0<void> task;
{ // fetch task
pool_type* lockedThis = const_cast<pool_type*>(this);
recursive_mutex::scoped_lock lock(lockedThis->m_monitor);
// decrease number of threads if necessary
if(m_worker_count > m_target_worker_count)
{
return false; // terminate worker
}
// wait for tasks
while(lockedThis->m_scheduler.empty())
{
// decrease number of workers if necessary
if(m_worker_count > m_target_worker_count)
{
return false; // terminate worker
}
else
{
m_active_worker_count--;
lockedThis->m_worker_idle_or_terminated_event.notify_all();
lockedThis->m_task_or_terminate_workers_event.wait(lock);
m_active_worker_count++;
}
}
task = lockedThis->m_scheduler.top();
lockedThis->m_scheduler.pop();
}
// call task function
if(task)
{
task();
}
//guard->disable();
return true;
}
};
} } } // namespace boost::threadpool::detail
#endif // THREADPOOL_POOL_CORE_HPP_INCLUDED

View File

@ -1,65 +0,0 @@
/*! \file
* \brief TODO.
*
* TODO.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_DETAIL_SCOPE_GUARD_HPP_INCLUDED
#define THREADPOOL_DETAIL_SCOPE_GUARD_HPP_INCLUDED
#include <boost/function.hpp>
namespace boost { namespace threadpool { namespace detail
{
// TODO documentation
class scope_guard
: private boost::noncopyable
{
function0<void> const m_function;
bool m_is_active;
public:
scope_guard(function0<void> const & call_on_exit)
: m_function(call_on_exit)
, m_is_active(true)
{
}
~scope_guard()
{
if(m_is_active && m_function)
{
m_function();
}
}
void disable()
{
m_is_active = false;
}
};
} } } // namespace boost::threadpool::detail
#endif // THREADPOOL_DETAIL_SCOPE_GUARD_HPP_INCLUDED

View File

@ -1,115 +0,0 @@
/*! \file
* \brief Thread pool worker.
*
* The worker thread instance is attached to a pool
* and executes tasks of this pool.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_DETAIL_WORKER_THREAD_HPP_INCLUDED
#define THREADPOOL_DETAIL_WORKER_THREAD_HPP_INCLUDED
#include "scope_guard.hpp"
#include <boost/smart_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
namespace boost { namespace threadpool { namespace detail
{
/*! \brief Thread pool worker.
*
* A worker_thread represents a thread of execution. The worker is attached to a
* thread pool and processes tasks of that pool. The lifetime of the worker and its
* internal boost::thread is managed automatically.
*
* This class is a helper class and cannot be constructed or accessed directly.
*
* \see pool_core
*/
template <typename Pool>
class worker_thread
: public enable_shared_from_this< worker_thread<Pool> >
, private noncopyable
{
public:
typedef Pool pool_type; //!< Indicates the pool's type.
private:
shared_ptr<pool_type> m_pool; //!< Pointer to the pool which created the worker.
shared_ptr<boost::thread> m_thread; //!< Pointer to the thread which executes the run loop.
/*! Constructs a new worker.
* \param pool Pointer to it's parent pool.
* \see function create_and_attach
*/
worker_thread(shared_ptr<pool_type> const & pool)
: m_pool(pool)
{
assert(pool);
}
/*! Notifies that an exception occurred in the run loop.
*/
void died_unexpectedly()
{
m_pool->worker_died_unexpectedly(this->shared_from_this());
}
public:
/*! Executes pool's tasks sequentially.
*/
void run()
{
scope_guard notify_exception(bind(&worker_thread::died_unexpectedly, this));
while(m_pool->execute_task()) {}
notify_exception.disable();
m_pool->worker_destructed(this->shared_from_this());
}
/*! Joins the worker's thread.
*/
void join()
{
m_thread->join();
}
/*! Constructs a new worker thread and attaches it to the pool.
* \param pool Pointer to the pool.
*/
static void create_and_attach(shared_ptr<pool_type> const & pool)
{
shared_ptr<worker_thread> worker(new worker_thread(pool));
if(worker)
{
worker->m_thread.reset(new boost::thread(bind(&worker_thread::run, worker)));
}
}
};
} } } // namespace boost::threadpool::detail
#endif // THREADPOOL_DETAIL_WORKER_THREAD_HPP_INCLUDED

View File

@ -1,144 +0,0 @@
/*! \file
* \brief TODO.
*
* TODO.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_FUTURE_HPP_INCLUDED
#define THREADPOOL_FUTURE_HPP_INCLUDED
#include "detail/future.hpp"
#include <boost/utility/enable_if.hpp>
//#include "pool.hpp"
//#include <boost/utility.hpp>
//#include <boost/thread/mutex.hpp>
namespace boost { namespace threadpool
{
/*! \brief Experimental. Do not use in production code. TODO.
*
* TODO Future
*
* \see TODO
*
*/
template<class Result>
class future
{
private:
shared_ptr<detail::future_impl<Result> > m_impl;
public:
typedef Result const & result_type; //!< Indicates the functor's result type.
typedef Result future_result_type; //!< Indicates the future's result type.
public:
future()
: m_impl(new detail::future_impl<future_result_type>()) // TODO remove this
{
}
// only for internal usage
future(shared_ptr<detail::future_impl<Result> > const & impl)
: m_impl(impl)
{
}
bool ready() const
{
return m_impl->ready();
}
void wait() const
{
m_impl->wait();
}
bool timed_wait(boost::xtime const & timestamp) const
{
return m_impl->timed_wait(timestamp);
}
result_type operator()() // throw( thread::cancelation_exception, ... )
{
return (*m_impl)();
}
result_type get() // throw( thread::cancelation_exception, ... )
{
return (*m_impl)();
}
bool cancel()
{
return m_impl->cancel();
}
bool is_cancelled() const
{
return m_impl->is_cancelled();
}
};
template<class Pool, class Function>
typename disable_if <
is_void< typename result_of< Function() >::type >,
future< typename result_of< Function() >::type >
>::type
schedule(Pool& pool, const Function& task)
{
typedef typename result_of< Function() >::type future_result_type;
// create future impl and future
shared_ptr<detail::future_impl<future_result_type> > impl(new detail::future_impl<future_result_type>);
future <future_result_type> res(impl);
// schedule future impl
pool.schedule(detail::future_impl_task_func<detail::future_impl, Function>(task, impl));
// return future
return res;
/*
TODO
if(pool->schedule(bind(&Future::run, future)))
{
return future;
}
else
{
// construct empty future
return error_future;
}
*/
}
} } // namespace boost::threadpool
#endif // THREADPOOL_FUTURE_HPP_INCLUDED

View File

@ -1,232 +0,0 @@
/*! \file
* \brief Thread pool core.
*
* This file contains the threadpool's core class: pool<Task, SchedulingPolicy>.
*
* Thread pools are a mechanism for asynchronous and parallel processing
* within the same process. The pool class provides a convenient way
* for dispatching asynchronous tasks as functions objects. The scheduling
* of these tasks can be easily controlled by using customized schedulers.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_POOL_HPP_INCLUDED
#define THREADPOOL_POOL_HPP_INCLUDED
#include <boost/ref.hpp>
#include "detail/pool_core.hpp"
#include "task_adaptors.hpp"
#include "detail/locking_ptr.hpp"
#include "scheduling_policies.hpp"
#include "size_policies.hpp"
#include "shutdown_policies.hpp"
/// The namespace threadpool contains a thread pool and related utility classes.
namespace boost { namespace threadpool
{
/*! \brief Thread pool.
*
* Thread pools are a mechanism for asynchronous and parallel processing
* within the same process. The pool class provides a convenient way
* for dispatching asynchronous tasks as functions objects. The scheduling
* of these tasks can be easily controlled by using customized schedulers.
* A task must not throw an exception.
*
* A pool is DefaultConstructible, CopyConstructible and Assignable.
* It has reference semantics; all copies of the same pool are equivalent and interchangeable.
* All operations on a pool except assignment are strongly thread safe or sequentially consistent;
* that is, the behavior of concurrent calls is as if the calls have been issued sequentially in an unspecified order.
*
* \param Task A function object which implements the operator 'void operator() (void) const'. The operator () is called by the pool to execute the task. Exceptions are ignored.
* \param SchedulingPolicy A task container which determines how tasks are scheduled. It is guaranteed that this container is accessed only by one thread at a time. The scheduler shall not throw exceptions.
*
* \remarks The pool class is thread-safe.
*
* \see Tasks: task_func, prio_task_func
* \see Scheduling policies: fifo_scheduler, lifo_scheduler, prio_scheduler
*/
template <
typename Task = task_func,
template <typename> class SchedulingPolicy = fifo_scheduler,
template <typename> class SizePolicy = static_size,
template <typename> class SizePolicyController = resize_controller,
template <typename> class ShutdownPolicy = wait_for_all_tasks
>
class thread_pool
{
typedef detail::pool_core<Task,
SchedulingPolicy,
SizePolicy,
SizePolicyController,
ShutdownPolicy> pool_core_type;
shared_ptr<pool_core_type> m_core; // pimpl idiom
shared_ptr<void> m_shutdown_controller; // If the last pool holding a pointer to the core is deleted the controller shuts the pool down.
public: // Type definitions
typedef Task task_type; //!< Indicates the task's type.
typedef SchedulingPolicy<task_type> scheduler_type; //!< Indicates the scheduler's type.
/* typedef thread_pool<Task,
SchedulingPolicy,
SizePolicy,
ShutdownPolicy > pool_type; //!< Indicates the thread pool's type.
*/
typedef SizePolicy<pool_core_type> size_policy_type;
typedef SizePolicyController<pool_core_type> size_controller_type;
public:
/*! Constructor.
* \param initial_threads The pool is immediately resized to set the specified number of threads. The pool's actual number threads depends on the SizePolicy.
*/
thread_pool(size_t initial_threads = 0)
: m_core(new pool_core_type)
, m_shutdown_controller(static_cast<void*>(0), bind(&pool_core_type::shutdown, m_core))
{
size_policy_type::init(*m_core, initial_threads);
}
/*! Gets the size controller which manages the number of threads in the pool.
* \return The size controller.
* \see SizePolicy
*/
size_controller_type size_controller()
{
return m_core->size_controller();
}
/*! Gets the number of threads in the pool.
* \return The number of threads.
*/
size_t size() const
{
return m_core->size();
}
/*! Schedules a task for asynchronous execution. The task will be executed once only.
* \param task The task function object. It should not throw execeptions.
* \return true, if the task could be scheduled and false otherwise.
*/
bool schedule(task_type const & task)
{
return m_core->schedule(task);
}
/*! Returns the number of tasks which are currently executed.
* \return The number of active tasks.
*/
size_t active() const
{
return m_core->active();
}
/*! Returns the number of tasks which are ready for execution.
* \return The number of pending tasks.
*/
size_t pending() const
{
return m_core->pending();
}
/*! Removes all pending tasks from the pool's scheduler.
*/
void clear()
{
m_core->clear();
}
/*! Indicates that there are no tasks pending.
* \return true if there are no tasks ready for execution.
* \remarks This function is more efficient that the check 'pending() == 0'.
*/
bool empty() const
{
return m_core->empty();
}
/*! The current thread of execution is blocked until the sum of all active
* and pending tasks is equal or less than a given threshold.
* \param task_threshold The maximum number of tasks in pool and scheduler.
*/
void wait(size_t task_threshold = 0) const
{
m_core->wait(task_threshold);
}
/*! The current thread of execution is blocked until the timestamp is met
* or the sum of all active and pending tasks is equal or less
* than a given threshold.
* \param timestamp The time when function returns at the latest.
* \param task_threshold The maximum number of tasks in pool and scheduler.
* \return true if the task sum is equal or less than the threshold, false otherwise.
*/
bool wait(xtime const & timestamp, size_t task_threshold = 0) const
{
return m_core->wait(timestamp, task_threshold);
}
};
/*! \brief Fifo pool.
*
* The pool's tasks are fifo scheduled task_func functors.
*
*/
typedef thread_pool<task_func, fifo_scheduler, static_size, resize_controller, wait_for_all_tasks> fifo_pool;
/*! \brief Lifo pool.
*
* The pool's tasks are lifo scheduled task_func functors.
*
*/
typedef thread_pool<task_func, lifo_scheduler, static_size, resize_controller, wait_for_all_tasks> lifo_pool;
/*! \brief Pool for prioritized task.
*
* The pool's tasks are prioritized prio_task_func functors.
*
*/
typedef thread_pool<prio_task_func, prio_scheduler, static_size, resize_controller, wait_for_all_tasks> prio_pool;
/*! \brief A standard pool.
*
* The pool's tasks are fifo scheduled task_func functors.
*
*/
typedef fifo_pool pool;
} } // namespace boost::threadpool
#endif // THREADPOOL_POOL_HPP_INCLUDED

View File

@ -1,70 +0,0 @@
/*! \file
* \brief Pool adaptors.
*
* This file contains an easy-to-use adaptor similar to a smart
* pointer for the pool class.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_POOL_ADAPTORS_HPP_INCLUDED
#define THREADPOOL_POOL_ADAPTORS_HPP_INCLUDED
#include <boost/smart_ptr.hpp>
namespace boost { namespace threadpool
{
// TODO convenience scheduling function
/*! Schedules a Runnable for asynchronous execution. A Runnable is an arbitrary class with a run()
* member function. This a convenience shorthand for pool->schedule(bind(&Runnable::run, task_object)).
* \param
* \param obj The Runnable object. The member function run() will be exectued and should not throw execeptions.
* \return true, if the task could be scheduled and false otherwise.
*/
template<typename Pool, typename Runnable>
bool schedule(Pool& pool, shared_ptr<Runnable> const & obj)
{
return pool->schedule(bind(&Runnable::run, obj));
}
/*! Schedules a task for asynchronous execution. The task will be executed once only.
* \param task The task function object.
*/
template<typename Pool>
typename enable_if <
is_void< typename result_of< typename Pool::task_type() >::type >,
bool
>::type
schedule(Pool& pool, typename Pool::task_type const & task)
{
return pool.schedule(task);
}
template<typename Pool>
typename enable_if <
is_void< typename result_of< typename Pool::task_type() >::type >,
bool
>::type
schedule(shared_ptr<Pool> const pool, typename Pool::task_type const & task)
{
return pool->schedule(task);
}
} } // namespace boost::threadpool
#endif // THREADPOOL_POOL_ADAPTORS_HPP_INCLUDED

View File

@ -1,262 +0,0 @@
/*! \file
* \brief Task scheduling policies.
*
* This file contains some fundamental scheduling policies for the pool class.
* A scheduling policy is realized by a task container which controls the access to
* the tasks. Fundamentally the container determines the order the tasks are processed
* by the thread pool.
* The task containers need not to be thread-safe because they are used by the pool
* in thread-safe way.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_SCHEDULING_POLICIES_HPP_INCLUDED
#define THREADPOOL_SCHEDULING_POLICIES_HPP_INCLUDED
#include <queue>
#include <deque>
#include "task_adaptors.hpp"
namespace boost { namespace threadpool
{
/*! \brief SchedulingPolicy which implements FIFO ordering.
*
* This container implements a FIFO scheduling policy.
* The first task to be added to the scheduler will be the first to be removed.
* The processing proceeds sequentially in the same order.
* FIFO stands for "first in, first out".
*
* \param Task A function object which implements the operator()(void).
*
*/
template <typename Task = task_func>
class fifo_scheduler
{
public:
typedef Task task_type; //!< Indicates the scheduler's task type.
protected:
std::deque<task_type> m_container; //!< Internal task container.
public:
/*! Adds a new task to the scheduler.
* \param task The task object.
* \return true, if the task could be scheduled and false otherwise.
*/
bool push(task_type const & task)
{
m_container.push_back(task);
return true;
}
/*! Removes the task which should be executed next.
*/
void pop()
{
m_container.pop_front();
}
/*! Gets the task which should be executed next.
* \return The task object to be executed.
*/
task_type const & top() const
{
return m_container.front();
}
/*! Gets the current number of tasks in the scheduler.
* \return The number of tasks.
* \remarks Prefer empty() to size() == 0 to check if the scheduler is empty.
*/
size_t size() const
{
return m_container.size();
}
/*! Checks if the scheduler is empty.
* \return true if the scheduler contains no tasks, false otherwise.
* \remarks Is more efficient than size() == 0.
*/
bool empty() const
{
return m_container.empty();
}
/*! Removes all tasks from the scheduler.
*/
void clear()
{
m_container.clear();
}
};
/*! \brief SchedulingPolicy which implements LIFO ordering.
*
* This container implements a LIFO scheduling policy.
* The last task to be added to the scheduler will be the first to be removed.
* LIFO stands for "last in, first out".
*
* \param Task A function object which implements the operator()(void).
*
*/
template <typename Task = task_func>
class lifo_scheduler
{
public:
typedef Task task_type; //!< Indicates the scheduler's task type.
protected:
std::deque<task_type> m_container; //!< Internal task container.
public:
/*! Adds a new task to the scheduler.
* \param task The task object.
* \return true, if the task could be scheduled and false otherwise.
*/
bool push(task_type const & task)
{
m_container.push_front(task);
return true;
}
/*! Removes the task which should be executed next.
*/
void pop()
{
m_container.pop_front();
}
/*! Gets the task which should be executed next.
* \return The task object to be executed.
*/
task_type const & top() const
{
return m_container.front();
}
/*! Gets the current number of tasks in the scheduler.
* \return The number of tasks.
* \remarks Prefer empty() to size() == 0 to check if the scheduler is empty.
*/
size_t size() const
{
return m_container.size();
}
/*! Checks if the scheduler is empty.
* \return true if the scheduler contains no tasks, false otherwise.
* \remarks Is more efficient than size() == 0.
*/
bool empty() const
{
return m_container.empty();
}
/*! Removes all tasks from the scheduler.
*/
void clear()
{
m_container.clear();
}
};
/*! \brief SchedulingPolicy which implements prioritized ordering.
*
* This container implements a scheduling policy based on task priorities.
* The task with highest priority will be the first to be removed.
* It must be possible to compare two tasks using operator<.
*
* \param Task A function object which implements the operator() and operator<. operator< must be a partial ordering.
*
* \see prio_thread_func
*
*/
template <typename Task = prio_task_func>
class prio_scheduler
{
public:
typedef Task task_type; //!< Indicates the scheduler's task type.
protected:
std::priority_queue<task_type> m_container; //!< Internal task container.
public:
/*! Adds a new task to the scheduler.
* \param task The task object.
* \return true, if the task could be scheduled and false otherwise.
*/
bool push(task_type const & task)
{
m_container.push(task);
return true;
}
/*! Removes the task which should be executed next.
*/
void pop()
{
m_container.pop();
}
/*! Gets the task which should be executed next.
* \return The task object to be executed.
*/
task_type const & top() const
{
return m_container.top();
}
/*! Gets the current number of tasks in the scheduler.
* \return The number of tasks.
* \remarks Prefer empty() to size() == 0 to check if the scheduler is empty.
*/
size_t size() const
{
return m_container.size();
}
/*! Checks if the scheduler is empty.
* \return true if the scheduler contains no tasks, false otherwise.
* \remarks Is more efficient than size() == 0.
*/
bool empty() const
{
return m_container.empty();
}
/*! Removes all tasks from the scheduler.
*/
void clear()
{
while(!m_container.empty())
{
m_container.pop();
}
}
};
} } // namespace boost::threadpool
#endif // THREADPOOL_SCHEDULING_POLICIES_HPP_INCLUDED

View File

@ -1,83 +0,0 @@
/*! \file
* \brief Shutdown policies.
*
* This file contains shutdown policies for thread_pool.
* A shutdown policy controls the pool's behavior from the time
* when the pool is not referenced any longer.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_SHUTDOWN_POLICIES_HPP_INCLUDED
#define THREADPOOL_SHUTDOWN_POLICIES_HPP_INCLUDED
/// The namespace threadpool contains a thread pool and related utility classes.
namespace boost { namespace threadpool
{
/*! \brief ShutdownPolicy which waits for the completion of all tasks
* and the worker termination afterwards.
*
* \param Pool The pool's core type.
*/
template<typename Pool>
class wait_for_all_tasks
{
public:
static void shutdown(Pool& pool)
{
pool.wait();
pool.terminate_all_workers(true);
}
};
/*! \brief ShutdownPolicy which waits for the completion of all active tasks
* and the worker termination afterwards.
*
* \param Pool The pool's core type.
*/
template<typename Pool>
class wait_for_active_tasks
{
public:
static void shutdown(Pool& pool)
{
pool.clear();
pool.wait();
pool.terminate_all_workers(true);
}
};
/*! \brief ShutdownPolicy which does not wait for any tasks or worker termination.
*
* This policy does not wait for any tasks. Nevertheless all active tasks will be processed completely.
*
* \param Pool The pool's core type.
*/
template<typename Pool>
class immediately
{
public:
static void shutdown(Pool& pool)
{
pool.clear();
pool.terminate_all_workers(false);
}
};
} } // namespace boost::threadpool
#endif // THREADPOOL_SHUTDOWN_POLICIES_HPP_INCLUDED

View File

@ -1,99 +0,0 @@
/*! \file
* \brief Size policies.
*
* This file contains size policies for thread_pool. A size
* policy controls the number of worker threads in the pool.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_SIZE_POLICIES_HPP_INCLUDED
#define THREADPOOL_SIZE_POLICIES_HPP_INCLUDED
/// The namespace threadpool contains a thread pool and related utility classes.
namespace boost { namespace threadpool
{
/*! \brief SizePolicyController which provides no functionality.
*
* \param Pool The pool's core type.
*/
template<typename Pool>
struct empty_controller
{
empty_controller(typename Pool::size_policy_type&, shared_ptr<Pool>) {}
};
/*! \brief SizePolicyController which allows resizing.
*
* \param Pool The pool's core type.
*/
template< typename Pool >
class resize_controller
{
typedef typename Pool::size_policy_type size_policy_type;
reference_wrapper<size_policy_type> m_policy;
shared_ptr<Pool> m_pool; //!< to make sure that the pool is alive (the policy pointer is valid) as long as the controller exists
public:
resize_controller(size_policy_type& policy, shared_ptr<Pool> pool)
: m_policy(policy)
, m_pool(pool)
{
}
bool resize(size_t worker_count)
{
return m_policy.get().resize(worker_count);
}
};
/*! \brief SizePolicy which preserves the thread count.
*
* \param Pool The pool's core type.
*/
template<typename Pool>
class static_size
{
reference_wrapper<Pool volatile> m_pool;
public:
static void init(Pool& pool, size_t const worker_count)
{
pool.resize(worker_count);
}
static_size(Pool volatile & pool)
: m_pool(pool)
{}
bool resize(size_t const worker_count)
{
return m_pool.get().resize(worker_count);
}
void worker_died_unexpectedly(size_t const new_worker_count)
{
m_pool.get().resize(new_worker_count + 1);
}
// TODO this functions are not called yet
void task_scheduled() {}
void task_finished() {}
};
} } // namespace boost::threadpool
#endif // THREADPOOL_SIZE_POLICIES_HPP_INCLUDED

View File

@ -1,176 +0,0 @@
/*! \file
* \brief Task adaptors.
*
* This file contains adaptors for task function objects.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/
#ifndef THREADPOOL_TASK_ADAPTERS_HPP_INCLUDED
#define THREADPOOL_TASK_ADAPTERS_HPP_INCLUDED
#include <boost/version.hpp>
#if BOOST_VERSION >= 105000
#ifndef TIME_UTC
#define TIME_UTC TIME_UTC_
#endif
#endif
#include <boost/smart_ptr.hpp>
#include <boost/function.hpp>
#include <boost/thread.hpp>
namespace boost { namespace threadpool
{
/*! \brief Standard task function object.
*
* This function object wraps a nullary function which returns void.
* The wrapped function is invoked by calling the operator ().
*
* \see boost function library
*
*/
typedef function0<void> task_func;
/*! \brief Prioritized task function object.
*
* This function object wraps a task_func object and binds a priority to it.
* prio_task_funcs can be compared using the operator < which realises a partial ordering.
* The wrapped task function is invoked by calling the operator ().
*
* \see prio_scheduler
*
*/
class prio_task_func
{
private:
unsigned int m_priority; //!< The priority of the task's function.
task_func m_function; //!< The task's function.
public:
typedef void result_type; //!< Indicates the functor's result type.
public:
/*! Constructor.
* \param priority The priority of the task.
* \param function The task's function object.
*/
prio_task_func(unsigned int const priority, task_func const & function)
: m_priority(priority)
, m_function(function)
{
}
/*! Executes the task function.
*/
void operator() (void) const
{
if(m_function)
{
m_function();
}
}
/*! Comparison operator which realises a partial ordering based on priorities.
* \param rhs The object to compare with.
* \return true if the priority of *this is less than right hand side's priority, false otherwise.
*/
bool operator< (const prio_task_func& rhs) const
{
return m_priority < rhs.m_priority;
}
}; // prio_task_func
/*! \brief Looped task function object.
*
* This function object wraps a boolean thread function object.
* The wrapped task function is invoked by calling the operator () and it is executed in regular
* time intervals until false is returned. The interval length may be zero.
* Please note that a pool's thread is engaged as long as the task is looped.
*
*/
class looped_task_func
{
private:
function0<bool> m_function; //!< The task's function.
unsigned int m_break_s; //!< Duration of breaks in seconds.
unsigned int m_break_ns; //!< Duration of breaks in nano seconds.
public:
typedef void result_type; //!< Indicates the functor's result type.
public:
/*! Constructor.
* \param function The task's function object which is looped until false is returned.
* \param interval The minimum break time in milli seconds before the first execution of the task function and between the following ones.
*/
looped_task_func(function0<bool> const & function, unsigned int const interval = 0)
: m_function(function)
{
m_break_s = interval / 1000;
m_break_ns = (interval - m_break_s * 1000) * 1000 * 1000;
}
/*! Executes the task function.
*/
void operator() (void) const
{
if(m_function)
{
if(m_break_s > 0 || m_break_ns > 0)
{ // Sleep some time before first execution
xtime xt;
xtime_get(&xt, TIME_UTC);
xt.nsec += m_break_ns;
xt.sec += m_break_s;
thread::sleep(xt);
}
while(m_function())
{
if(m_break_s > 0 || m_break_ns > 0)
{
xtime xt;
xtime_get(&xt, TIME_UTC);
xt.nsec += m_break_ns;
xt.sec += m_break_s;
thread::sleep(xt);
}
else
{
thread::yield(); // Be fair to other threads
}
}
}
}
}; // looped_task_func
} } // namespace boost::threadpool
#endif // THREADPOOL_TASK_ADAPTERS_HPP_INCLUDED

View File

@ -38,7 +38,7 @@ void match_features(const struct feature_map_t* matchtable, int count, uint32_t
{ {
int i; int i;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
if (reg & (1 << matchtable[i].bit)) if (reg & (1U << matchtable[i].bit))
data->flags[matchtable[i].feature] = 1; data->flags[matchtable[i].feature] = 1;
} }

View File

@ -1,6 +1,8 @@
/* libdivide.h /* libdivide.h
Copyright 2010 ridiculous_fish Copyright 2010 ridiculous_fish
*/ */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
#define LIBDIVIDE_WINDOWS 1 #define LIBDIVIDE_WINDOWS 1
@ -1340,3 +1342,5 @@ __m128i operator/(__m128i numer, const divider<int_type, ALGO> & denom) {
} //close namespace libdivide } //close namespace libdivide
} //close anonymous namespace } //close anonymous namespace
#endif #endif
#pragma GCC diagnostic pop

View File

@ -136,7 +136,8 @@ endif(WIN32)
if (UNIX AND NOT ANDROID ) if (UNIX AND NOT ANDROID )
add_definitions( -DPOCO_OS_FAMILY_UNIX ) add_definitions( -DPOCO_OS_FAMILY_UNIX )
add_definitions( -Wno-unused-private-field -Wno-unused-local-typedef -Wno-for-loop-analysis -Wno-unknown-pragmas ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-private-field -Wno-unused-local-typedef -Wno-for-loop-analysis -Wno-unknown-pragmas -Wno-unused-variable")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unknown-pragmas -Wno-unused-variable")
# Standard 'must be' defines # Standard 'must be' defines
if (APPLE) if (APPLE)
add_definitions( -DPOCO_HAVE_IPv6 -DPOCO_NO_STAT64) add_definitions( -DPOCO_HAVE_IPv6 -DPOCO_NO_STAT64)
@ -321,9 +322,6 @@ install(
message(STATUS "CMake ${CMAKE_VERSION} successfully configured ${PROJECT_NAME} using ${CMAKE_GENERATOR} generator") message(STATUS "CMake ${CMAKE_VERSION} successfully configured ${PROJECT_NAME} using ${CMAKE_GENERATOR} generator")
message(STATUS "Installation target path: ${CMAKE_INSTALL_PREFIX}") message(STATUS "Installation target path: ${CMAKE_INSTALL_PREFIX}")
message(STATUS "C_FLAGS: =${CMAKE_C_FLAGS}")
message(STATUS "CXX_FLAGS:=${CMAKE_CXX_FLAGS}")
foreach(component ${Poco_COMPONENTS}) foreach(component ${Poco_COMPONENTS})
message(STATUS "Building: ${component}") message(STATUS "Building: ${component}")
endforeach() endforeach()

View File

@ -357,7 +357,7 @@ inline SQLINTEGER stringLength(SQLPOINTER pValue, SQLINTEGER length)
{ {
if (SQL_NTS != length) return length; if (SQL_NTS != length) return length;
return (SQLINTEGER) std::strlen((const char*) pValue); return static_cast<SQLINTEGER>(std::strlen(static_cast<const char*>(pValue)));
} }

View File

@ -124,7 +124,7 @@ inline const std::string& AbstractBinding::name() const
inline AbstractBinder::Direction AbstractBinding::getDirection() const inline AbstractBinder::Direction AbstractBinding::getDirection() const
{ {
return (AbstractBinder::Direction) _direction; return static_cast<AbstractBinder::Direction>(_direction);
} }

View File

@ -390,7 +390,7 @@ public:
/// to start iteration from beginning or end, /// to start iteration from beginning or end,
/// depending on the position requested. /// depending on the position requested.
{ {
if (row <= (std::size_t) (_pData->size() / 2)) if (row <= static_cast<std::size_t>(_pData->size() / 2))
{ {
Iterator it = _pData->begin(); Iterator it = _pData->begin();
Iterator end = _pData->end(); Iterator end = _pData->end();

View File

@ -35,7 +35,7 @@ public:
enum Type enum Type
{ {
LIMIT_UNLIMITED = ~((SizeT) 0) LIMIT_UNLIMITED = ~(static_cast<SizeT>(0))
}; };
Limit(SizeT value, bool hardLimit = false, bool isLowerLimit = false); Limit(SizeT value, bool hardLimit = false, bool isLowerLimit = false);

View File

@ -91,7 +91,7 @@ inline int PooledSessionHolder::idle() const
{ {
Poco::FastMutex::ScopedLock lock(_mutex); Poco::FastMutex::ScopedLock lock(_mutex);
return (int) (_lastUsed.elapsed()/Poco::Timestamp::resolution()); return static_cast<int>(_lastUsed.elapsed()/Poco::Timestamp::resolution());
} }

View File

@ -176,10 +176,10 @@ struct poco_static_assert_test
#if defined(__GNUC__) && (__GNUC__ == 3) && ((__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4)) #if defined(__GNUC__) && (__GNUC__ == 3) && ((__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4))
#define poco_static_assert(B) \ #define poco_static_assert(B) \
typedef char POCO_JOIN(poco_static_assert_typedef_, __LINE__) \ typedef char POCO_JOIN(poco_static_assert_typedef_, __LINE__) \
[POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>::value] [POCO_STATIC_ASSERTION_FAILURE<static_cast<bool>(B)>::value]
#else #else
#define poco_static_assert(B) \ #define poco_static_assert(B) \
typedef poco_static_assert_test<sizeof(POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>)> \ typedef poco_static_assert_test<sizeof(POCO_STATIC_ASSERTION_FAILURE<static_cast<bool>(B)>)> \
POCO_JOIN(poco_static_assert_typedef_, __LINE__) POCO_JOIN(poco_static_assert_typedef_, __LINE__)
#endif #endif

View File

@ -87,7 +87,7 @@ inline bool FPEnvironmentImpl::isInfiniteImpl(double value)
inline bool FPEnvironmentImpl::isInfiniteImpl(long double value) inline bool FPEnvironmentImpl::isInfiniteImpl(long double value)
{ {
return std::isinf((double) value) != 0; return std::isinf(static_cast<double>(value)) != 0;
} }
@ -105,7 +105,7 @@ inline bool FPEnvironmentImpl::isNaNImpl(double value)
inline bool FPEnvironmentImpl::isNaNImpl(long double value) inline bool FPEnvironmentImpl::isNaNImpl(long double value)
{ {
return std::isnan((double) value) != 0; return std::isnan(static_cast<double>(value)) != 0;
} }

View File

@ -368,13 +368,13 @@ inline Timestamp LocalDateTime::timestamp() const
inline Timestamp::UtcTimeVal LocalDateTime::utcTime() const inline Timestamp::UtcTimeVal LocalDateTime::utcTime() const
{ {
return _dateTime.utcTime() - ((Timestamp::TimeDiff) _tzd)*10000000; return _dateTime.utcTime() - (static_cast<Timestamp::TimeDiff>(_tzd))*10000000;
} }
inline void LocalDateTime::adjustForTzd() inline void LocalDateTime::adjustForTzd()
{ {
_dateTime += Timespan(((Timestamp::TimeDiff) _tzd)*Timespan::SECONDS); _dateTime += Timespan((static_cast<Timestamp::TimeDiff>(_tzd))*Timespan::SECONDS);
} }

View File

@ -132,7 +132,7 @@ public:
if (newoff + off < 0 || (this->epptr() - this->pbase()) < newoff + off) if (newoff + off < 0 || (this->epptr() - this->pbase()) < newoff + off)
return fail; return fail;
this->pbump((int)(newoff + off - (this->pptr() - this->pbase()))); this->pbump(static_cast<int>(newoff + off - (this->pptr() - this->pbase())));
} }
return newoff; return newoff;

View File

@ -26,6 +26,8 @@
#include "Poco/Mutex.h" #include "Poco/Mutex.h"
#include "Poco/Event.h" #include "Poco/Event.h"
#include <atomic>
namespace Poco { namespace Poco {
@ -140,7 +142,7 @@ private:
std::string _name; std::string _name;
TaskManager* _pOwner; TaskManager* _pOwner;
float _progress; float _progress;
TaskState _state; std::atomic<TaskState> _state;
Event _cancelEvent; Event _cancelEvent;
mutable FastMutex _mutex; mutable FastMutex _mutex;

View File

@ -129,7 +129,7 @@ inline int TaskManager::count() const
{ {
FastMutex::ScopedLock lock(_mutex); FastMutex::ScopedLock lock(_mutex);
return (int) _taskList.size(); return static_cast<int>(_taskList.size());
} }

View File

@ -17,7 +17,7 @@
#include "Poco/Task.h" #include "Poco/Task.h"
#include "Poco/TaskManager.h" #include "Poco/TaskManager.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include <array>
namespace Poco { namespace Poco {
@ -61,8 +61,17 @@ void Task::run()
pOwner->taskStarted(this); pOwner->taskStarted(this);
try try
{ {
_state = TASK_RUNNING; /** Task can be already cancelled.
* To prevent endless executing already cancelled task _state is assigned to TASK_RUNNING only if _state != TASK_CANCELLING
*/
std::array<TaskState, 3> allowed_states{TASK_IDLE, TASK_STARTING, TASK_FINISHED};
for (auto & expected : allowed_states)
if (_state.compare_exchange_strong(expected, TASK_RUNNING))
break;
if (_state == TASK_RUNNING)
runTask(); runTask();
} }
catch (Exception& exc) catch (Exception& exc)
{ {

View File

@ -419,7 +419,11 @@ void DNS::aierror(int code, const std::string& arg)
throw HostNotFoundException(arg); throw HostNotFoundException(arg);
#endif #endif
default: default:
throw DNSException("EAI", NumberFormatter::format(code)); #if defined(POCO_HAVE_ADDRINFO)
throw DNSException(gai_strerror(code), NumberFormatter::format(code), code);
#else
throw DNSException("EAI", NumberFormatter::format(code), code);
#endif
} }
#endif // POCO_HAVE_IPv6 || defined(POCO_HAVE_ADDRINFO) #endif // POCO_HAVE_IPv6 || defined(POCO_HAVE_ADDRINFO)
} }

View File

@ -115,7 +115,7 @@ inline const XMLString& CharacterData::getData() const
inline unsigned long CharacterData::length() const inline unsigned long CharacterData::length() const
{ {
return (unsigned long) _data.length(); return static_cast<unsigned long>(_data.length());
} }

View File

@ -0,0 +1,18 @@
add_definitions(-DHAVE_CONFIG_H -DTHREADED)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
add_definitions(-Wno-unused-but-set-variable)
endif()
include_directories (include/zookeeper src)
add_library (zookeeper
src/zookeeper.c
src/zookeeper.jute.c
src/zk_hashtable.c
src/zk_log.c
src/mt_adaptor.c
src/recordio.c
src/hashtable/hashtable.c
src/hashtable/hashtable_itr.c
)

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1 @@
http://apache-mirror.rbc.ru/pub/apache/zookeeper/stable/zookeeper-3.4.8.tar.gz

View File

@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PROTO_H_
#define PROTO_H_
#ifdef __cplusplus
extern "C" {
#endif
#define ZOO_NOTIFY_OP 0
#define ZOO_CREATE_OP 1
#define ZOO_DELETE_OP 2
#define ZOO_EXISTS_OP 3
#define ZOO_GETDATA_OP 4
#define ZOO_SETDATA_OP 5
#define ZOO_GETACL_OP 6
#define ZOO_SETACL_OP 7
#define ZOO_GETCHILDREN_OP 8
#define ZOO_SYNC_OP 9
#define ZOO_PING_OP 11
#define ZOO_GETCHILDREN2_OP 12
#define ZOO_CHECK_OP 13
#define ZOO_MULTI_OP 14
#define ZOO_CLOSE_OP -11
#define ZOO_SETAUTH_OP 100
#define ZOO_SETWATCHES_OP 101
#ifdef __cplusplus
}
#endif
#endif /*PROTO_H_*/

View File

@ -0,0 +1,82 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __RECORDIO_H__
#define __RECORDIO_H__
#include <sys/types.h>
#ifndef WIN32
#define STRUCT_INITIALIZER(l,r) .l = r
#else
#define STRUCT_INITIALIZER(l,r) r
#include "winconfig.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct buffer {
int32_t len;
char *buff;
};
void deallocate_String(char **s);
void deallocate_Buffer(struct buffer *b);
void deallocate_vector(void *d);
struct iarchive {
int (*start_record)(struct iarchive *ia, const char *tag);
int (*end_record)(struct iarchive *ia, const char *tag);
int (*start_vector)(struct iarchive *ia, const char *tag, int32_t *count);
int (*end_vector)(struct iarchive *ia, const char *tag);
int (*deserialize_Bool)(struct iarchive *ia, const char *name, int32_t *);
int (*deserialize_Int)(struct iarchive *ia, const char *name, int32_t *);
int (*deserialize_Long)(struct iarchive *ia, const char *name, int64_t *);
int (*deserialize_Buffer)(struct iarchive *ia, const char *name,
struct buffer *);
int (*deserialize_String)(struct iarchive *ia, const char *name, char **);
void *priv;
};
struct oarchive {
int (*start_record)(struct oarchive *oa, const char *tag);
int (*end_record)(struct oarchive *oa, const char *tag);
int (*start_vector)(struct oarchive *oa, const char *tag, const int32_t *count);
int (*end_vector)(struct oarchive *oa, const char *tag);
int (*serialize_Bool)(struct oarchive *oa, const char *name, const int32_t *);
int (*serialize_Int)(struct oarchive *oa, const char *name, const int32_t *);
int (*serialize_Long)(struct oarchive *oa, const char *name,
const int64_t *);
int (*serialize_Buffer)(struct oarchive *oa, const char *name,
const struct buffer *);
int (*serialize_String)(struct oarchive *oa, const char *name, char **);
void *priv;
};
struct oarchive *create_buffer_oarchive(void);
void close_buffer_oarchive(struct oarchive **oa, int free_buffer);
struct iarchive *create_buffer_iarchive(char *buffer, int len);
void close_buffer_iarchive(struct iarchive **ia);
char *get_buffer(struct oarchive *);
int get_buffer_len(struct oarchive *);
int64_t zoo_htonll(int64_t v);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,485 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __ZOOKEEPER_JUTE__
#define __ZOOKEEPER_JUTE__
#include "recordio.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Id {
char * scheme;
char * id;
};
int serialize_Id(struct oarchive *out, const char *tag, struct Id *v);
int deserialize_Id(struct iarchive *in, const char *tag, struct Id*v);
void deallocate_Id(struct Id*);
struct ACL {
int32_t perms;
struct Id id;
};
int serialize_ACL(struct oarchive *out, const char *tag, struct ACL *v);
int deserialize_ACL(struct iarchive *in, const char *tag, struct ACL*v);
void deallocate_ACL(struct ACL*);
struct Stat {
int64_t czxid;
int64_t mzxid;
int64_t ctime;
int64_t mtime;
int32_t version;
int32_t cversion;
int32_t aversion;
int64_t ephemeralOwner;
int32_t dataLength;
int32_t numChildren;
int64_t pzxid;
};
int serialize_Stat(struct oarchive *out, const char *tag, struct Stat *v);
int deserialize_Stat(struct iarchive *in, const char *tag, struct Stat*v);
void deallocate_Stat(struct Stat*);
struct StatPersisted {
int64_t czxid;
int64_t mzxid;
int64_t ctime;
int64_t mtime;
int32_t version;
int32_t cversion;
int32_t aversion;
int64_t ephemeralOwner;
int64_t pzxid;
};
int serialize_StatPersisted(struct oarchive *out, const char *tag, struct StatPersisted *v);
int deserialize_StatPersisted(struct iarchive *in, const char *tag, struct StatPersisted*v);
void deallocate_StatPersisted(struct StatPersisted*);
struct StatPersistedV1 {
int64_t czxid;
int64_t mzxid;
int64_t ctime;
int64_t mtime;
int32_t version;
int32_t cversion;
int32_t aversion;
int64_t ephemeralOwner;
};
int serialize_StatPersistedV1(struct oarchive *out, const char *tag, struct StatPersistedV1 *v);
int deserialize_StatPersistedV1(struct iarchive *in, const char *tag, struct StatPersistedV1*v);
void deallocate_StatPersistedV1(struct StatPersistedV1*);
struct ConnectRequest {
int32_t protocolVersion;
int64_t lastZxidSeen;
int32_t timeOut;
int64_t sessionId;
struct buffer passwd;
};
int serialize_ConnectRequest(struct oarchive *out, const char *tag, struct ConnectRequest *v);
int deserialize_ConnectRequest(struct iarchive *in, const char *tag, struct ConnectRequest*v);
void deallocate_ConnectRequest(struct ConnectRequest*);
struct ConnectResponse {
int32_t protocolVersion;
int32_t timeOut;
int64_t sessionId;
struct buffer passwd;
};
int serialize_ConnectResponse(struct oarchive *out, const char *tag, struct ConnectResponse *v);
int deserialize_ConnectResponse(struct iarchive *in, const char *tag, struct ConnectResponse*v);
void deallocate_ConnectResponse(struct ConnectResponse*);
struct String_vector {
int32_t count;
char * *data;
};
int serialize_String_vector(struct oarchive *out, const char *tag, struct String_vector *v);
int deserialize_String_vector(struct iarchive *in, const char *tag, struct String_vector *v);
int allocate_String_vector(struct String_vector *v, int32_t len);
int deallocate_String_vector(struct String_vector *v);
struct SetWatches {
int64_t relativeZxid;
struct String_vector dataWatches;
struct String_vector existWatches;
struct String_vector childWatches;
};
int serialize_SetWatches(struct oarchive *out, const char *tag, struct SetWatches *v);
int deserialize_SetWatches(struct iarchive *in, const char *tag, struct SetWatches*v);
void deallocate_SetWatches(struct SetWatches*);
struct RequestHeader {
int32_t xid;
int32_t type;
};
int serialize_RequestHeader(struct oarchive *out, const char *tag, struct RequestHeader *v);
int deserialize_RequestHeader(struct iarchive *in, const char *tag, struct RequestHeader*v);
void deallocate_RequestHeader(struct RequestHeader*);
struct MultiHeader {
int32_t type;
int32_t done;
int32_t err;
};
int serialize_MultiHeader(struct oarchive *out, const char *tag, struct MultiHeader *v);
int deserialize_MultiHeader(struct iarchive *in, const char *tag, struct MultiHeader*v);
void deallocate_MultiHeader(struct MultiHeader*);
struct AuthPacket {
int32_t type;
char * scheme;
struct buffer auth;
};
int serialize_AuthPacket(struct oarchive *out, const char *tag, struct AuthPacket *v);
int deserialize_AuthPacket(struct iarchive *in, const char *tag, struct AuthPacket*v);
void deallocate_AuthPacket(struct AuthPacket*);
struct ReplyHeader {
int32_t xid;
int64_t zxid;
int32_t err;
};
int serialize_ReplyHeader(struct oarchive *out, const char *tag, struct ReplyHeader *v);
int deserialize_ReplyHeader(struct iarchive *in, const char *tag, struct ReplyHeader*v);
void deallocate_ReplyHeader(struct ReplyHeader*);
struct GetDataRequest {
char * path;
int32_t watch;
};
int serialize_GetDataRequest(struct oarchive *out, const char *tag, struct GetDataRequest *v);
int deserialize_GetDataRequest(struct iarchive *in, const char *tag, struct GetDataRequest*v);
void deallocate_GetDataRequest(struct GetDataRequest*);
struct SetDataRequest {
char * path;
struct buffer data;
int32_t version;
};
int serialize_SetDataRequest(struct oarchive *out, const char *tag, struct SetDataRequest *v);
int deserialize_SetDataRequest(struct iarchive *in, const char *tag, struct SetDataRequest*v);
void deallocate_SetDataRequest(struct SetDataRequest*);
struct SetDataResponse {
struct Stat stat;
};
int serialize_SetDataResponse(struct oarchive *out, const char *tag, struct SetDataResponse *v);
int deserialize_SetDataResponse(struct iarchive *in, const char *tag, struct SetDataResponse*v);
void deallocate_SetDataResponse(struct SetDataResponse*);
struct GetSASLRequest {
struct buffer token;
};
int serialize_GetSASLRequest(struct oarchive *out, const char *tag, struct GetSASLRequest *v);
int deserialize_GetSASLRequest(struct iarchive *in, const char *tag, struct GetSASLRequest*v);
void deallocate_GetSASLRequest(struct GetSASLRequest*);
struct SetSASLRequest {
struct buffer token;
};
int serialize_SetSASLRequest(struct oarchive *out, const char *tag, struct SetSASLRequest *v);
int deserialize_SetSASLRequest(struct iarchive *in, const char *tag, struct SetSASLRequest*v);
void deallocate_SetSASLRequest(struct SetSASLRequest*);
struct SetSASLResponse {
struct buffer token;
};
int serialize_SetSASLResponse(struct oarchive *out, const char *tag, struct SetSASLResponse *v);
int deserialize_SetSASLResponse(struct iarchive *in, const char *tag, struct SetSASLResponse*v);
void deallocate_SetSASLResponse(struct SetSASLResponse*);
struct ACL_vector {
int32_t count;
struct ACL *data;
};
int serialize_ACL_vector(struct oarchive *out, const char *tag, struct ACL_vector *v);
int deserialize_ACL_vector(struct iarchive *in, const char *tag, struct ACL_vector *v);
int allocate_ACL_vector(struct ACL_vector *v, int32_t len);
int deallocate_ACL_vector(struct ACL_vector *v);
struct CreateRequest {
char * path;
struct buffer data;
struct ACL_vector acl;
int32_t flags;
};
int serialize_CreateRequest(struct oarchive *out, const char *tag, struct CreateRequest *v);
int deserialize_CreateRequest(struct iarchive *in, const char *tag, struct CreateRequest*v);
void deallocate_CreateRequest(struct CreateRequest*);
struct DeleteRequest {
char * path;
int32_t version;
};
int serialize_DeleteRequest(struct oarchive *out, const char *tag, struct DeleteRequest *v);
int deserialize_DeleteRequest(struct iarchive *in, const char *tag, struct DeleteRequest*v);
void deallocate_DeleteRequest(struct DeleteRequest*);
struct GetChildrenRequest {
char * path;
int32_t watch;
};
int serialize_GetChildrenRequest(struct oarchive *out, const char *tag, struct GetChildrenRequest *v);
int deserialize_GetChildrenRequest(struct iarchive *in, const char *tag, struct GetChildrenRequest*v);
void deallocate_GetChildrenRequest(struct GetChildrenRequest*);
struct GetChildren2Request {
char * path;
int32_t watch;
};
int serialize_GetChildren2Request(struct oarchive *out, const char *tag, struct GetChildren2Request *v);
int deserialize_GetChildren2Request(struct iarchive *in, const char *tag, struct GetChildren2Request*v);
void deallocate_GetChildren2Request(struct GetChildren2Request*);
struct CheckVersionRequest {
char * path;
int32_t version;
};
int serialize_CheckVersionRequest(struct oarchive *out, const char *tag, struct CheckVersionRequest *v);
int deserialize_CheckVersionRequest(struct iarchive *in, const char *tag, struct CheckVersionRequest*v);
void deallocate_CheckVersionRequest(struct CheckVersionRequest*);
struct GetMaxChildrenRequest {
char * path;
};
int serialize_GetMaxChildrenRequest(struct oarchive *out, const char *tag, struct GetMaxChildrenRequest *v);
int deserialize_GetMaxChildrenRequest(struct iarchive *in, const char *tag, struct GetMaxChildrenRequest*v);
void deallocate_GetMaxChildrenRequest(struct GetMaxChildrenRequest*);
struct GetMaxChildrenResponse {
int32_t max;
};
int serialize_GetMaxChildrenResponse(struct oarchive *out, const char *tag, struct GetMaxChildrenResponse *v);
int deserialize_GetMaxChildrenResponse(struct iarchive *in, const char *tag, struct GetMaxChildrenResponse*v);
void deallocate_GetMaxChildrenResponse(struct GetMaxChildrenResponse*);
struct SetMaxChildrenRequest {
char * path;
int32_t max;
};
int serialize_SetMaxChildrenRequest(struct oarchive *out, const char *tag, struct SetMaxChildrenRequest *v);
int deserialize_SetMaxChildrenRequest(struct iarchive *in, const char *tag, struct SetMaxChildrenRequest*v);
void deallocate_SetMaxChildrenRequest(struct SetMaxChildrenRequest*);
struct SyncRequest {
char * path;
};
int serialize_SyncRequest(struct oarchive *out, const char *tag, struct SyncRequest *v);
int deserialize_SyncRequest(struct iarchive *in, const char *tag, struct SyncRequest*v);
void deallocate_SyncRequest(struct SyncRequest*);
struct SyncResponse {
char * path;
};
int serialize_SyncResponse(struct oarchive *out, const char *tag, struct SyncResponse *v);
int deserialize_SyncResponse(struct iarchive *in, const char *tag, struct SyncResponse*v);
void deallocate_SyncResponse(struct SyncResponse*);
struct GetACLRequest {
char * path;
};
int serialize_GetACLRequest(struct oarchive *out, const char *tag, struct GetACLRequest *v);
int deserialize_GetACLRequest(struct iarchive *in, const char *tag, struct GetACLRequest*v);
void deallocate_GetACLRequest(struct GetACLRequest*);
struct SetACLRequest {
char * path;
struct ACL_vector acl;
int32_t version;
};
int serialize_SetACLRequest(struct oarchive *out, const char *tag, struct SetACLRequest *v);
int deserialize_SetACLRequest(struct iarchive *in, const char *tag, struct SetACLRequest*v);
void deallocate_SetACLRequest(struct SetACLRequest*);
struct SetACLResponse {
struct Stat stat;
};
int serialize_SetACLResponse(struct oarchive *out, const char *tag, struct SetACLResponse *v);
int deserialize_SetACLResponse(struct iarchive *in, const char *tag, struct SetACLResponse*v);
void deallocate_SetACLResponse(struct SetACLResponse*);
struct WatcherEvent {
int32_t type;
int32_t state;
char * path;
};
int serialize_WatcherEvent(struct oarchive *out, const char *tag, struct WatcherEvent *v);
int deserialize_WatcherEvent(struct iarchive *in, const char *tag, struct WatcherEvent*v);
void deallocate_WatcherEvent(struct WatcherEvent*);
struct ErrorResponse {
int32_t err;
};
int serialize_ErrorResponse(struct oarchive *out, const char *tag, struct ErrorResponse *v);
int deserialize_ErrorResponse(struct iarchive *in, const char *tag, struct ErrorResponse*v);
void deallocate_ErrorResponse(struct ErrorResponse*);
struct CreateResponse {
char * path;
};
int serialize_CreateResponse(struct oarchive *out, const char *tag, struct CreateResponse *v);
int deserialize_CreateResponse(struct iarchive *in, const char *tag, struct CreateResponse*v);
void deallocate_CreateResponse(struct CreateResponse*);
struct ExistsRequest {
char * path;
int32_t watch;
};
int serialize_ExistsRequest(struct oarchive *out, const char *tag, struct ExistsRequest *v);
int deserialize_ExistsRequest(struct iarchive *in, const char *tag, struct ExistsRequest*v);
void deallocate_ExistsRequest(struct ExistsRequest*);
struct ExistsResponse {
struct Stat stat;
};
int serialize_ExistsResponse(struct oarchive *out, const char *tag, struct ExistsResponse *v);
int deserialize_ExistsResponse(struct iarchive *in, const char *tag, struct ExistsResponse*v);
void deallocate_ExistsResponse(struct ExistsResponse*);
struct GetDataResponse {
struct buffer data;
struct Stat stat;
};
int serialize_GetDataResponse(struct oarchive *out, const char *tag, struct GetDataResponse *v);
int deserialize_GetDataResponse(struct iarchive *in, const char *tag, struct GetDataResponse*v);
void deallocate_GetDataResponse(struct GetDataResponse*);
struct GetChildrenResponse {
struct String_vector children;
};
int serialize_GetChildrenResponse(struct oarchive *out, const char *tag, struct GetChildrenResponse *v);
int deserialize_GetChildrenResponse(struct iarchive *in, const char *tag, struct GetChildrenResponse*v);
void deallocate_GetChildrenResponse(struct GetChildrenResponse*);
struct GetChildren2Response {
struct String_vector children;
struct Stat stat;
};
int serialize_GetChildren2Response(struct oarchive *out, const char *tag, struct GetChildren2Response *v);
int deserialize_GetChildren2Response(struct iarchive *in, const char *tag, struct GetChildren2Response*v);
void deallocate_GetChildren2Response(struct GetChildren2Response*);
struct GetACLResponse {
struct ACL_vector acl;
struct Stat stat;
};
int serialize_GetACLResponse(struct oarchive *out, const char *tag, struct GetACLResponse *v);
int deserialize_GetACLResponse(struct iarchive *in, const char *tag, struct GetACLResponse*v);
void deallocate_GetACLResponse(struct GetACLResponse*);
struct LearnerInfo {
int64_t serverid;
int32_t protocolVersion;
};
int serialize_LearnerInfo(struct oarchive *out, const char *tag, struct LearnerInfo *v);
int deserialize_LearnerInfo(struct iarchive *in, const char *tag, struct LearnerInfo*v);
void deallocate_LearnerInfo(struct LearnerInfo*);
struct Id_vector {
int32_t count;
struct Id *data;
};
int serialize_Id_vector(struct oarchive *out, const char *tag, struct Id_vector *v);
int deserialize_Id_vector(struct iarchive *in, const char *tag, struct Id_vector *v);
int allocate_Id_vector(struct Id_vector *v, int32_t len);
int deallocate_Id_vector(struct Id_vector *v);
struct QuorumPacket {
int32_t type;
int64_t zxid;
struct buffer data;
struct Id_vector authinfo;
};
int serialize_QuorumPacket(struct oarchive *out, const char *tag, struct QuorumPacket *v);
int deserialize_QuorumPacket(struct iarchive *in, const char *tag, struct QuorumPacket*v);
void deallocate_QuorumPacket(struct QuorumPacket*);
struct FileHeader {
int32_t magic;
int32_t version;
int64_t dbid;
};
int serialize_FileHeader(struct oarchive *out, const char *tag, struct FileHeader *v);
int deserialize_FileHeader(struct iarchive *in, const char *tag, struct FileHeader*v);
void deallocate_FileHeader(struct FileHeader*);
struct TxnHeader {
int64_t clientId;
int32_t cxid;
int64_t zxid;
int64_t time;
int32_t type;
};
int serialize_TxnHeader(struct oarchive *out, const char *tag, struct TxnHeader *v);
int deserialize_TxnHeader(struct iarchive *in, const char *tag, struct TxnHeader*v);
void deallocate_TxnHeader(struct TxnHeader*);
struct CreateTxnV0 {
char * path;
struct buffer data;
struct ACL_vector acl;
int32_t ephemeral;
};
int serialize_CreateTxnV0(struct oarchive *out, const char *tag, struct CreateTxnV0 *v);
int deserialize_CreateTxnV0(struct iarchive *in, const char *tag, struct CreateTxnV0*v);
void deallocate_CreateTxnV0(struct CreateTxnV0*);
struct CreateTxn {
char * path;
struct buffer data;
struct ACL_vector acl;
int32_t ephemeral;
int32_t parentCVersion;
};
int serialize_CreateTxn(struct oarchive *out, const char *tag, struct CreateTxn *v);
int deserialize_CreateTxn(struct iarchive *in, const char *tag, struct CreateTxn*v);
void deallocate_CreateTxn(struct CreateTxn*);
struct DeleteTxn {
char * path;
};
int serialize_DeleteTxn(struct oarchive *out, const char *tag, struct DeleteTxn *v);
int deserialize_DeleteTxn(struct iarchive *in, const char *tag, struct DeleteTxn*v);
void deallocate_DeleteTxn(struct DeleteTxn*);
struct SetDataTxn {
char * path;
struct buffer data;
int32_t version;
};
int serialize_SetDataTxn(struct oarchive *out, const char *tag, struct SetDataTxn *v);
int deserialize_SetDataTxn(struct iarchive *in, const char *tag, struct SetDataTxn*v);
void deallocate_SetDataTxn(struct SetDataTxn*);
struct CheckVersionTxn {
char * path;
int32_t version;
};
int serialize_CheckVersionTxn(struct oarchive *out, const char *tag, struct CheckVersionTxn *v);
int deserialize_CheckVersionTxn(struct iarchive *in, const char *tag, struct CheckVersionTxn*v);
void deallocate_CheckVersionTxn(struct CheckVersionTxn*);
struct SetACLTxn {
char * path;
struct ACL_vector acl;
int32_t version;
};
int serialize_SetACLTxn(struct oarchive *out, const char *tag, struct SetACLTxn *v);
int deserialize_SetACLTxn(struct iarchive *in, const char *tag, struct SetACLTxn*v);
void deallocate_SetACLTxn(struct SetACLTxn*);
struct SetMaxChildrenTxn {
char * path;
int32_t max;
};
int serialize_SetMaxChildrenTxn(struct oarchive *out, const char *tag, struct SetMaxChildrenTxn *v);
int deserialize_SetMaxChildrenTxn(struct iarchive *in, const char *tag, struct SetMaxChildrenTxn*v);
void deallocate_SetMaxChildrenTxn(struct SetMaxChildrenTxn*);
struct CreateSessionTxn {
int32_t timeOut;
};
int serialize_CreateSessionTxn(struct oarchive *out, const char *tag, struct CreateSessionTxn *v);
int deserialize_CreateSessionTxn(struct iarchive *in, const char *tag, struct CreateSessionTxn*v);
void deallocate_CreateSessionTxn(struct CreateSessionTxn*);
struct ErrorTxn {
int32_t err;
};
int serialize_ErrorTxn(struct oarchive *out, const char *tag, struct ErrorTxn *v);
int deserialize_ErrorTxn(struct iarchive *in, const char *tag, struct ErrorTxn*v);
void deallocate_ErrorTxn(struct ErrorTxn*);
struct Txn {
int32_t type;
struct buffer data;
};
int serialize_Txn(struct oarchive *out, const char *tag, struct Txn *v);
int deserialize_Txn(struct iarchive *in, const char *tag, struct Txn*v);
void deallocate_Txn(struct Txn*);
struct Txn_vector {
int32_t count;
struct Txn *data;
};
int serialize_Txn_vector(struct oarchive *out, const char *tag, struct Txn_vector *v);
int deserialize_Txn_vector(struct iarchive *in, const char *tag, struct Txn_vector *v);
int allocate_Txn_vector(struct Txn_vector *v, int32_t len);
int deallocate_Txn_vector(struct Txn_vector *v);
struct MultiTxn {
struct Txn_vector txns;
};
int serialize_MultiTxn(struct oarchive *out, const char *tag, struct MultiTxn *v);
int deserialize_MultiTxn(struct iarchive *in, const char *tag, struct MultiTxn*v);
void deallocate_MultiTxn(struct MultiTxn*);
#ifdef __cplusplus
}
#endif
#endif //ZOOKEEPER_JUTE__

View File

@ -0,0 +1,51 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ZK_LOG_H_
#define ZK_LOG_H_
#include <zookeeper.h>
#ifdef __cplusplus
extern "C" {
#endif
extern ZOOAPI ZooLogLevel logLevel;
#define LOGSTREAM getLogStream()
#define LOG_ERROR(x) if(logLevel>=ZOO_LOG_LEVEL_ERROR) \
log_message(ZOO_LOG_LEVEL_ERROR,__LINE__,__func__,format_log_message x)
#define LOG_WARN(x) if(logLevel>=ZOO_LOG_LEVEL_WARN) \
log_message(ZOO_LOG_LEVEL_WARN,__LINE__,__func__,format_log_message x)
#define LOG_INFO(x) if(logLevel>=ZOO_LOG_LEVEL_INFO) \
log_message(ZOO_LOG_LEVEL_INFO,__LINE__,__func__,format_log_message x)
#define LOG_DEBUG(x) if(logLevel==ZOO_LOG_LEVEL_DEBUG) \
log_message(ZOO_LOG_LEVEL_DEBUG,__LINE__,__func__,format_log_message x)
ZOOAPI void log_message(ZooLogLevel curLevel, int line,const char* funcName,
const char* message);
ZOOAPI const char* format_log_message(const char* format,...);
FILE* getLogStream();
#ifdef __cplusplus
}
#endif
#endif /*ZK_LOG_H_*/

View File

@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ZOOKEEPER_VERSION_H_
#define ZOOKEEPER_VERSION_H_
#ifdef __cplusplus
extern "C" {
#endif
#define ZOO_MAJOR_VERSION 3
#define ZOO_MINOR_VERSION 4
#define ZOO_PATCH_VERSION 8
#ifdef __cplusplus
}
#endif
#endif /* ZOOKEEPER_VERSION_H_ */

View File

@ -0,0 +1,149 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the file `generated/zookeeper.jute.c'. */
#define HAVE_GENERATED_ZOOKEEPER_JUTE_C 1
/* Define to 1 if you have the file `generated/zookeeper.jute.h'. */
#define HAVE_GENERATED_ZOOKEEPER_JUTE_H 1
/* Define to 1 if you have the `getcwd' function. */
#define HAVE_GETCWD 1
/* Define to 1 if you have the `gethostbyname' function. */
#define HAVE_GETHOSTBYNAME 1
/* Define to 1 if you have the `gethostname' function. */
#define HAVE_GETHOSTNAME 1
/* Define to 1 if you have the `getlogin' function. */
#define HAVE_GETLOGIN 1
/* Define to 1 if you have the `getpwuid_r' function. */
#define HAVE_GETPWUID_R 1
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the `getuid' function. */
#define HAVE_GETUID 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the <netdb.h> header file. */
#define HAVE_NETDB_H 1
/* Define to 1 if you have the <netinet/in.h> header file. */
#define HAVE_NETINET_IN_H 1
/* Define to 1 if you have the `poll' function. */
#define HAVE_POLL 1
/* Define to 1 if you have the `socket' function. */
#define HAVE_SOCKET 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1
/* Define to 1 if you have the <sys/socket.h> header file. */
#define HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/utsname.h> header file. */
#define HAVE_SYS_UTSNAME_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "zookeeper"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "user@zookeeper.apache.org"
/* Define to the full name of this package. */
#define PACKAGE_NAME "zookeeper C client"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "zookeeper C client 3.4.8"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "zookeeper"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "3.4.8"
/* poll() second argument type */
#define POLL_NFDS_TYPE nfds_t
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Version number of package */
#define VERSION "3.4.8"
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif

View File

@ -0,0 +1,30 @@
Copyright (c) 2002, 2004, Christopher Clark
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the original author; nor the names of any contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,274 @@
/* Copyright (C) 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#include "hashtable.h"
#include "hashtable_private.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
/*
Credit for primes table: Aaron Krowne
http://br.endernet.org/~akrowne/
http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
*/
static const unsigned int primes[] = {
53, 97, 193, 389,
769, 1543, 3079, 6151,
12289, 24593, 49157, 98317,
196613, 393241, 786433, 1572869,
3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189,
805306457, 1610612741
};
const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
const float max_load_factor = 0.65;
/*****************************************************************************/
struct hashtable *
create_hashtable(unsigned int minsize,
unsigned int (*hashf) (void*),
int (*eqf) (void*,void*))
{
struct hashtable *h;
unsigned int pindex, size = primes[0];
/* Check requested hashtable isn't too large */
if (minsize > (1u << 30)) return NULL;
/* Enforce size as prime */
for (pindex=0; pindex < prime_table_length; pindex++) {
if (primes[pindex] > minsize) { size = primes[pindex]; break; }
}
h = (struct hashtable *)malloc(sizeof(struct hashtable));
if (NULL == h) return NULL; /*oom*/
h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
if (NULL == h->table) { free(h); return NULL; } /*oom*/
memset(h->table, 0, size * sizeof(struct entry *));
h->tablelength = size;
h->primeindex = pindex;
h->entrycount = 0;
h->hashfn = hashf;
h->eqfn = eqf;
h->loadlimit = (unsigned int) ceil(size * max_load_factor);
return h;
}
/*****************************************************************************/
unsigned int
hash(struct hashtable *h, void *k)
{
/* Aim to protect against poor hash functions by adding logic here
* - logic taken from java 1.4 hashtable source */
unsigned int i = h->hashfn(k);
i += ~(i << 9);
i ^= ((i >> 14) | (i << 18)); /* >>> */
i += (i << 4);
i ^= ((i >> 10) | (i << 22)); /* >>> */
return i;
}
/*****************************************************************************/
static int
hashtable_expand(struct hashtable *h)
{
/* Double the size of the table to accomodate more entries */
struct entry **newtable;
struct entry *e;
struct entry **pE;
unsigned int newsize, i, index;
/* Check we're not hitting max capacity */
if (h->primeindex == (prime_table_length - 1)) return 0;
newsize = primes[++(h->primeindex)];
newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
if (NULL != newtable)
{
memset(newtable, 0, newsize * sizeof(struct entry *));
/* This algorithm is not 'stable'. ie. it reverses the list
* when it transfers entries between the tables */
for (i = 0; i < h->tablelength; i++) {
while (NULL != (e = h->table[i])) {
h->table[i] = e->next;
index = indexFor(newsize,e->h);
e->next = newtable[index];
newtable[index] = e;
}
}
free(h->table);
h->table = newtable;
}
/* Plan B: realloc instead */
else
{
newtable = (struct entry **)
realloc(h->table, newsize * sizeof(struct entry *));
if (NULL == newtable) { (h->primeindex)--; return 0; }
h->table = newtable;
memset(newtable[h->tablelength], 0, newsize - h->tablelength);
for (i = 0; i < h->tablelength; i++) {
for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
index = indexFor(newsize,e->h);
if (index == i)
{
pE = &(e->next);
}
else
{
*pE = e->next;
e->next = newtable[index];
newtable[index] = e;
}
}
}
}
h->tablelength = newsize;
h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
return -1;
}
/*****************************************************************************/
unsigned int
hashtable_count(struct hashtable *h)
{
return h->entrycount;
}
/*****************************************************************************/
int
hashtable_insert(struct hashtable *h, void *k, void *v)
{
/* This method allows duplicate keys - but they shouldn't be used */
unsigned int index;
struct entry *e;
if (++(h->entrycount) > h->loadlimit)
{
/* Ignore the return value. If expand fails, we should
* still try cramming just this value into the existing table
* -- we may not have memory for a larger table, but one more
* element may be ok. Next time we insert, we'll try expanding again.*/
hashtable_expand(h);
}
e = (struct entry *)malloc(sizeof(struct entry));
if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
e->h = hash(h,k);
index = indexFor(h->tablelength,e->h);
e->k = k;
e->v = v;
e->next = h->table[index];
h->table[index] = e;
return -1;
}
/*****************************************************************************/
void * /* returns value associated with key */
hashtable_search(struct hashtable *h, void *k)
{
struct entry *e;
unsigned int hashvalue, index;
hashvalue = hash(h,k);
index = indexFor(h->tablelength,hashvalue);
e = h->table[index];
while (NULL != e)
{
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
e = e->next;
}
return NULL;
}
/*****************************************************************************/
void * /* returns value associated with key */
hashtable_remove(struct hashtable *h, void *k)
{
/* TODO: consider compacting the table when the load factor drops enough,
* or provide a 'compact' method. */
struct entry *e;
struct entry **pE;
void *v;
unsigned int hashvalue, index;
hashvalue = hash(h,k);
index = indexFor(h->tablelength,hash(h,k));
pE = &(h->table[index]);
e = *pE;
while (NULL != e)
{
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
{
*pE = e->next;
h->entrycount--;
v = e->v;
freekey(e->k);
free(e);
return v;
}
pE = &(e->next);
e = e->next;
}
return NULL;
}
/*****************************************************************************/
/* destroy */
void
hashtable_destroy(struct hashtable *h, int free_values)
{
unsigned int i;
struct entry *e, *f;
struct entry **table = h->table;
if (free_values)
{
for (i = 0; i < h->tablelength; i++)
{
e = table[i];
while (NULL != e)
{ f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
}
}
else
{
for (i = 0; i < h->tablelength; i++)
{
e = table[i];
while (NULL != e)
{ f = e; e = e->next; freekey(f->k); free(f); }
}
}
free(h->table);
free(h);
}
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View File

@ -0,0 +1,209 @@
/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#ifndef __HASHTABLE_CWC22_H__
#define __HASHTABLE_CWC22_H__
#ifdef WIN32
#include "winconfig.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct hashtable;
/* Example of use:
*
* struct hashtable *h;
* struct some_key *k;
* struct some_value *v;
*
* static unsigned int hash_from_key_fn( void *k );
* static int keys_equal_fn ( void *key1, void *key2 );
*
* h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
* k = (struct some_key *) malloc(sizeof(struct some_key));
* v = (struct some_value *) malloc(sizeof(struct some_value));
*
* (initialise k and v to suitable values)
*
* if (! hashtable_insert(h,k,v) )
* { exit(-1); }
*
* if (NULL == (found = hashtable_search(h,k) ))
* { printf("not found!"); }
*
* if (NULL == (found = hashtable_remove(h,k) ))
* { printf("Not found\n"); }
*
*/
/* Macros may be used to define type-safe(r) hashtable access functions, with
* methods specialized to take known key and value types as parameters.
*
* Example:
*
* Insert this at the start of your file:
*
* DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
* DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
* DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
*
* This defines the functions 'insert_some', 'search_some' and 'remove_some'.
* These operate just like hashtable_insert etc., with the same parameters,
* but their function signatures have 'struct some_key *' rather than
* 'void *', and hence can generate compile time errors if your program is
* supplying incorrect data as a key (and similarly for value).
*
* Note that the hash and key equality functions passed to create_hashtable
* still take 'void *' parameters instead of 'some key *'. This shouldn't be
* a difficult issue as they're only defined and passed once, and the other
* functions will ensure that only valid keys are supplied to them.
*
* The cost for this checking is increased code size and runtime overhead
* - if performance is important, it may be worth switching back to the
* unsafe methods once your program has been debugged with the safe methods.
* This just requires switching to some simple alternative defines - eg:
* #define insert_some hashtable_insert
*
*/
/*****************************************************************************
* create_hashtable
* @name create_hashtable
* @param minsize minimum initial size of hashtable
* @param hashfunction function for hashing keys
* @param key_eq_fn function for determining key equality
* @return newly created hashtable or NULL on failure
*/
struct hashtable *
create_hashtable(unsigned int minsize,
unsigned int (*hashfunction) (void*),
int (*key_eq_fn) (void*,void*));
/*****************************************************************************
* hashtable_insert
* @name hashtable_insert
* @param h the hashtable to insert into
* @param k the key - hashtable claims ownership and will free on removal
* @param v the value - does not claim ownership
* @return non-zero for successful insertion
*
* This function will cause the table to expand if the insertion would take
* the ratio of entries to table size over the maximum load factor.
*
* This function does not check for repeated insertions with a duplicate key.
* The value returned when using a duplicate key is undefined -- when
* the hashtable changes size, the order of retrieval of duplicate key
* entries is reversed.
* If in doubt, remove before insert.
*/
int
hashtable_insert(struct hashtable *h, void *k, void *v);
#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
int fnname (struct hashtable *h, keytype *k, valuetype *v) \
{ \
return hashtable_insert(h,k,v); \
}
/*****************************************************************************
* hashtable_search
* @name hashtable_search
* @param h the hashtable to search
* @param k the key to search for - does not claim ownership
* @return the value associated with the key, or NULL if none found
*/
void *
hashtable_search(struct hashtable *h, void *k);
#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
valuetype * fnname (struct hashtable *h, keytype *k) \
{ \
return (valuetype *) (hashtable_search(h,k)); \
}
/*****************************************************************************
* hashtable_remove
* @name hashtable_remove
* @param h the hashtable to remove the item from
* @param k the key to search for - does not claim ownership
* @return the value associated with the key, or NULL if none found
*/
void * /* returns value */
hashtable_remove(struct hashtable *h, void *k);
#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
valuetype * fnname (struct hashtable *h, keytype *k) \
{ \
return (valuetype *) (hashtable_remove(h,k)); \
}
/*****************************************************************************
* hashtable_count
* @name hashtable_count
* @param h the hashtable
* @return the number of items stored in the hashtable
*/
unsigned int
hashtable_count(struct hashtable *h);
/*****************************************************************************
* hashtable_destroy
* @name hashtable_destroy
* @param h the hashtable
* @param free_values whether to call 'free' on the remaining values
*/
void
hashtable_destroy(struct hashtable *h, int free_values);
#ifdef __cplusplus
}
#endif
#endif /* __HASHTABLE_CWC22_H__ */
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View File

@ -0,0 +1,176 @@
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#include "hashtable.h"
#include "hashtable_private.h"
#include "hashtable_itr.h"
#include <stdlib.h> /* defines NULL */
/*****************************************************************************/
/* hashtable_iterator - iterator constructor */
struct hashtable_itr *
hashtable_iterator(struct hashtable *h)
{
unsigned int i, tablelength;
struct hashtable_itr *itr = (struct hashtable_itr *)
malloc(sizeof(struct hashtable_itr));
if (NULL == itr) return NULL;
itr->h = h;
itr->e = NULL;
itr->parent = NULL;
tablelength = h->tablelength;
itr->index = tablelength;
if (0 == h->entrycount) return itr;
for (i = 0; i < tablelength; i++)
{
if (NULL != h->table[i])
{
itr->e = h->table[i];
itr->index = i;
break;
}
}
return itr;
}
/*****************************************************************************/
/* advance - advance the iterator to the next element
* returns zero if advanced to end of table */
int
hashtable_iterator_advance(struct hashtable_itr *itr)
{
unsigned int j,tablelength;
struct entry **table;
struct entry *next;
if (NULL == itr->e) return 0; /* stupidity check */
next = itr->e->next;
if (NULL != next)
{
itr->parent = itr->e;
itr->e = next;
return -1;
}
tablelength = itr->h->tablelength;
itr->parent = NULL;
if (tablelength <= (j = ++(itr->index)))
{
itr->e = NULL;
return 0;
}
table = itr->h->table;
while (NULL == (next = table[j]))
{
if (++j >= tablelength)
{
itr->index = tablelength;
itr->e = NULL;
return 0;
}
}
itr->index = j;
itr->e = next;
return -1;
}
/*****************************************************************************/
/* remove - remove the entry at the current iterator position
* and advance the iterator, if there is a successive
* element.
* If you want the value, read it before you remove:
* beware memory leaks if you don't.
* Returns zero if end of iteration. */
int
hashtable_iterator_remove(struct hashtable_itr *itr)
{
struct entry *remember_e, *remember_parent;
int ret;
/* Do the removal */
if (NULL == (itr->parent))
{
/* element is head of a chain */
itr->h->table[itr->index] = itr->e->next;
} else {
/* element is mid-chain */
itr->parent->next = itr->e->next;
}
/* itr->e is now outside the hashtable */
remember_e = itr->e;
itr->h->entrycount--;
freekey(remember_e->k);
/* Advance the iterator, correcting the parent */
remember_parent = itr->parent;
ret = hashtable_iterator_advance(itr);
if (itr->parent == remember_e) { itr->parent = remember_parent; }
free(remember_e);
return ret;
}
/*****************************************************************************/
int /* returns zero if not found */
hashtable_iterator_search(struct hashtable_itr *itr,
struct hashtable *h, void *k)
{
struct entry *e, *parent;
unsigned int hashvalue, index;
hashvalue = hash(h,k);
index = indexFor(h->tablelength,hashvalue);
e = h->table[index];
parent = NULL;
while (NULL != e)
{
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
{
itr->index = index;
itr->e = e;
itr->parent = parent;
itr->h = h;
return -1;
}
parent = e;
e = e->next;
}
return 0;
}
/*
* Copyright (c) 2002, 2004, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View File

@ -0,0 +1,119 @@
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#ifndef __HASHTABLE_ITR_CWC22__
#define __HASHTABLE_ITR_CWC22__
#include "hashtable.h"
#include "hashtable_private.h" /* needed to enable inlining */
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************/
/* This struct is only concrete here to allow the inlining of two of the
* accessor functions. */
struct hashtable_itr
{
struct hashtable *h;
struct entry *e;
struct entry *parent;
unsigned int index;
};
/*****************************************************************************/
/* hashtable_iterator
*/
struct hashtable_itr *
hashtable_iterator(struct hashtable *h);
/*****************************************************************************/
/* hashtable_iterator_key
* - return the value of the (key,value) pair at the current position */
static inline void *
hashtable_iterator_key(struct hashtable_itr *i)
{
return i->e->k;
}
/*****************************************************************************/
/* value - return the value of the (key,value) pair at the current position */
static inline void *
hashtable_iterator_value(struct hashtable_itr *i)
{
return i->e->v;
}
/*****************************************************************************/
/* advance - advance the iterator to the next element
* returns zero if advanced to end of table */
int
hashtable_iterator_advance(struct hashtable_itr *itr);
/*****************************************************************************/
/* remove - remove current element and advance the iterator to the next element
* NB: if you need the value to free it, read it before
* removing. ie: beware memory leaks!
* returns zero if advanced to end of table */
int
hashtable_iterator_remove(struct hashtable_itr *itr);
/*****************************************************************************/
/* search - overwrite the supplied iterator, to point to the entry
* matching the supplied key.
h points to the hashtable to be searched.
* returns zero if not found. */
int
hashtable_iterator_search(struct hashtable_itr *itr,
struct hashtable *h, void *k);
#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
{ \
return (hashtable_iterator_search(i,h,k)); \
}
#ifdef __cplusplus
}
#endif
#endif /* __HASHTABLE_ITR_CWC22__*/
/*
* Copyright (c) 2002, 2004, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View File

@ -0,0 +1,85 @@
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#ifndef __HASHTABLE_PRIVATE_CWC22_H__
#define __HASHTABLE_PRIVATE_CWC22_H__
#include "hashtable.h"
/*****************************************************************************/
struct entry
{
void *k, *v;
unsigned int h;
struct entry *next;
};
struct hashtable {
unsigned int tablelength;
struct entry **table;
unsigned int entrycount;
unsigned int loadlimit;
unsigned int primeindex;
unsigned int (*hashfn) (void *k);
int (*eqfn) (void *k1, void *k2);
};
/*****************************************************************************/
unsigned int
hash(struct hashtable *h, void *k);
/*****************************************************************************/
/* indexFor */
static inline unsigned int
indexFor(unsigned int tablelength, unsigned int hashvalue) {
return (hashvalue % tablelength);
};
/* Only works if tablelength == 2^N */
/*static inline unsigned int
indexFor(unsigned int tablelength, unsigned int hashvalue)
{
return (hashvalue & (tablelength - 1u));
}
*/
/*****************************************************************************/
#define freekey(X) free(X)
/*define freekey(X) ; */
/*****************************************************************************/
#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View File

@ -0,0 +1,536 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef THREADED
#define THREADED
#endif
#ifndef DLL_EXPORT
# define USE_STATIC_LIB
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "zk_adaptor.h"
#include "zookeeper_log.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#ifndef WIN32
#include <signal.h>
#include <poll.h>
#include <unistd.h>
#include <sys/time.h>
#endif
int zoo_lock_auth(zhandle_t *zh)
{
return pthread_mutex_lock(&zh->auth_h.lock);
}
int zoo_unlock_auth(zhandle_t *zh)
{
return pthread_mutex_unlock(&zh->auth_h.lock);
}
int lock_buffer_list(buffer_head_t *l)
{
return pthread_mutex_lock(&l->lock);
}
int unlock_buffer_list(buffer_head_t *l)
{
return pthread_mutex_unlock(&l->lock);
}
int lock_completion_list(completion_head_t *l)
{
return pthread_mutex_lock(&l->lock);
}
int unlock_completion_list(completion_head_t *l)
{
pthread_cond_broadcast(&l->cond);
return pthread_mutex_unlock(&l->lock);
}
struct sync_completion *alloc_sync_completion(void)
{
struct sync_completion *sc = (struct sync_completion*)calloc(1, sizeof(struct sync_completion));
if (sc) {
pthread_cond_init(&sc->cond, 0);
pthread_mutex_init(&sc->lock, 0);
}
return sc;
}
int wait_sync_completion(struct sync_completion *sc)
{
pthread_mutex_lock(&sc->lock);
while (!sc->complete) {
pthread_cond_wait(&sc->cond, &sc->lock);
}
pthread_mutex_unlock(&sc->lock);
return 0;
}
void free_sync_completion(struct sync_completion *sc)
{
if (sc) {
pthread_mutex_destroy(&sc->lock);
pthread_cond_destroy(&sc->cond);
free(sc);
}
}
void notify_sync_completion(struct sync_completion *sc)
{
pthread_mutex_lock(&sc->lock);
sc->complete = 1;
pthread_cond_broadcast(&sc->cond);
pthread_mutex_unlock(&sc->lock);
}
int process_async(int outstanding_sync)
{
return 0;
}
#ifdef WIN32
unsigned __stdcall do_io( void * );
unsigned __stdcall do_completion( void * );
int handle_error(SOCKET sock, char* message)
{
LOG_ERROR(("%s. %d",message, WSAGetLastError()));
closesocket (sock);
return -1;
}
//--create socket pair for interupting selects.
int create_socket_pair(SOCKET fds[2])
{
struct sockaddr_in inaddr;
struct sockaddr addr;
int yes=1;
int len=0;
SOCKET lst=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
if (lst == INVALID_SOCKET ){
LOG_ERROR(("Error creating socket. %d",WSAGetLastError()));
return -1;
}
memset(&inaddr, 0, sizeof(inaddr));
memset(&addr, 0, sizeof(addr));
inaddr.sin_family = AF_INET;
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
inaddr.sin_port = 0; //--system assigns the port
if ( setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes)) == SOCKET_ERROR ) {
return handle_error(lst,"Error trying to set socket option.");
}
if (bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr)) == SOCKET_ERROR){
return handle_error(lst,"Error trying to bind socket.");
}
if (listen(lst,1) == SOCKET_ERROR){
return handle_error(lst,"Error trying to listen on socket.");
}
len=sizeof(inaddr);
getsockname(lst, &addr,&len);
fds[0]=socket(AF_INET, SOCK_STREAM,0);
if (connect(fds[0],&addr,len) == SOCKET_ERROR){
return handle_error(lst, "Error while connecting to socket.");
}
if ((fds[1]=accept(lst,0,0)) == INVALID_SOCKET){
closesocket(fds[0]);
return handle_error(lst, "Error while accepting socket connection.");
}
closesocket(lst);
return 0;
}
#else
void *do_io(void *);
void *do_completion(void *);
#endif
int wakeup_io_thread(zhandle_t *zh);
#ifdef WIN32
static int set_nonblock(SOCKET fd){
ULONG nonblocking_flag = 1;
if (ioctlsocket(fd, FIONBIO, &nonblocking_flag) == 0)
return 1;
else
return -1;
}
#else
static int set_nonblock(int fd){
long l = fcntl(fd, F_GETFL);
if(l & O_NONBLOCK) return 0;
return fcntl(fd, F_SETFL, l | O_NONBLOCK);
}
#endif
void wait_for_others(zhandle_t* zh)
{
struct adaptor_threads* adaptor=zh->adaptor_priv;
pthread_mutex_lock(&adaptor->lock);
while(adaptor->threadsToWait>0)
pthread_cond_wait(&adaptor->cond,&adaptor->lock);
pthread_mutex_unlock(&adaptor->lock);
}
void notify_thread_ready(zhandle_t* zh)
{
struct adaptor_threads* adaptor=zh->adaptor_priv;
pthread_mutex_lock(&adaptor->lock);
adaptor->threadsToWait--;
pthread_cond_broadcast(&adaptor->cond);
while(adaptor->threadsToWait>0)
pthread_cond_wait(&adaptor->cond,&adaptor->lock);
pthread_mutex_unlock(&adaptor->lock);
}
void start_threads(zhandle_t* zh)
{
int rc = 0;
struct adaptor_threads* adaptor=zh->adaptor_priv;
pthread_cond_init(&adaptor->cond,0);
pthread_mutex_init(&adaptor->lock,0);
adaptor->threadsToWait=2; // wait for 2 threads before opening the barrier
// use api_prolog() to make sure zhandle doesn't get destroyed
// while initialization is in progress
api_prolog(zh);
LOG_DEBUG(("starting threads..."));
rc=pthread_create(&adaptor->io, 0, do_io, zh);
assert("pthread_create() failed for the IO thread"&&!rc);
rc=pthread_create(&adaptor->completion, 0, do_completion, zh);
assert("pthread_create() failed for the completion thread"&&!rc);
wait_for_others(zh);
api_epilog(zh, 0);
}
int adaptor_init(zhandle_t *zh)
{
pthread_mutexattr_t recursive_mx_attr;
struct adaptor_threads *adaptor_threads = calloc(1, sizeof(*adaptor_threads));
if (!adaptor_threads) {
LOG_ERROR(("Out of memory"));
return -1;
}
/* We use a pipe for interrupting select() in unix/sol and socketpair in windows. */
#ifdef WIN32
if (create_socket_pair(adaptor_threads->self_pipe) == -1){
LOG_ERROR(("Can't make a socket."));
#else
if(pipe(adaptor_threads->self_pipe)==-1) {
LOG_ERROR(("Can't make a pipe %d",errno));
#endif
free(adaptor_threads);
return -1;
}
set_nonblock(adaptor_threads->self_pipe[1]);
set_nonblock(adaptor_threads->self_pipe[0]);
pthread_mutex_init(&zh->auth_h.lock,0);
zh->adaptor_priv = adaptor_threads;
pthread_mutex_init(&zh->to_process.lock,0);
pthread_mutex_init(&adaptor_threads->zh_lock,0);
// to_send must be recursive mutex
pthread_mutexattr_init(&recursive_mx_attr);
pthread_mutexattr_settype(&recursive_mx_attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&zh->to_send.lock,&recursive_mx_attr);
pthread_mutexattr_destroy(&recursive_mx_attr);
pthread_mutex_init(&zh->sent_requests.lock,0);
pthread_cond_init(&zh->sent_requests.cond,0);
pthread_mutex_init(&zh->completions_to_process.lock,0);
pthread_cond_init(&zh->completions_to_process.cond,0);
start_threads(zh);
return 0;
}
void adaptor_finish(zhandle_t *zh)
{
struct adaptor_threads *adaptor_threads;
// make sure zh doesn't get destroyed until after we're done here
api_prolog(zh);
adaptor_threads = zh->adaptor_priv;
if(adaptor_threads==0) {
api_epilog(zh,0);
return;
}
if(!pthread_equal(adaptor_threads->io,pthread_self())){
wakeup_io_thread(zh);
pthread_join(adaptor_threads->io, 0);
}else
pthread_detach(adaptor_threads->io);
if(!pthread_equal(adaptor_threads->completion,pthread_self())){
pthread_mutex_lock(&zh->completions_to_process.lock);
pthread_cond_broadcast(&zh->completions_to_process.cond);
pthread_mutex_unlock(&zh->completions_to_process.lock);
pthread_join(adaptor_threads->completion, 0);
}else
pthread_detach(adaptor_threads->completion);
api_epilog(zh,0);
}
void adaptor_destroy(zhandle_t *zh)
{
struct adaptor_threads *adaptor = zh->adaptor_priv;
if(adaptor==0) return;
pthread_cond_destroy(&adaptor->cond);
pthread_mutex_destroy(&adaptor->lock);
pthread_mutex_destroy(&zh->to_process.lock);
pthread_mutex_destroy(&zh->to_send.lock);
pthread_mutex_destroy(&zh->sent_requests.lock);
pthread_cond_destroy(&zh->sent_requests.cond);
pthread_mutex_destroy(&zh->completions_to_process.lock);
pthread_cond_destroy(&zh->completions_to_process.cond);
pthread_mutex_destroy(&adaptor->zh_lock);
pthread_mutex_destroy(&zh->auth_h.lock);
close(adaptor->self_pipe[0]);
close(adaptor->self_pipe[1]);
free(adaptor);
zh->adaptor_priv=0;
}
int wakeup_io_thread(zhandle_t *zh)
{
struct adaptor_threads *adaptor_threads = zh->adaptor_priv;
char c=0;
#ifndef WIN32
return write(adaptor_threads->self_pipe[1],&c,1)==1? ZOK: ZSYSTEMERROR;
#else
return send(adaptor_threads->self_pipe[1], &c, 1, 0)==1? ZOK: ZSYSTEMERROR;
#endif
}
int adaptor_send_queue(zhandle_t *zh, int timeout)
{
if(!zh->close_requested)
return wakeup_io_thread(zh);
// don't rely on the IO thread to send the messages if the app has
// requested to close
return flush_send_queue(zh, timeout);
}
/* These two are declared here because we will run the event loop
* and not the client */
#ifdef WIN32
int zookeeper_interest(zhandle_t *zh, SOCKET *fd, int *interest,
struct timeval *tv);
#else
int zookeeper_interest(zhandle_t *zh, int *fd, int *interest,
struct timeval *tv);
#endif
int zookeeper_process(zhandle_t *zh, int events);
#ifdef WIN32
unsigned __stdcall do_io( void * v)
#else
void *do_io(void *v)
#endif
{
zhandle_t *zh = (zhandle_t*)v;
#ifndef WIN32
struct pollfd fds[2];
struct adaptor_threads *adaptor_threads = zh->adaptor_priv;
api_prolog(zh);
notify_thread_ready(zh);
LOG_DEBUG(("started IO thread"));
fds[0].fd=adaptor_threads->self_pipe[0];
fds[0].events=POLLIN;
while(!zh->close_requested) {
struct timeval tv;
int fd;
int interest;
int timeout;
int maxfd=1;
int rc;
zookeeper_interest(zh, &fd, &interest, &tv);
if (fd != -1) {
fds[1].fd=fd;
fds[1].events=(interest&ZOOKEEPER_READ)?POLLIN:0;
fds[1].events|=(interest&ZOOKEEPER_WRITE)?POLLOUT:0;
maxfd=2;
}
timeout=tv.tv_sec * 1000 + (tv.tv_usec/1000);
poll(fds,maxfd,timeout);
if (fd != -1) {
interest=(fds[1].revents&POLLIN)?ZOOKEEPER_READ:0;
interest|=((fds[1].revents&POLLOUT)||(fds[1].revents&POLLHUP))?ZOOKEEPER_WRITE:0;
}
if(fds[0].revents&POLLIN){
// flush the pipe
char b[128];
while(read(adaptor_threads->self_pipe[0],b,sizeof(b))==sizeof(b)){}
}
#else
fd_set rfds, wfds, efds;
struct adaptor_threads *adaptor_threads = zh->adaptor_priv;
api_prolog(zh);
notify_thread_ready(zh);
LOG_DEBUG(("started IO thread"));
FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
while(!zh->close_requested) {
struct timeval tv;
SOCKET fd;
SOCKET maxfd=adaptor_threads->self_pipe[0];
int interest;
int rc;
zookeeper_interest(zh, &fd, &interest, &tv);
if (fd != -1) {
if (interest&ZOOKEEPER_READ) {
FD_SET(fd, &rfds);
} else {
FD_CLR(fd, &rfds);
}
if (interest&ZOOKEEPER_WRITE) {
FD_SET(fd, &wfds);
} else {
FD_CLR(fd, &wfds);
}
}
FD_SET( adaptor_threads->self_pipe[0] ,&rfds );
rc = select((int)maxfd, &rfds, &wfds, &efds, &tv);
if (fd != -1)
{
interest = (FD_ISSET(fd, &rfds))? ZOOKEEPER_READ:0;
interest|= (FD_ISSET(fd, &wfds))? ZOOKEEPER_WRITE:0;
}
if (FD_ISSET(adaptor_threads->self_pipe[0], &rfds)){
// flush the pipe/socket
char b[128];
while(recv(adaptor_threads->self_pipe[0],b,sizeof(b), 0)==sizeof(b)){}
}
#endif
// dispatch zookeeper events
rc = zookeeper_process(zh, interest);
// check the current state of the zhandle and terminate
// if it is_unrecoverable()
if(is_unrecoverable(zh))
break;
}
api_epilog(zh, 0);
LOG_DEBUG(("IO thread terminated"));
return 0;
}
#ifdef WIN32
unsigned __stdcall do_completion( void * v)
#else
void *do_completion(void *v)
#endif
{
zhandle_t *zh = v;
api_prolog(zh);
notify_thread_ready(zh);
LOG_DEBUG(("started completion thread"));
while(!zh->close_requested) {
pthread_mutex_lock(&zh->completions_to_process.lock);
while(!zh->completions_to_process.head && !zh->close_requested) {
pthread_cond_wait(&zh->completions_to_process.cond, &zh->completions_to_process.lock);
}
pthread_mutex_unlock(&zh->completions_to_process.lock);
process_completions(zh);
}
api_epilog(zh, 0);
LOG_DEBUG(("completion thread terminated"));
return 0;
}
int32_t inc_ref_counter(zhandle_t* zh,int i)
{
int incr=(i<0?-1:(i>0?1:0));
// fetch_and_add implements atomic post-increment
int v=fetch_and_add(&zh->ref_counter,incr);
// inc_ref_counter wants pre-increment
v+=incr; // simulate pre-increment
return v;
}
int32_t fetch_and_add(volatile int32_t* operand, int incr)
{
#ifndef WIN32
int32_t result;
asm __volatile__(
"lock xaddl %0,%1\n"
: "=r"(result), "=m"(*(int *)operand)
: "0"(incr)
: "memory");
return result;
#else
volatile int32_t result;
_asm
{
mov eax, operand; //eax = v;
mov ebx, incr; // ebx = i;
mov ecx, 0x0; // ecx = 0;
lock xadd dword ptr [eax], ecx;
lock xadd dword ptr [eax], ebx;
mov result, ecx; // result = ebx;
}
return result;
#endif
}
// make sure the static xid is initialized before any threads started
__attribute__((constructor)) int32_t get_xid()
{
static int32_t xid = -1;
if (xid == -1) {
xid = time(0);
}
return fetch_and_add(&xid,1);
}
int enter_critical(zhandle_t* zh)
{
struct adaptor_threads *adaptor = zh->adaptor_priv;
if (adaptor) {
return pthread_mutex_lock(&adaptor->zh_lock);
} else {
return 0;
}
}
int leave_critical(zhandle_t* zh)
{
struct adaptor_threads *adaptor = zh->adaptor_priv;
if (adaptor) {
return pthread_mutex_unlock(&adaptor->zh_lock);
} else {
return 0;
}
}

View File

@ -0,0 +1,360 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <recordio.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#ifndef WIN32
#include <netinet/in.h>
#endif
void deallocate_String(char **s)
{
if (*s)
free(*s);
*s = 0;
}
void deallocate_Buffer(struct buffer *b)
{
if (b->buff)
free(b->buff);
b->buff = 0;
}
struct buff_struct {
int32_t len;
int32_t off;
char *buffer;
};
static int resize_buffer(struct buff_struct *s, int newlen)
{
char *buffer= NULL;
while (s->len < newlen) {
s->len *= 2;
}
buffer = (char*)realloc(s->buffer, s->len);
if (!buffer) {
s->buffer = 0;
return -ENOMEM;
}
s->buffer = buffer;
return 0;
}
int oa_start_record(struct oarchive *oa, const char *tag)
{
return 0;
}
int oa_end_record(struct oarchive *oa, const char *tag)
{
return 0;
}
int oa_serialize_int(struct oarchive *oa, const char *tag, const int32_t *d)
{
struct buff_struct *priv = oa->priv;
int32_t i = htonl(*d);
if ((priv->len - priv->off) < sizeof(i)) {
int rc = resize_buffer(priv, priv->len + sizeof(i));
if (rc < 0) return rc;
}
memcpy(priv->buffer+priv->off, &i, sizeof(i));
priv->off+=sizeof(i);
return 0;
}
int64_t zoo_htonll(int64_t v)
{
int i = 0;
char *s = (char *)&v;
if (htonl(1) == 1) {
return v;
}
for (i = 0; i < 4; i++) {
int tmp = s[i];
s[i] = s[8-i-1];
s[8-i-1] = tmp;
}
return v;
}
int oa_serialize_long(struct oarchive *oa, const char *tag, const int64_t *d)
{
const int64_t i = zoo_htonll(*d);
struct buff_struct *priv = oa->priv;
if ((priv->len - priv->off) < sizeof(i)) {
int rc = resize_buffer(priv, priv->len + sizeof(i));
if (rc < 0) return rc;
}
memcpy(priv->buffer+priv->off, &i, sizeof(i));
priv->off+=sizeof(i);
return 0;
}
int oa_start_vector(struct oarchive *oa, const char *tag, const int32_t *count)
{
return oa_serialize_int(oa, tag, count);
}
int oa_end_vector(struct oarchive *oa, const char *tag)
{
return 0;
}
int oa_serialize_bool(struct oarchive *oa, const char *name, const int32_t *i)
{
//return oa_serialize_int(oa, name, i);
struct buff_struct *priv = oa->priv;
if ((priv->len - priv->off) < 1) {
int rc = resize_buffer(priv, priv->len + 1);
if (rc < 0)
return rc;
}
priv->buffer[priv->off] = (*i == 0 ? '\0' : '\1');
priv->off++;
return 0;
}
static const int32_t negone = -1;
int oa_serialize_buffer(struct oarchive *oa, const char *name,
const struct buffer *b)
{
struct buff_struct *priv = oa->priv;
int rc;
if (!b) {
return oa_serialize_int(oa, "len", &negone);
}
rc = oa_serialize_int(oa, "len", &b->len);
if (rc < 0)
return rc;
// this means a buffer of NUll
// with size of -1. This is
// waht we use in java serialization for NULL
if (b->len == -1) {
return rc;
}
if ((priv->len - priv->off) < b->len) {
rc = resize_buffer(priv, priv->len + b->len);
if (rc < 0)
return rc;
}
memcpy(priv->buffer+priv->off, b->buff, b->len);
priv->off += b->len;
return 0;
}
int oa_serialize_string(struct oarchive *oa, const char *name, char **s)
{
struct buff_struct *priv = oa->priv;
int32_t len;
int rc;
if (!*s) {
oa_serialize_int(oa, "len", &negone);
return 0;
}
len = strlen(*s);
rc = oa_serialize_int(oa, "len", &len);
if (rc < 0)
return rc;
if ((priv->len - priv->off) < len) {
rc = resize_buffer(priv, priv->len + len);
if (rc < 0)
return rc;
}
memcpy(priv->buffer+priv->off, *s, len);
priv->off += len;
return 0;
}
int ia_start_record(struct iarchive *ia, const char *tag)
{
return 0;
}
int ia_end_record(struct iarchive *ia, const char *tag)
{
return 0;
}
int ia_deserialize_int(struct iarchive *ia, const char *tag, int32_t *count)
{
struct buff_struct *priv = ia->priv;
if ((priv->len - priv->off) < sizeof(*count)) {
return -E2BIG;
}
memcpy(count, priv->buffer+priv->off, sizeof(*count));
priv->off+=sizeof(*count);
*count = ntohl(*count);
return 0;
}
int ia_deserialize_long(struct iarchive *ia, const char *tag, int64_t *count)
{
struct buff_struct *priv = ia->priv;
int64_t v = 0;
if ((priv->len - priv->off) < sizeof(*count)) {
return -E2BIG;
}
memcpy(count, priv->buffer+priv->off, sizeof(*count));
priv->off+=sizeof(*count);
v = zoo_htonll(*count); // htonll and ntohll do the same
*count = v;
return 0;
}
int ia_start_vector(struct iarchive *ia, const char *tag, int32_t *count)
{
return ia_deserialize_int(ia, tag, count);
}
int ia_end_vector(struct iarchive *ia, const char *tag)
{
return 0;
}
int ia_deserialize_bool(struct iarchive *ia, const char *name, int32_t *v)
{
struct buff_struct *priv = ia->priv;
//fprintf(stderr, "Deserializing bool %d\n", priv->off);
//return ia_deserialize_int(ia, name, v);
if ((priv->len - priv->off) < 1) {
return -E2BIG;
}
*v = priv->buffer[priv->off];
priv->off+=1;
//fprintf(stderr, "Deserializing bool end %d\n", priv->off);
return 0;
}
int ia_deserialize_buffer(struct iarchive *ia, const char *name,
struct buffer *b)
{
struct buff_struct *priv = ia->priv;
int rc = ia_deserialize_int(ia, "len", &b->len);
if (rc < 0)
return rc;
if ((priv->len - priv->off) < b->len) {
return -E2BIG;
}
// set the buffer to null
if (b->len == -1) {
b->buff = NULL;
return rc;
}
b->buff = malloc(b->len);
if (!b->buff) {
return -ENOMEM;
}
memcpy(b->buff, priv->buffer+priv->off, b->len);
priv->off += b->len;
return 0;
}
int ia_deserialize_string(struct iarchive *ia, const char *name, char **s)
{
struct buff_struct *priv = ia->priv;
int32_t len;
int rc = ia_deserialize_int(ia, "len", &len);
if (rc < 0)
return rc;
if ((priv->len - priv->off) < len) {
return -E2BIG;
}
if (len < 0) {
return -EINVAL;
}
*s = malloc(len+1);
if (!*s) {
return -ENOMEM;
}
memcpy(*s, priv->buffer+priv->off, len);
(*s)[len] = '\0';
priv->off += len;
return 0;
}
static struct iarchive ia_default = { STRUCT_INITIALIZER (start_record ,ia_start_record),
STRUCT_INITIALIZER (end_record ,ia_end_record), STRUCT_INITIALIZER (start_vector , ia_start_vector),
STRUCT_INITIALIZER (end_vector ,ia_end_vector), STRUCT_INITIALIZER (deserialize_Bool , ia_deserialize_bool),
STRUCT_INITIALIZER (deserialize_Int ,ia_deserialize_int),
STRUCT_INITIALIZER (deserialize_Long , ia_deserialize_long) ,
STRUCT_INITIALIZER (deserialize_Buffer, ia_deserialize_buffer),
STRUCT_INITIALIZER (deserialize_String, ia_deserialize_string) };
static struct oarchive oa_default = { STRUCT_INITIALIZER (start_record , oa_start_record),
STRUCT_INITIALIZER (end_record , oa_end_record), STRUCT_INITIALIZER (start_vector , oa_start_vector),
STRUCT_INITIALIZER (end_vector , oa_end_vector), STRUCT_INITIALIZER (serialize_Bool , oa_serialize_bool),
STRUCT_INITIALIZER (serialize_Int , oa_serialize_int),
STRUCT_INITIALIZER (serialize_Long , oa_serialize_long) ,
STRUCT_INITIALIZER (serialize_Buffer , oa_serialize_buffer),
STRUCT_INITIALIZER (serialize_String , oa_serialize_string) };
struct iarchive *create_buffer_iarchive(char *buffer, int len)
{
struct iarchive *ia = malloc(sizeof(*ia));
struct buff_struct *buff = malloc(sizeof(struct buff_struct));
if (!ia) return 0;
if (!buff) {
free(ia);
return 0;
}
*ia = ia_default;
buff->off = 0;
buff->buffer = buffer;
buff->len = len;
ia->priv = buff;
return ia;
}
struct oarchive *create_buffer_oarchive()
{
struct oarchive *oa = malloc(sizeof(*oa));
struct buff_struct *buff = malloc(sizeof(struct buff_struct));
if (!oa) return 0;
if (!buff) {
free(oa);
return 0;
}
*oa = oa_default;
buff->off = 0;
buff->buffer = malloc(128);
buff->len = 128;
oa->priv = buff;
return oa;
}
void close_buffer_iarchive(struct iarchive **ia)
{
free((*ia)->priv);
free(*ia);
*ia = 0;
}
void close_buffer_oarchive(struct oarchive **oa, int free_buffer)
{
if (free_buffer) {
struct buff_struct *buff = (struct buff_struct *)(*oa)->priv;
if (buff->buffer) {
free(buff->buffer);
}
}
free((*oa)->priv);
free(*oa);
*oa = 0;
}
char *get_buffer(struct oarchive *oa)
{
struct buff_struct *buff = oa->priv;
return buff->buffer;
}
int get_buffer_len(struct oarchive *oa)
{
struct buff_struct *buff = oa->priv;
return buff->off;
}

View File

@ -0,0 +1,113 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DLL_EXPORT
# define USE_STATIC_LIB
#endif
#include "zk_adaptor.h"
#include <stdlib.h>
#include <time.h>
int zoo_lock_auth(zhandle_t *zh)
{
return 0;
}
int zoo_unlock_auth(zhandle_t *zh)
{
return 0;
}
int lock_buffer_list(buffer_head_t *l)
{
return 0;
}
int unlock_buffer_list(buffer_head_t *l)
{
return 0;
}
int lock_completion_list(completion_head_t *l)
{
return 0;
}
int unlock_completion_list(completion_head_t *l)
{
return 0;
}
struct sync_completion *alloc_sync_completion(void)
{
return (struct sync_completion*)calloc(1, sizeof(struct sync_completion));
}
int wait_sync_completion(struct sync_completion *sc)
{
return 0;
}
void free_sync_completion(struct sync_completion *sc)
{
free(sc);
}
void notify_sync_completion(struct sync_completion *sc)
{
}
int process_async(int outstanding_sync)
{
return outstanding_sync == 0;
}
int adaptor_init(zhandle_t *zh)
{
return 0;
}
void adaptor_finish(zhandle_t *zh){}
void adaptor_destroy(zhandle_t *zh){}
int flush_send_queue(zhandle_t *, int);
int adaptor_send_queue(zhandle_t *zh, int timeout)
{
return flush_send_queue(zh, timeout);
}
int32_t inc_ref_counter(zhandle_t* zh,int i)
{
zh->ref_counter+=(i<0?-1:(i>0?1:0));
return zh->ref_counter;
}
int32_t get_xid()
{
static int32_t xid = -1;
if (xid == -1) {
xid = time(0);
}
return xid++;
}
int enter_critical(zhandle_t* zh)
{
return 0;
}
int leave_critical(zhandle_t* zh)
{
return 0;
}

View File

@ -0,0 +1,276 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ZK_ADAPTOR_H_
#define ZK_ADAPTOR_H_
#include <zookeeper.jute.h>
#ifdef THREADED
#ifndef WIN32
#include <pthread.h>
#else
#include "winport.h"
#endif
#endif
#include "zookeeper.h"
#include "zk_hashtable.h"
/* predefined xid's values recognized as special by the server */
#define WATCHER_EVENT_XID -1
#define PING_XID -2
#define AUTH_XID -4
#define SET_WATCHES_XID -8
/* zookeeper state constants */
#define EXPIRED_SESSION_STATE_DEF -112
#define AUTH_FAILED_STATE_DEF -113
#define CONNECTING_STATE_DEF 1
#define ASSOCIATING_STATE_DEF 2
#define CONNECTED_STATE_DEF 3
#define NOTCONNECTED_STATE_DEF 999
/* zookeeper event type constants */
#define CREATED_EVENT_DEF 1
#define DELETED_EVENT_DEF 2
#define CHANGED_EVENT_DEF 3
#define CHILD_EVENT_DEF 4
#define SESSION_EVENT_DEF -1
#define NOTWATCHING_EVENT_DEF -2
#ifdef __cplusplus
extern "C" {
#endif
struct _buffer_list;
struct _completion_list;
typedef struct _buffer_head {
struct _buffer_list *volatile head;
struct _buffer_list *last;
#ifdef THREADED
pthread_mutex_t lock;
#endif
} buffer_head_t;
typedef struct _completion_head {
struct _completion_list *volatile head;
struct _completion_list *last;
#ifdef THREADED
pthread_cond_t cond;
pthread_mutex_t lock;
#endif
} completion_head_t;
int lock_buffer_list(buffer_head_t *l);
int unlock_buffer_list(buffer_head_t *l);
int lock_completion_list(completion_head_t *l);
int unlock_completion_list(completion_head_t *l);
struct sync_completion {
int rc;
union {
struct {
char *str;
int str_len;
} str;
struct Stat stat;
struct {
char *buffer;
int buff_len;
struct Stat stat;
} data;
struct {
struct ACL_vector acl;
struct Stat stat;
} acl;
struct String_vector strs2;
struct {
struct String_vector strs2;
struct Stat stat2;
} strs_stat;
} u;
int complete;
#ifdef THREADED
pthread_cond_t cond;
pthread_mutex_t lock;
#endif
};
typedef struct _auth_info {
int state; /* 0=>inactive, >0 => active */
char* scheme;
struct buffer auth;
void_completion_t completion;
const char* data;
struct _auth_info *next;
} auth_info;
/**
* This structure represents a packet being read or written.
*/
typedef struct _buffer_list {
char *buffer;
int len; /* This represents the length of sizeof(header) + length of buffer */
int curr_offset; /* This is the offset into the header followed by offset into the buffer */
struct _buffer_list *next;
} buffer_list_t;
/* the size of connect request */
#define HANDSHAKE_REQ_SIZE 44
/* connect request */
struct connect_req {
int32_t protocolVersion;
int64_t lastZxidSeen;
int32_t timeOut;
int64_t sessionId;
int32_t passwd_len;
char passwd[16];
};
/* the connect response */
struct prime_struct {
int32_t len;
int32_t protocolVersion;
int32_t timeOut;
int64_t sessionId;
int32_t passwd_len;
char passwd[16];
};
#ifdef THREADED
/* this is used by mt_adaptor internally for thread management */
struct adaptor_threads {
pthread_t io;
pthread_t completion;
int threadsToWait; // barrier
pthread_cond_t cond; // barrier's conditional
pthread_mutex_t lock; // ... and a lock
pthread_mutex_t zh_lock; // critical section lock
#ifdef WIN32
SOCKET self_pipe[2];
#else
int self_pipe[2];
#endif
};
#endif
/** the auth list for adding auth */
typedef struct _auth_list_head {
auth_info *auth;
#ifdef THREADED
pthread_mutex_t lock;
#endif
} auth_list_head_t;
/**
* This structure represents the connection to zookeeper.
*/
struct _zhandle {
#ifdef WIN32
SOCKET fd; /* the descriptor used to talk to zookeeper */
#else
int fd; /* the descriptor used to talk to zookeeper */
#endif
char *hostname; /* the hostname of zookeeper */
struct sockaddr_storage *addrs; /* the addresses that correspond to the hostname */
int addrs_count; /* The number of addresses in the addrs array */
watcher_fn watcher; /* the registered watcher */
struct timeval last_recv; /* The time that the last message was received */
struct timeval last_send; /* The time that the last message was sent */
struct timeval last_ping; /* The time that the last PING was sent */
struct timeval next_deadline; /* The time of the next deadline */
int recv_timeout; /* The maximum amount of time that can go by without
receiving anything from the zookeeper server */
buffer_list_t *input_buffer; /* the current buffer being read in */
buffer_head_t to_process; /* The buffers that have been read and are ready to be processed. */
buffer_head_t to_send; /* The packets queued to send */
completion_head_t sent_requests; /* The outstanding requests */
completion_head_t completions_to_process; /* completions that are ready to run */
int connect_index; /* The index of the address to connect to */
clientid_t client_id;
long long last_zxid;
int outstanding_sync; /* Number of outstanding synchronous requests */
struct _buffer_list primer_buffer; /* The buffer used for the handshake at the start of a connection */
struct prime_struct primer_storage; /* the connect response */
char primer_storage_buffer[40]; /* the true size of primer_storage */
volatile int state;
void *context;
auth_list_head_t auth_h; /* authentication data list */
/* zookeeper_close is not reentrant because it de-allocates the zhandler.
* This guard variable is used to defer the destruction of zhandle till
* right before top-level API call returns to the caller */
int32_t ref_counter;
volatile int close_requested;
void *adaptor_priv;
/* Used for debugging only: non-zero value indicates the time when the zookeeper_process
* call returned while there was at least one unprocessed server response
* available in the socket recv buffer */
struct timeval socket_readable;
zk_hashtable* active_node_watchers;
zk_hashtable* active_exist_watchers;
zk_hashtable* active_child_watchers;
/** used for chroot path at the client side **/
char *chroot;
};
int adaptor_init(zhandle_t *zh);
void adaptor_finish(zhandle_t *zh);
void adaptor_destroy(zhandle_t *zh);
struct sync_completion *alloc_sync_completion(void);
int wait_sync_completion(struct sync_completion *sc);
void free_sync_completion(struct sync_completion *sc);
void notify_sync_completion(struct sync_completion *sc);
int adaptor_send_queue(zhandle_t *zh, int timeout);
int process_async(int outstanding_sync);
void process_completions(zhandle_t *zh);
int flush_send_queue(zhandle_t*zh, int timeout);
char* sub_string(zhandle_t *zh, const char* server_path);
void free_duplicate_path(const char* free_path, const char* path);
int zoo_lock_auth(zhandle_t *zh);
int zoo_unlock_auth(zhandle_t *zh);
// critical section guards
int enter_critical(zhandle_t* zh);
int leave_critical(zhandle_t* zh);
// zhandle object reference counting
void api_prolog(zhandle_t* zh);
int api_epilog(zhandle_t *zh, int rc);
int32_t get_xid();
// returns the new value of the ref counter
int32_t inc_ref_counter(zhandle_t* zh,int i);
#ifdef THREADED
// atomic post-increment
int32_t fetch_and_add(volatile int32_t* operand, int incr);
// in mt mode process session event asynchronously by the completion thread
#define PROCESS_SESSION_EVENT(zh,newstate) queue_session_event(zh,newstate)
#else
// in single-threaded mode process session event immediately
//#define PROCESS_SESSION_EVENT(zh,newstate) deliverWatchers(zh,ZOO_SESSION_EVENT,newstate,0)
#define PROCESS_SESSION_EVENT(zh,newstate) queue_session_event(zh,newstate)
#endif
#ifdef __cplusplus
}
#endif
#endif /*ZK_ADAPTOR_H_*/

View File

@ -0,0 +1,337 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "zk_hashtable.h"
#include "zk_adaptor.h"
#include "hashtable/hashtable.h"
#include "hashtable/hashtable_itr.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
typedef struct _watcher_object {
watcher_fn watcher;
void* context;
struct _watcher_object* next;
} watcher_object_t;
struct _zk_hashtable {
struct hashtable* ht;
};
struct watcher_object_list {
watcher_object_t* head;
};
/* the following functions are for testing only */
typedef struct hashtable hashtable_impl;
hashtable_impl* getImpl(zk_hashtable* ht){
return ht->ht;
}
watcher_object_t* getFirstWatcher(zk_hashtable* ht,const char* path)
{
watcher_object_list_t* wl=hashtable_search(ht->ht,(void*)path);
if(wl!=0)
return wl->head;
return 0;
}
/* end of testing functions */
watcher_object_t* clone_watcher_object(watcher_object_t* wo)
{
watcher_object_t* res=calloc(1,sizeof(watcher_object_t));
assert(res);
res->watcher=wo->watcher;
res->context=wo->context;
return res;
}
static unsigned int string_hash_djb2(void *str)
{
unsigned int hash = 5381;
int c;
const char* cstr = (const char*)str;
while ((c = *cstr++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
static int string_equal(void *key1,void *key2)
{
return strcmp((const char*)key1,(const char*)key2)==0;
}
static watcher_object_t* create_watcher_object(watcher_fn watcher,void* ctx)
{
watcher_object_t* wo=calloc(1,sizeof(watcher_object_t));
assert(wo);
wo->watcher=watcher;
wo->context=ctx;
return wo;
}
static watcher_object_list_t* create_watcher_object_list(watcher_object_t* head)
{
watcher_object_list_t* wl=calloc(1,sizeof(watcher_object_list_t));
assert(wl);
wl->head=head;
return wl;
}
static void destroy_watcher_object_list(watcher_object_list_t* list)
{
watcher_object_t* e = NULL;
if(list==0)
return;
e=list->head;
while(e!=0){
watcher_object_t* this=e;
e=e->next;
free(this);
}
free(list);
}
zk_hashtable* create_zk_hashtable()
{
struct _zk_hashtable *ht=calloc(1,sizeof(struct _zk_hashtable));
assert(ht);
ht->ht=create_hashtable(32,string_hash_djb2,string_equal);
return ht;
}
static void do_clean_hashtable(zk_hashtable* ht)
{
struct hashtable_itr *it;
int hasMore;
if(hashtable_count(ht->ht)==0)
return;
it=hashtable_iterator(ht->ht);
do {
watcher_object_list_t* w=hashtable_iterator_value(it);
destroy_watcher_object_list(w);
hasMore=hashtable_iterator_remove(it);
} while(hasMore);
free(it);
}
void destroy_zk_hashtable(zk_hashtable* ht)
{
if(ht!=0){
do_clean_hashtable(ht);
hashtable_destroy(ht->ht,0);
free(ht);
}
}
// searches for a watcher object instance in a watcher object list;
// two watcher objects are equal if their watcher function and context pointers
// are equal
static watcher_object_t* search_watcher(watcher_object_list_t** wl,watcher_object_t* wo)
{
watcher_object_t* wobj=(*wl)->head;
while(wobj!=0){
if(wobj->watcher==wo->watcher && wobj->context==wo->context)
return wobj;
wobj=wobj->next;
}
return 0;
}
static int add_to_list(watcher_object_list_t **wl, watcher_object_t *wo,
int clone)
{
if (search_watcher(wl, wo)==0) {
watcher_object_t* cloned=wo;
if (clone) {
cloned = clone_watcher_object(wo);
assert(cloned);
}
cloned->next = (*wl)->head;
(*wl)->head = cloned;
return 1;
} else if (!clone) {
// If it's here and we aren't supposed to clone, we must destroy
free(wo);
}
return 0;
}
static int do_insert_watcher_object(zk_hashtable *ht, const char *path, watcher_object_t* wo)
{
int res=1;
watcher_object_list_t* wl;
wl=hashtable_search(ht->ht,(void*)path);
if(wl==0){
int res;
/* inserting a new path element */
res=hashtable_insert(ht->ht,strdup(path),create_watcher_object_list(wo));
assert(res);
}else{
/*
* Path already exists; check if the watcher already exists.
* Don't clone the watcher since it's allocated on the heap --- avoids
* a memory leak and saves a clone operation (calloc + copy).
*/
res = add_to_list(&wl, wo, 0);
}
return res;
}
char **collect_keys(zk_hashtable *ht, int *count)
{
char **list;
struct hashtable_itr *it;
int i;
*count = hashtable_count(ht->ht);
list = calloc(*count, sizeof(char*));
it=hashtable_iterator(ht->ht);
for(i = 0; i < *count; i++) {
list[i] = strdup(hashtable_iterator_key(it));
hashtable_iterator_advance(it);
}
free(it);
return list;
}
static int insert_watcher_object(zk_hashtable *ht, const char *path,
watcher_object_t* wo)
{
int res;
res=do_insert_watcher_object(ht,path,wo);
return res;
}
static void copy_watchers(watcher_object_list_t *from, watcher_object_list_t *to, int clone)
{
watcher_object_t* wo=from->head;
while(wo){
watcher_object_t *next = wo->next;
add_to_list(&to, wo, clone);
wo=next;
}
}
static void copy_table(zk_hashtable *from, watcher_object_list_t *to) {
struct hashtable_itr *it;
int hasMore;
if(hashtable_count(from->ht)==0)
return;
it=hashtable_iterator(from->ht);
do {
watcher_object_list_t *w = hashtable_iterator_value(it);
copy_watchers(w, to, 1);
hasMore=hashtable_iterator_advance(it);
} while(hasMore);
free(it);
}
static void collect_session_watchers(zhandle_t *zh,
watcher_object_list_t **list)
{
copy_table(zh->active_node_watchers, *list);
copy_table(zh->active_exist_watchers, *list);
copy_table(zh->active_child_watchers, *list);
}
static void add_for_event(zk_hashtable *ht, char *path, watcher_object_list_t **list)
{
watcher_object_list_t* wl;
wl = (watcher_object_list_t*)hashtable_remove(ht->ht, path);
if (wl) {
copy_watchers(wl, *list, 0);
// Since we move, not clone the watch_objects, we just need to free the
// head pointer
free(wl);
}
}
static void do_foreach_watcher(watcher_object_t* wo,zhandle_t* zh,
const char* path,int type,int state)
{
// session event's don't have paths
const char *client_path =
(type != ZOO_SESSION_EVENT ? sub_string(zh, path) : path);
while(wo!=0){
wo->watcher(zh,type,state,client_path,wo->context);
wo=wo->next;
}
free_duplicate_path(client_path, path);
}
watcher_object_list_t *collectWatchers(zhandle_t *zh,int type, char *path)
{
struct watcher_object_list *list = create_watcher_object_list(0);
if(type==ZOO_SESSION_EVENT){
watcher_object_t defWatcher;
defWatcher.watcher=zh->watcher;
defWatcher.context=zh->context;
add_to_list(&list, &defWatcher, 1);
collect_session_watchers(zh, &list);
return list;
}
switch(type){
case CREATED_EVENT_DEF:
case CHANGED_EVENT_DEF:
// look up the watchers for the path and move them to a delivery list
add_for_event(zh->active_node_watchers,path,&list);
add_for_event(zh->active_exist_watchers,path,&list);
break;
case CHILD_EVENT_DEF:
// look up the watchers for the path and move them to a delivery list
add_for_event(zh->active_child_watchers,path,&list);
break;
case DELETED_EVENT_DEF:
// look up the watchers for the path and move them to a delivery list
add_for_event(zh->active_node_watchers,path,&list);
add_for_event(zh->active_exist_watchers,path,&list);
add_for_event(zh->active_child_watchers,path,&list);
break;
}
return list;
}
void deliverWatchers(zhandle_t *zh, int type,int state, char *path, watcher_object_list_t **list)
{
if (!list || !(*list)) return;
do_foreach_watcher((*list)->head, zh, path, type, state);
destroy_watcher_object_list(*list);
*list = 0;
}
void activateWatcher(zhandle_t *zh, watcher_registration_t* reg, int rc)
{
if(reg){
/* in multithreaded lib, this code is executed
* by the IO thread */
zk_hashtable *ht = reg->checker(zh, rc);
if(ht){
insert_watcher_object(ht,reg->path,
create_watcher_object(reg->watcher, reg->context));
}
}
}

View File

@ -0,0 +1,69 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ZK_HASHTABLE_H_
#define ZK_HASHTABLE_H_
#include <zookeeper.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct watcher_object_list watcher_object_list_t;
typedef struct _zk_hashtable zk_hashtable;
/**
* The function must return a non-zero value if the watcher object can be activated
* as a result of the server response. Normally, a watch can only be activated
* if the server returns a success code (ZOK). However in the case when zoo_exists()
* returns a ZNONODE code the watcher should be activated nevertheless.
*/
typedef zk_hashtable *(*result_checker_fn)(zhandle_t *, int rc);
/**
* A watcher object gets temporarily stored with the completion entry until
* the server response comes back at which moment the watcher object is moved
* to the active watchers map.
*/
typedef struct _watcher_registration {
watcher_fn watcher;
void* context;
result_checker_fn checker;
const char* path;
} watcher_registration_t;
zk_hashtable* create_zk_hashtable();
void destroy_zk_hashtable(zk_hashtable* ht);
char **collect_keys(zk_hashtable *ht, int *count);
/**
* check if the completion has a watcher object associated
* with it. If it does, move the watcher object to the map of
* active watchers (only if the checker allows to do so)
*/
void activateWatcher(zhandle_t *zh, watcher_registration_t* reg, int rc);
watcher_object_list_t *collectWatchers(zhandle_t *zh,int type, char *path);
void deliverWatchers(zhandle_t *zh, int type, int state, char *path, struct watcher_object_list **list);
#ifdef __cplusplus
}
#endif
#endif /*ZK_HASHTABLE_H_*/

View File

@ -0,0 +1,177 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DLL_EXPORT
# define USE_STATIC_LIB
#endif
#include "zookeeper_log.h"
#ifndef WIN32
#include <unistd.h>
#endif
#include <stdarg.h>
#include <time.h>
#define TIME_NOW_BUF_SIZE 1024
#define FORMAT_LOG_BUF_SIZE 4096
#ifdef THREADED
#ifndef WIN32
#include <pthread.h>
#else
#include "winport.h"
#endif
static pthread_key_t time_now_buffer;
static pthread_key_t format_log_msg_buffer;
void freeBuffer(void* p){
if(p) free(p);
}
__attribute__((constructor)) void prepareTSDKeys() {
pthread_key_create (&time_now_buffer, freeBuffer);
pthread_key_create (&format_log_msg_buffer, freeBuffer);
}
char* getTSData(pthread_key_t key,int size){
char* p=pthread_getspecific(key);
if(p==0){
int res;
p=calloc(1,size);
res=pthread_setspecific(key,p);
if(res!=0){
fprintf(stderr,"Failed to set TSD key: %d",res);
}
}
return p;
}
char* get_time_buffer(){
return getTSData(time_now_buffer,TIME_NOW_BUF_SIZE);
}
char* get_format_log_buffer(){
return getTSData(format_log_msg_buffer,FORMAT_LOG_BUF_SIZE);
}
#else
char* get_time_buffer(){
static char buf[TIME_NOW_BUF_SIZE];
return buf;
}
char* get_format_log_buffer(){
static char buf[FORMAT_LOG_BUF_SIZE];
return buf;
}
#endif
ZooLogLevel logLevel=ZOO_LOG_LEVEL_INFO;
static FILE* logStream=0;
FILE* getLogStream(){
if(logStream==0)
logStream=stderr;
return logStream;
}
void zoo_set_log_stream(FILE* stream){
logStream=stream;
}
static const char* time_now(char* now_str){
struct timeval tv;
struct tm lt;
time_t now = 0;
size_t len = 0;
gettimeofday(&tv,0);
now = tv.tv_sec;
localtime_r(&now, &lt);
// clone the format used by log4j ISO8601DateFormat
// specifically: "yyyy-MM-dd HH:mm:ss,SSS"
len = strftime(now_str, TIME_NOW_BUF_SIZE,
"%Y-%m-%d %H:%M:%S",
&lt);
len += snprintf(now_str + len,
TIME_NOW_BUF_SIZE - len,
",%03d",
(int)(tv.tv_usec/1000));
return now_str;
}
void log_message(ZooLogLevel curLevel,int line,const char* funcName,
const char* message)
{
static const char* dbgLevelStr[]={"ZOO_INVALID","ZOO_ERROR","ZOO_WARN",
"ZOO_INFO","ZOO_DEBUG"};
static pid_t pid=0;
#ifdef WIN32
char timebuf [TIME_NOW_BUF_SIZE];
#endif
if(pid==0)pid=getpid();
#ifndef THREADED
// pid_t is long on Solaris
fprintf(LOGSTREAM, "%s:%ld:%s@%s@%d: %s\n", time_now(get_time_buffer()),(long)pid,
dbgLevelStr[curLevel],funcName,line,message);
#else
#ifdef WIN32
fprintf(LOGSTREAM, "%s:%d(0x%lx):%s@%s@%d: %s\n", time_now(timebuf),pid,
(unsigned long int)(pthread_self().thread_id),
dbgLevelStr[curLevel],funcName,line,message);
#else
fprintf(LOGSTREAM, "%s:%ld(0x%lx):%s@%s@%d: %s\n", time_now(get_time_buffer()),(long)pid,
(unsigned long int)pthread_self(),
dbgLevelStr[curLevel],funcName,line,message);
#endif
#endif
fflush(LOGSTREAM);
}
const char* format_log_message(const char* format,...)
{
va_list va;
char* buf=get_format_log_buffer();
if(!buf)
return "format_log_message: Unable to allocate memory buffer";
va_start(va,format);
vsnprintf(buf, FORMAT_LOG_BUF_SIZE-1,format,va);
va_end(va);
return buf;
}
void zoo_set_debug_level(ZooLogLevel level)
{
if(level==0){
// disable logging (unit tests do this)
logLevel=(ZooLogLevel)0;
return;
}
if(level<ZOO_LOG_LEVEL_ERROR)level=ZOO_LOG_LEVEL_ERROR;
if(level>ZOO_LOG_LEVEL_DEBUG)level=ZOO_LOG_LEVEL_DEBUG;
logLevel=level;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,18 +12,19 @@ endif()
if (${DISABLE_MONGODB}) if (${DISABLE_MONGODB})
add_definitions(-D DISABLE_MONGODB) add_definitions(-D DISABLE_MONGODB)
else() else()
set (LINK_MONGOCLIENT libmongoclient.a libssl.a libcrypto.a) set (LINK_MONGOCLIENT libmongoclient.a libssl.a libcrypto.a libboost_thread.a)
endif() endif()
add_library(string_utils
include/DB/Common/StringUtils.h
src/Common/StringUtils.cpp)
add_library (dbms add_library (dbms
src/Server/OLAPAttributesMetadata.h
src/Server/InterserverIOHTTPHandler.h src/Server/InterserverIOHTTPHandler.h
src/Server/OLAPHTTPHandler.h
src/Server/OLAPQueryConverter.h
src/Server/Server.h src/Server/Server.h
src/Server/TCPHandler.h src/Server/TCPHandler.h
src/Server/HTTPHandler.h src/Server/HTTPHandler.h
src/Server/OLAPQueryParser.h
src/Server/MetricsTransmitter.h src/Server/MetricsTransmitter.h
src/Server/UsersConfigReloader.h src/Server/UsersConfigReloader.h
src/Server/StatusFile.h src/Server/StatusFile.h
@ -60,6 +61,7 @@ add_library (dbms
include/DB/Functions/FunctionsComparison.h include/DB/Functions/FunctionsComparison.h
include/DB/Functions/FunctionsHashing.h include/DB/Functions/FunctionsHashing.h
include/DB/Functions/FunctionsMath.h include/DB/Functions/FunctionsMath.h
include/DB/Functions/FunctionsGeo.h
include/DB/Functions/FunctionsMiscellaneous.h include/DB/Functions/FunctionsMiscellaneous.h
include/DB/Functions/FunctionsDateTime.h include/DB/Functions/FunctionsDateTime.h
include/DB/Functions/IFunction.h include/DB/Functions/IFunction.h
@ -67,6 +69,7 @@ add_library (dbms
include/DB/Functions/NumberTraits.h include/DB/Functions/NumberTraits.h
include/DB/Functions/DataTypeTraits.h include/DB/Functions/DataTypeTraits.h
include/DB/Functions/EnrichedDataTypePtr.h include/DB/Functions/EnrichedDataTypePtr.h
include/DB/Functions/ObjectPool.h
include/DB/TableFunctions/TableFunctionRemote.h include/DB/TableFunctions/TableFunctionRemote.h
include/DB/TableFunctions/TableFunctionFactory.h include/DB/TableFunctions/TableFunctionFactory.h
include/DB/TableFunctions/TableFunctionMerge.h include/DB/TableFunctions/TableFunctionMerge.h
@ -82,7 +85,6 @@ add_library (dbms
include/DB/Parsers/ASTExpressionList.h include/DB/Parsers/ASTExpressionList.h
include/DB/Parsers/ASTQueryWithOutput.h include/DB/Parsers/ASTQueryWithOutput.h
include/DB/Parsers/ParserSelectQuery.h include/DB/Parsers/ParserSelectQuery.h
include/DB/Parsers/ParserTableExpression.h
include/DB/Parsers/ParserUseQuery.h include/DB/Parsers/ParserUseQuery.h
include/DB/Parsers/ASTShowTablesQuery.h include/DB/Parsers/ASTShowTablesQuery.h
include/DB/Parsers/ASTFunction.h include/DB/Parsers/ASTFunction.h
@ -95,9 +97,7 @@ add_library (dbms
include/DB/Parsers/ASTSubquery.h include/DB/Parsers/ASTSubquery.h
include/DB/Parsers/ASTUseQuery.h include/DB/Parsers/ASTUseQuery.h
include/DB/Parsers/ASTIdentifier.h include/DB/Parsers/ASTIdentifier.h
include/DB/Parsers/ParserJoin.h
include/DB/Parsers/ParserTablePropertiesQuery.h include/DB/Parsers/ParserTablePropertiesQuery.h
include/DB/Parsers/ASTJoin.h
include/DB/Parsers/ParserCheckQuery.h include/DB/Parsers/ParserCheckQuery.h
include/DB/Parsers/ParserRenameQuery.h include/DB/Parsers/ParserRenameQuery.h
include/DB/Parsers/ParserInsertQuery.h include/DB/Parsers/ParserInsertQuery.h
@ -132,6 +132,8 @@ add_library (dbms
include/DB/Parsers/ASTSampleRatio.h include/DB/Parsers/ASTSampleRatio.h
include/DB/Parsers/ParserSampleRatio.h include/DB/Parsers/ParserSampleRatio.h
include/DB/Parsers/ParserCase.h include/DB/Parsers/ParserCase.h
include/DB/Parsers/ASTTablesInSelectQuery.h
include/DB/Parsers/ParserTablesInSelectQuery.h
include/DB/AggregateFunctions/AggregateFunctionMerge.h include/DB/AggregateFunctions/AggregateFunctionMerge.h
include/DB/AggregateFunctions/AggregateFunctionUniqUpTo.h include/DB/AggregateFunctions/AggregateFunctionUniqUpTo.h
include/DB/AggregateFunctions/AggregateFunctionIf.h include/DB/AggregateFunctions/AggregateFunctionIf.h
@ -265,6 +267,10 @@ add_library (dbms
include/DB/DataStreams/MarkInCompressedFile.h include/DB/DataStreams/MarkInCompressedFile.h
include/DB/DataStreams/CSVRowOutputStream.h include/DB/DataStreams/CSVRowOutputStream.h
include/DB/DataStreams/CSVRowInputStream.h include/DB/DataStreams/CSVRowInputStream.h
include/DB/DataStreams/verbosePrintString.h
include/DB/DataStreams/SquashingTransform.h
include/DB/DataStreams/SquashingBlockInputStream.h
include/DB/DataStreams/SquashingBlockOutputStream.h
include/DB/DataTypes/IDataType.h include/DB/DataTypes/IDataType.h
include/DB/DataTypes/IDataTypeDummy.h include/DB/DataTypes/IDataTypeDummy.h
include/DB/DataTypes/DataTypeSet.h include/DB/DataTypes/DataTypeSet.h
@ -316,7 +322,6 @@ add_library (dbms
include/DB/Interpreters/AggregationCommon.h include/DB/Interpreters/AggregationCommon.h
include/DB/Interpreters/ProcessList.h include/DB/Interpreters/ProcessList.h
include/DB/Interpreters/AggregateDescription.h include/DB/Interpreters/AggregateDescription.h
include/DB/Interpreters/reinterpretAsIdentifier.h
include/DB/Interpreters/Cluster.h include/DB/Interpreters/Cluster.h
include/DB/Interpreters/loadMetadata.h include/DB/Interpreters/loadMetadata.h
include/DB/Interpreters/ExternalDictionaries.h include/DB/Interpreters/ExternalDictionaries.h
@ -428,6 +433,9 @@ add_library (dbms
include/DB/Common/getNumberOfPhysicalCPUCores.h include/DB/Common/getNumberOfPhysicalCPUCores.h
include/DB/Common/BitHelpers.h include/DB/Common/BitHelpers.h
include/DB/Common/BlockFilterCreator.h include/DB/Common/BlockFilterCreator.h
include/DB/Common/randomSeed.h
include/DB/Common/unaligned.h
include/DB/Common/ThreadPool.h
include/DB/IO/CompressedStream.h include/DB/IO/CompressedStream.h
include/DB/IO/ReadBufferFromFileDescriptor.h include/DB/IO/ReadBufferFromFileDescriptor.h
include/DB/IO/CompressedWriteBuffer.h include/DB/IO/CompressedWriteBuffer.h
@ -597,6 +605,8 @@ add_library (dbms
src/Common/ShellCommand.cpp src/Common/ShellCommand.cpp
src/Common/isLocalAddress.cpp src/Common/isLocalAddress.cpp
src/Common/getNumberOfPhysicalCPUCores.cpp src/Common/getNumberOfPhysicalCPUCores.cpp
src/Common/randomSeed.cpp
src/Common/ThreadPool.cpp
src/Core/Field.cpp src/Core/Field.cpp
src/Core/FieldVisitors.cpp src/Core/FieldVisitors.cpp
@ -619,6 +629,7 @@ add_library (dbms
src/IO/ReadBufferFromFileBase.cpp src/IO/ReadBufferFromFileBase.cpp
src/IO/WriteBufferFromFileBase.cpp src/IO/WriteBufferFromFileBase.cpp
src/IO/InterserverWriteBuffer.cpp src/IO/InterserverWriteBuffer.cpp
src/IO/ReadBufferFromHTTP.cpp
src/Columns/ColumnConst.cpp src/Columns/ColumnConst.cpp
src/Columns/ColumnArray.cpp src/Columns/ColumnArray.cpp
@ -742,6 +753,10 @@ add_library (dbms
src/DataStreams/DistinctBlockInputStream.cpp src/DataStreams/DistinctBlockInputStream.cpp
src/DataStreams/RemoteBlockInputStream.cpp src/DataStreams/RemoteBlockInputStream.cpp
src/DataStreams/BlockIO.cpp src/DataStreams/BlockIO.cpp
src/DataStreams/verbosePrintString.cpp
src/DataStreams/SquashingTransform.cpp
src/DataStreams/SquashingBlockInputStream.cpp
src/DataStreams/SquashingBlockOutputStream.cpp
src/DataTypes/DataTypeString.cpp src/DataTypes/DataTypeString.cpp
src/DataTypes/DataTypeFixedString.cpp src/DataTypes/DataTypeFixedString.cpp
@ -771,6 +786,7 @@ add_library (dbms
src/Parsers/ASTWithAlias.cpp src/Parsers/ASTWithAlias.cpp
src/Parsers/ASTIdentifier.cpp src/Parsers/ASTIdentifier.cpp
src/Parsers/ASTSampleRatio.cpp src/Parsers/ASTSampleRatio.cpp
src/Parsers/ASTTablesInSelectQuery.cpp
src/Parsers/IAST.cpp src/Parsers/IAST.cpp
src/Parsers/IParserBase.cpp src/Parsers/IParserBase.cpp
src/Parsers/ExpressionElementParsers.cpp src/Parsers/ExpressionElementParsers.cpp
@ -778,8 +794,6 @@ add_library (dbms
src/Parsers/ParserQueryWithOutput.cpp src/Parsers/ParserQueryWithOutput.cpp
src/Parsers/ParserCreateQuery.cpp src/Parsers/ParserCreateQuery.cpp
src/Parsers/ParserSelectQuery.cpp src/Parsers/ParserSelectQuery.cpp
src/Parsers/ParserTableExpression.cpp
src/Parsers/ParserJoin.cpp
src/Parsers/ParserInsertQuery.cpp src/Parsers/ParserInsertQuery.cpp
src/Parsers/ParserDropQuery.cpp src/Parsers/ParserDropQuery.cpp
src/Parsers/ParserRenameQuery.cpp src/Parsers/ParserRenameQuery.cpp
@ -792,6 +806,7 @@ add_library (dbms
src/Parsers/ParserCheckQuery.cpp src/Parsers/ParserCheckQuery.cpp
src/Parsers/ParserSampleRatio.cpp src/Parsers/ParserSampleRatio.cpp
src/Parsers/ParserCase.cpp src/Parsers/ParserCase.cpp
src/Parsers/ParserTablesInSelectQuery.cpp
src/Parsers/formatAST.cpp src/Parsers/formatAST.cpp
src/Parsers/parseQuery.cpp src/Parsers/parseQuery.cpp
src/Parsers/queryToString.cpp src/Parsers/queryToString.cpp
@ -822,7 +837,6 @@ add_library (dbms
src/Interpreters/evaluateMissingDefaults.cpp src/Interpreters/evaluateMissingDefaults.cpp
src/Interpreters/evaluateConstantExpression.cpp src/Interpreters/evaluateConstantExpression.cpp
src/Interpreters/convertFieldToType.cpp src/Interpreters/convertFieldToType.cpp
src/Interpreters/reinterpretAsIdentifier.cpp
src/Interpreters/Set.cpp src/Interpreters/Set.cpp
src/Interpreters/Join.cpp src/Interpreters/Join.cpp
src/Interpreters/Quota.cpp src/Interpreters/Quota.cpp
@ -861,8 +875,10 @@ add_library (dbms
src/Functions/FunctionsURL.cpp src/Functions/FunctionsURL.cpp
src/Functions/FunctionsVisitParam.cpp src/Functions/FunctionsVisitParam.cpp
src/Functions/FunctionsMath.cpp src/Functions/FunctionsMath.cpp
src/Functions/FunctionsGeo.cpp
src/Functions/FunctionsMiscellaneous.cpp src/Functions/FunctionsMiscellaneous.cpp
src/Functions/FunctionsTransform.cpp src/Functions/FunctionsTransform.cpp
src/Functions/FunctionsCharset.cpp
src/Functions/Conditional/getArrayType.cpp src/Functions/Conditional/getArrayType.cpp
src/Functions/Conditional/ArgsInfo.cpp src/Functions/Conditional/ArgsInfo.cpp
src/Functions/Conditional/CondSource.cpp src/Functions/Conditional/CondSource.cpp
@ -902,6 +918,7 @@ add_library (dbms
src/Client/MultiplexedConnections.cpp src/Client/MultiplexedConnections.cpp
) )
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# Не генерируем отладочную информацию для файлов с большим количеством инстанцирований шаблонов # Не генерируем отладочную информацию для файлов с большим количеством инстанцирований шаблонов
# - для более быстрой линковки и меньшего размера бинарника. # - для более быстрой линковки и меньшего размера бинарника.
SET_SOURCE_FILES_PROPERTIES( SET_SOURCE_FILES_PROPERTIES(
@ -926,6 +943,7 @@ SET_SOURCE_FILES_PROPERTIES(
src/Functions/FunctionsURL.cpp src/Functions/FunctionsURL.cpp
src/Functions/FunctionsVisitParam.cpp src/Functions/FunctionsVisitParam.cpp
src/Functions/FunctionsMath.cpp src/Functions/FunctionsMath.cpp
src/Functions/FunctionsGeo.cpp
src/Functions/FunctionsMiscellaneous.cpp src/Functions/FunctionsMiscellaneous.cpp
src/Functions/FunctionsTransform.cpp src/Functions/FunctionsTransform.cpp
src/Dictionaries/FlatDictionary.cpp src/Dictionaries/FlatDictionary.cpp
@ -935,6 +953,7 @@ SET_SOURCE_FILES_PROPERTIES(
src/Dictionaries/ComplexKeyHashedDictionary.cpp src/Dictionaries/ComplexKeyHashedDictionary.cpp
src/Dictionaries/ComplexKeyCacheDictionary.cpp src/Dictionaries/ComplexKeyCacheDictionary.cpp
PROPERTIES COMPILE_FLAGS -g0) PROPERTIES COMPILE_FLAGS -g0)
endif()
IF (NOT AARCH64) IF (NOT AARCH64)
SET(LINK_LIBRARIES_ONLY_ON_X86_64 cpuid) SET(LINK_LIBRARIES_ONLY_ON_X86_64 cpuid)
@ -946,11 +965,11 @@ target_link_libraries(dbms
mysqlxx mysqlxx
cityhash farmhash metrohash cityhash farmhash metrohash
lz4 zstd lz4 zstd
string_utils
double-conversion double-conversion
${LINK_LIBRARIES_ONLY_ON_X86_64} ${LINK_LIBRARIES_ONLY_ON_X86_64}
re2 re2_st re2 re2_st
libcrypto.a libcrypto.a
libboost_thread.a
libboost_system.a libboost_system.a
${LINK_MONGOCLIENT} ${LINK_MONGOCLIENT}
libboost_regex.a libboost_regex.a

View File

@ -19,7 +19,7 @@ class AggregateFunctionArray final : public IAggregateFunction
private: private:
AggregateFunctionPtr nested_func_owner; AggregateFunctionPtr nested_func_owner;
IAggregateFunction * nested_func; IAggregateFunction * nested_func;
int num_agruments; size_t num_agruments;
public: public:
AggregateFunctionArray(AggregateFunctionPtr nested_) : nested_func_owner(nested_), nested_func(nested_func_owner.get()) {} AggregateFunctionArray(AggregateFunctionPtr nested_) : nested_func_owner(nested_), nested_func(nested_func_owner.get()) {}
@ -42,7 +42,7 @@ public:
throw Exception("Array aggregate functions requires at least one argument", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); throw Exception("Array aggregate functions requires at least one argument", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
DataTypes nested_arguments; DataTypes nested_arguments;
for (int i = 0; i < num_agruments; ++i) for (size_t i = 0; i < num_agruments; ++i)
{ {
if (const DataTypeArray * array = typeid_cast<const DataTypeArray *>(&*arguments[i])) if (const DataTypeArray * array = typeid_cast<const DataTypeArray *>(&*arguments[i]))
nested_arguments.push_back(array->getNestedType()); nested_arguments.push_back(array->getNestedType());
@ -87,7 +87,7 @@ public:
{ {
const IColumn * nested[num_agruments]; const IColumn * nested[num_agruments];
for (int i = 0; i < num_agruments; ++i) for (size_t i = 0; i < num_agruments; ++i)
nested[i] = &static_cast<const ColumnArray &>(*columns[i]).getData(); nested[i] = &static_cast<const ColumnArray &>(*columns[i]).getData();
const ColumnArray & first_array_column = static_cast<const ColumnArray &>(*columns[0]); const ColumnArray & first_array_column = static_cast<const ColumnArray &>(*columns[0]);

View File

@ -7,13 +7,16 @@
namespace DB namespace DB
{ {
/** Позволяет создать агрегатную функцию по её имени. /** Creates aggregate function by name.
*/ */
class AggregateFunctionFactory final class AggregateFunctionFactory final
{ {
friend class StorageSystemFunctions;
private: private:
/// Не std::function, так как меньше indirection и размер объекта. /// Not std::function, for lower object size and less indirection.
using Creator = AggregateFunctionPtr(*)(const std::string & name, const DataTypes & argument_types); using Creator = AggregateFunctionPtr(*)(const String & name, const DataTypes & argument_types);
using AggregateFunctions = std::unordered_map<String, Creator>;
public: public:
AggregateFunctionFactory(); AggregateFunctionFactory();
@ -21,45 +24,24 @@ public:
AggregateFunctionPtr tryGet(const String & name, const DataTypes & argument_types) const; AggregateFunctionPtr tryGet(const String & name, const DataTypes & argument_types) const;
bool isAggregateFunctionName(const String & name, int recursion_level = 0) const; bool isAggregateFunctionName(const String & name, int recursion_level = 0) const;
/// Зарегистрировать агрегатную функцию заданную по одному или нескольким названиям. /// For compatibility with SQL, it's possible to specify that certain aggregate function name is case insensitive.
void registerFunction(const std::vector<std::string> & names, Creator creator); enum CaseSensitiveness
{
CaseSensitive,
CaseInsensitive
};
/// Register aggregate function with its name.
void registerFunction(const String & name, Creator creator, CaseSensitiveness case_sensitiveness = CaseSensitive);
AggregateFunctionFactory(const AggregateFunctionFactory &) = delete; AggregateFunctionFactory(const AggregateFunctionFactory &) = delete;
AggregateFunctionFactory & operator=(const AggregateFunctionFactory &) = delete; AggregateFunctionFactory & operator=(const AggregateFunctionFactory &) = delete;
private:
struct Descriptor
{
Creator creator;
bool is_alias;
};
using AggregateFunctions = std::unordered_map<std::string, Descriptor>;
public:
struct Details
{
std::string name;
bool is_alias;
};
private:
/// Вспомогательная функция для реализации итератора (см. ниже).
static Details getDetails(const AggregateFunctions::value_type & entry);
public:
/** Итератор над агрегатными функциями. Возвращает объект типа Details.
* Этот итератор нужен для таблицы system.functions.
*/
using const_iterator = boost::transform_iterator<decltype(&AggregateFunctionFactory::getDetails),
typename AggregateFunctions::const_iterator>;
public:
const_iterator begin() const;
const_iterator end() const;
private: private:
AggregateFunctions aggregate_functions; AggregateFunctions aggregate_functions;
/// Case insensitive aggregate functions will be additionally added here with lowercased name.
AggregateFunctions case_insensitive_aggregate_functions;
}; };
} }

View File

@ -36,7 +36,8 @@ struct AggregateFunctionGroupUniqArrayData
/// Складывает все значения в хэш-множество. Возвращает массив уникальных значений. Реализована для числовых типов. /// Складывает все значения в хэш-множество. Возвращает массив уникальных значений. Реализована для числовых типов.
template <typename T> template <typename T>
class AggregateFunctionGroupUniqArray : public IUnaryAggregateFunction<AggregateFunctionGroupUniqArrayData<T>, AggregateFunctionGroupUniqArray<T> > class AggregateFunctionGroupUniqArray
: public IUnaryAggregateFunction<AggregateFunctionGroupUniqArrayData<T>, AggregateFunctionGroupUniqArray<T>>
{ {
private: private:
using State = AggregateFunctionGroupUniqArrayData<T>; using State = AggregateFunctionGroupUniqArrayData<T>;

View File

@ -19,7 +19,7 @@ class AggregateFunctionIf final : public IAggregateFunction
private: private:
AggregateFunctionPtr nested_func_owner; AggregateFunctionPtr nested_func_owner;
IAggregateFunction * nested_func; IAggregateFunction * nested_func;
int num_agruments; size_t num_agruments;
public: public:
AggregateFunctionIf(AggregateFunctionPtr nested_) : nested_func_owner(nested_), nested_func(nested_func_owner.get()) {} AggregateFunctionIf(AggregateFunctionPtr nested_) : nested_func_owner(nested_), nested_func(nested_func_owner.get()) {}
@ -42,7 +42,7 @@ public:
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
DataTypes nested_arguments; DataTypes nested_arguments;
for (int i = 0; i < num_agruments - 1; i ++) for (size_t i = 0; i < num_agruments - 1; i ++)
nested_arguments.push_back(arguments[i]); nested_arguments.push_back(arguments[i]);
nested_func->setArguments(nested_arguments); nested_func->setArguments(nested_arguments);
} }

View File

@ -8,6 +8,7 @@
#include <boost/range/iterator_range_core.hpp> #include <boost/range/iterator_range_core.hpp>
#include <DB/Parsers/ExpressionElementParsers.h> #include <DB/Parsers/ExpressionElementParsers.h>
#include <DB/Parsers/ASTLiteral.h> #include <DB/Parsers/ASTLiteral.h>
#include <DB/Common/PODArray.h>
#include <bitset> #include <bitset>
#include <stack> #include <stack>
@ -44,7 +45,8 @@ struct AggregateFunctionSequenceMatchData final
using Comparator = ComparePairFirst<std::less>; using Comparator = ComparePairFirst<std::less>;
bool sorted = true; bool sorted = true;
std::vector<TimestampEvents> eventsList; static constexpr size_t bytes_in_arena = 64;
PODArray<TimestampEvents, bytes_in_arena, AllocatorWithStackMemory<Allocator<false>, bytes_in_arena>> eventsList;
void add(const Timestamp timestamp, const Events & events) void add(const Timestamp timestamp, const Events & events)
{ {
@ -60,7 +62,7 @@ struct AggregateFunctionSequenceMatchData final
{ {
const auto size = eventsList.size(); const auto size = eventsList.size();
eventsList.insert(std::end(eventsList), std::begin(other.eventsList), std::end(other.eventsList)); eventsList.insert(std::begin(other.eventsList), std::end(other.eventsList));
/// either sort whole container or do so partially merging ranges afterwards /// either sort whole container or do so partially merging ranges afterwards
if (!sorted && !other.sorted) if (!sorted && !other.sorted)
@ -111,7 +113,7 @@ struct AggregateFunctionSequenceMatchData final
std::size_t size; std::size_t size;
readBinary(size, buf); readBinary(size, buf);
decltype(eventsList) eventsList; eventsList.clear();
eventsList.reserve(size); eventsList.reserve(size);
for (std::size_t i = 0; i < size; ++i) for (std::size_t i = 0; i < size; ++i)
@ -124,8 +126,6 @@ struct AggregateFunctionSequenceMatchData final
eventsList.emplace_back(timestamp, Events{events}); eventsList.emplace_back(timestamp, Events{events});
} }
this->eventsList = std::move(eventsList);
} }
}; };
@ -262,14 +262,14 @@ private:
PatternAction(const PatternActionType type, const std::uint32_t extra = 0) : type{type}, extra{extra} {} PatternAction(const PatternActionType type, const std::uint32_t extra = 0) : type{type}, extra{extra} {}
}; };
using PatternActions = std::vector<PatternAction>; static constexpr size_t bytes_on_stack = 64;
using PatternActions = PODArray<PatternAction, bytes_on_stack, AllocatorWithStackMemory<Allocator<false>, bytes_on_stack>>;
void parsePattern() void parsePattern()
{ {
PatternActions actions{ actions.clear();
{ PatternActionType::KleeneStar } actions.emplace_back(PatternActionType::KleeneStar);
};
ParserString special_open_p("(?"); ParserString special_open_p("(?");
ParserString special_close_p(")"); ParserString special_close_p(")");
@ -354,8 +354,6 @@ private:
else else
throw_exception("Could not parse pattern, unexpected starting symbol"); throw_exception("Could not parse pattern, unexpected starting symbol");
} }
this->actions = std::move(actions);
} }
protected: protected:

View File

@ -7,7 +7,6 @@
#include <DB/IO/WriteHelpers.h> #include <DB/IO/WriteHelpers.h>
#include <DB/IO/ReadHelpers.h> #include <DB/IO/ReadHelpers.h>
#include <DB/IO/WriteBufferFromString.h>
#include <DB/DataTypes/DataTypesNumberFixed.h> #include <DB/DataTypes/DataTypesNumberFixed.h>
#include <DB/DataTypes/DataTypeString.h> #include <DB/DataTypes/DataTypeString.h>

View File

@ -62,6 +62,7 @@ struct SingleValueDataFixed
value = static_cast<const ColumnVector<T> &>(column).getData()[row_num]; value = static_cast<const ColumnVector<T> &>(column).getData()[row_num];
} }
/// Assuming to.has()
void change(const Self & to) void change(const Self & to)
{ {
has_value = true; has_value = true;
@ -81,7 +82,24 @@ struct SingleValueDataFixed
bool changeFirstTime(const Self & to) bool changeFirstTime(const Self & to)
{ {
if (!has()) if (!has() && to.has())
{
change(to);
return true;
}
else
return false;
}
bool changeEveryTime(const IColumn & column, size_t row_num)
{
change(column, row_num);
return true;
}
bool changeEveryTime(const Self & to)
{
if (to.has())
{ {
change(to); change(to);
return true; return true;
@ -133,6 +151,16 @@ struct SingleValueDataFixed
else else
return false; return false;
} }
bool isEqualTo(const Self & to) const
{
return has() && to.value == value;
}
bool isEqualTo(const IColumn & column, size_t row_num) const
{
return has() && static_cast<const ColumnVector<T> &>(column).getData()[row_num] == value;
}
}; };
@ -229,7 +257,7 @@ struct __attribute__((__packed__, __aligned__(1))) SingleValueDataString
} }
} }
/// Assuming to.has()
void changeImpl(StringRef value) void changeImpl(StringRef value)
{ {
Int32 value_size = value.size; Int32 value_size = value.size;
@ -282,7 +310,24 @@ struct __attribute__((__packed__, __aligned__(1))) SingleValueDataString
bool changeFirstTime(const Self & to) bool changeFirstTime(const Self & to)
{ {
if (!has()) if (!has() && to.has())
{
change(to);
return true;
}
else
return false;
}
bool changeEveryTime(const IColumn & column, size_t row_num)
{
change(column, row_num);
return true;
}
bool changeEveryTime(const Self & to)
{
if (to.has())
{ {
change(to); change(to);
return true; return true;
@ -334,6 +379,16 @@ struct __attribute__((__packed__, __aligned__(1))) SingleValueDataString
else else
return false; return false;
} }
bool isEqualTo(const Self & to) const
{
return has() && to.getStringRef() == getStringRef();
}
bool isEqualTo(const IColumn & column, size_t row_num) const
{
return has() && static_cast<const ColumnString &>(column).getDataAtWithTerminatingZero(row_num) == getStringRef();
}
}; };
static_assert( static_assert(
@ -404,7 +459,24 @@ struct SingleValueDataGeneric
bool changeFirstTime(const Self & to) bool changeFirstTime(const Self & to)
{ {
if (!has()) if (!has() && to.has())
{
change(to);
return true;
}
else
return false;
}
bool changeEveryTime(const IColumn & column, size_t row_num)
{
change(column, row_num);
return true;
}
bool changeEveryTime(const Self & to)
{
if (to.has())
{ {
change(to); change(to);
return true; return true;
@ -476,6 +548,16 @@ struct SingleValueDataGeneric
else else
return false; return false;
} }
bool isEqualTo(const IColumn & column, size_t row_num) const
{
return has() && value == column[row_num];
}
bool isEqualTo(const Self & to) const
{
return has() && to.value == value;
}
}; };
@ -522,13 +604,80 @@ struct AggregateFunctionAnyLastData : Data
{ {
using Self = AggregateFunctionAnyLastData<Data>; using Self = AggregateFunctionAnyLastData<Data>;
bool changeIfBetter(const IColumn & column, size_t row_num) { this->change(column, row_num); return true; } bool changeIfBetter(const IColumn & column, size_t row_num) { return this->changeEveryTime(column, row_num); }
bool changeIfBetter(const Self & to) { this->change(to); return true; } bool changeIfBetter(const Self & to) { return this->changeEveryTime(to); }
static const char * name() { return "anyLast"; } static const char * name() { return "anyLast"; }
}; };
/** Implement 'heavy hitters' algorithm.
* Selects most frequent value if its frequency is more than 50% in each thread of execution.
* Otherwise, selects some arbitary value.
* http://www.cs.umd.edu/~samir/498/karp.pdf
*/
template <typename Data>
struct AggregateFunctionAnyHeavyData : Data
{
size_t counter = 0;
using Self = AggregateFunctionAnyHeavyData<Data>;
bool changeIfBetter(const IColumn & column, size_t row_num)
{
if (this->isEqualTo(column, row_num))
{
++counter;
}
else
{
if (counter == 0)
{
this->change(column, row_num);
++counter;
return true;
}
else
--counter;
}
return false;
}
bool changeIfBetter(const Self & to)
{
if (this->isEqualTo(to))
{
counter += to.counter;
}
else
{
if (counter < to.counter)
{
this->change(to);
return true;
}
else
counter -= to.counter;
}
return false;
}
void write(WriteBuffer & buf, const IDataType & data_type) const
{
Data::write(buf, data_type);
writeBinary(counter, buf);
}
void read(ReadBuffer & buf, const IDataType & data_type)
{
Data::read(buf, data_type);
readBinary(counter, buf);
}
static const char * name() { return "anyHeavy"; }
};
template <typename Data> template <typename Data>
class AggregateFunctionsSingleValue final : public IUnaryAggregateFunction<Data, AggregateFunctionsSingleValue<Data> > class AggregateFunctionsSingleValue final : public IUnaryAggregateFunction<Data, AggregateFunctionsSingleValue<Data> >
{ {

View File

@ -88,16 +88,14 @@ struct UniqVariadicHash<true, false>
{ {
static inline UInt128 apply(size_t num_args, const IColumn ** columns, size_t row_num) static inline UInt128 apply(size_t num_args, const IColumn ** columns, size_t row_num)
{ {
SipHash hash;
const IColumn ** column = columns; const IColumn ** column = columns;
const IColumn ** columns_end = column + num_args; const IColumn ** columns_end = column + num_args;
SipHash hash;
while (column < columns_end) while (column < columns_end)
{ {
StringRef value = (*column)->getDataAt(row_num); (*column)->updateHashWithValue(row_num, hash);
hash.update(reinterpret_cast<const char *>(&value.size), sizeof(value.size));
hash.update(value.data, value.size);
++column; ++column;
} }
@ -112,18 +110,16 @@ struct UniqVariadicHash<true, true>
{ {
static inline UInt128 apply(size_t num_args, const IColumn ** columns, size_t row_num) static inline UInt128 apply(size_t num_args, const IColumn ** columns, size_t row_num)
{ {
SipHash hash;
const Columns & tuple_columns = static_cast<const ColumnTuple *>(columns[0])->getColumns(); const Columns & tuple_columns = static_cast<const ColumnTuple *>(columns[0])->getColumns();
const ColumnPtr * column = tuple_columns.data(); const ColumnPtr * column = tuple_columns.data();
const ColumnPtr * columns_end = column + num_args; const ColumnPtr * columns_end = column + num_args;
SipHash hash;
while (column < columns_end) while (column < columns_end)
{ {
StringRef value = column->get()->getDataAt(row_num); (*column)->updateHashWithValue(row_num, hash);
hash.update(reinterpret_cast<const char *>(&value.size), sizeof(value.size));
hash.update(value.data, value.size);
++column; ++column;
} }

View File

@ -35,12 +35,12 @@ using ConnectionPtr = std::shared_ptr<Connection>;
using Connections = std::vector<ConnectionPtr>; using Connections = std::vector<ConnectionPtr>;
/** Соединение с сервером БД для использования в клиенте. /** Connection with database server, to use by client.
* Как использовать - см. Core/Protocol.h * How to use - see Core/Protocol.h
* (Реализацию на стороне сервера - см. Server/TCPHandler.h) * (Implementation of server end - see Server/TCPHandler.h)
* *
* В качестве default_database может быть указана пустая строка * As 'default_database' empty string could be passed
* - в этом случае сервер использует свою БД по-умолчанию. * - in that case, server will use it's own default database.
*/ */
class Connection : private boost::noncopyable class Connection : private boost::noncopyable
{ {
@ -65,7 +65,7 @@ public:
ping_timeout(ping_timeout_), ping_timeout(ping_timeout_),
log_wrapper(*this) log_wrapper(*this)
{ {
/// Соединеняемся не сразу, а при первой необходимости. /// Don't connect immediately, only on first need.
if (user.empty()) if (user.empty())
user = "default"; user = "default";
@ -93,7 +93,7 @@ public:
ping_timeout(ping_timeout_), ping_timeout(ping_timeout_),
log_wrapper(*this) log_wrapper(*this)
{ {
/// Соединеняемся не сразу, а при первой необходимости. /// Don't connect immediately, only on first need.
if (user.empty()) if (user.empty())
user = "default"; user = "default";
@ -103,14 +103,14 @@ public:
virtual ~Connection() {}; virtual ~Connection() {};
/// Установить ограничитель сетевого трафика. Один ограничитель может использоваться одновременно для нескольких разных соединений. /// Set throttler of network traffic. One throttler could be used for multiple connections to limit total traffic.
void setThrottler(const ThrottlerPtr & throttler_) void setThrottler(const ThrottlerPtr & throttler_)
{ {
throttler = throttler_; throttler = throttler_;
} }
/// Пакет, который может быть получен от сервера. /// Packet that could be received from server.
struct Packet struct Packet
{ {
UInt64 type; UInt64 type;
@ -123,46 +123,46 @@ public:
Packet() : type(Protocol::Server::Hello) {} Packet() : type(Protocol::Server::Hello) {}
}; };
/// Изменить базу данных по умолчанию. Изменения начинают использоваться только при следующем переподключении. /// Change default database. Changes will take effect on next reconnect.
void setDefaultDatabase(const String & database); void setDefaultDatabase(const String & database);
void getServerVersion(String & name, UInt64 & version_major, UInt64 & version_minor, UInt64 & revision); void getServerVersion(String & name, UInt64 & version_major, UInt64 & version_minor, UInt64 & revision);
/// Для сообщений в логе и в эксепшенах. /// For log and exception messages.
const String & getDescription() const; const String & getDescription() const;
const String & getHost() const; const String & getHost() const;
UInt16 getPort() const; UInt16 getPort() const;
const String & getDefaultDatabase() const; const String & getDefaultDatabase() const;
/// Если последний флаг true, то затем необходимо вызвать sendExternalTablesData /// If last flag is true, you need to call sendExternalTablesData after.
void sendQuery(const String & query, const String & query_id_ = "", UInt64 stage = QueryProcessingStage::Complete, void sendQuery(const String & query, const String & query_id_ = "", UInt64 stage = QueryProcessingStage::Complete,
const Settings * settings = nullptr, bool with_pending_data = false); const Settings * settings = nullptr, bool with_pending_data = false);
void sendCancel(); void sendCancel();
/// Отправить блок данных, на сервере сохранить во временную таблицу name /// Send block of data; if name is specified, server will write it to external (temporary) table of that name.
void sendData(const Block & block, const String & name = ""); void sendData(const Block & block, const String & name = "");
/// Отправить все содержимое внешних таблиц /// Send all contents of external (temporary) tables.
void sendExternalTablesData(ExternalTablesData & data); void sendExternalTablesData(ExternalTablesData & data);
/// Отправить блок данных, который уже был заранее сериализован (и, если надо, сжат), который следует прочитать из input-а. /// Send prepared block of data (serialized and, if need, compressed), that will be read from 'input'.
/// можно передать размер сериализованного/сжатого блока. /// You could pass size of serialized/compressed block.
void sendPreparedData(ReadBuffer & input, size_t size, const String & name = ""); void sendPreparedData(ReadBuffer & input, size_t size, const String & name = "");
/// Проверить, есть ли данные, которые можно прочитать. /// Check, if has data to read.
bool poll(size_t timeout_microseconds = 0); bool poll(size_t timeout_microseconds = 0);
/// Проверить, есть ли данные в буфере для чтения. /// Check, if has data in read buffer.
bool hasReadBufferPendingData() const; bool hasReadBufferPendingData() const;
/// Получить пакет от сервера. /// Receive packet from server.
Packet receivePacket(); Packet receivePacket();
/// Если ещё не соединено, или соединение разорвано - соединиться. Если не получилось - кинуть исключение. /// If not connected yet, or if connection is broken - then connect. If cannot connect - throw an exception.
void forceConnected(); void forceConnected();
/** Разорвать соединение. /** Disconnect.
* Это может быть нужно, например, чтобы соединение не осталось висеть в * This may be used, if connection is left in unsynchronised state
* рассинхронизированном состоянии (когда кто-то чего-то продолжает ждать) после эксепшена. * (when someone continues to wait for something) after an exception.
*/ */
void disconnect(); void disconnect();
@ -181,8 +181,8 @@ private:
String user; String user;
String password; String password;
/** Адрес может быть заранее отрезолвен и передан в конструктор. Тогда поля host и port имеют смысл только для логгирования. /** Address could be resolved beforehand and passed to constructor. Then 'host' and 'port' fields are used just for logging.
* Иначе адрес резолвится в конструкторе. То есть, DNS балансировка не поддерживается. * Otherwise address is resolved in constructor. Thus, DNS based load balancing is not supported.
*/ */
Poco::Net::SocketAddress resolved_address; Poco::Net::SocketAddress resolved_address;
@ -204,12 +204,12 @@ private:
std::shared_ptr<WriteBuffer> out; std::shared_ptr<WriteBuffer> out;
String query_id; String query_id;
UInt64 compression; /// Сжимать ли данные при взаимодействии с сервером. UInt64 compression; /// Enable data compression for communication.
/// каким алгоритмом сжимать данные при INSERT и данные внешних таблиц /// What compression algorithm to use while sending data for INSERT queries and external tables.
CompressionMethod network_compression_method = CompressionMethod::LZ4; CompressionMethod network_compression_method = CompressionMethod::LZ4;
/** Если не nullptr, то используется, чтобы ограничить сетевой трафик. /** If not nullptr, used to limit network traffic.
* Учитывается только трафик при передаче блоков. Другие пакеты не учитываются. * Only traffic for transferring blocks is accounted. Other packets don't.
*/ */
ThrottlerPtr throttler; ThrottlerPtr throttler;
@ -218,15 +218,15 @@ private:
Poco::Timespan send_timeout; Poco::Timespan send_timeout;
Poco::Timespan ping_timeout; Poco::Timespan ping_timeout;
/// Откуда читать результат выполнения запроса. /// From where to read query execution result.
std::shared_ptr<ReadBuffer> maybe_compressed_in; std::shared_ptr<ReadBuffer> maybe_compressed_in;
BlockInputStreamPtr block_in; BlockInputStreamPtr block_in;
/// Куда писать данные INSERT-а. /// Where to write data for INSERT.
std::shared_ptr<WriteBuffer> maybe_compressed_out; std::shared_ptr<WriteBuffer> maybe_compressed_out;
BlockOutputStreamPtr block_out; BlockOutputStreamPtr block_out;
/// логгер, создаваемый лениво, чтобы не обращаться к DNS в конструкторе /// Logger is created lazily, for avoid to run DNS request in constructor.
class LoggerWrapper class LoggerWrapper
{ {
public: public:

View File

@ -61,7 +61,7 @@ private:
/// Источник. Используется (удерживает источник от уничтожения), /// Источник. Используется (удерживает источник от уничтожения),
/// если данный столбец создан из другого и использует все или часть его значений. /// если данный столбец создан из другого и использует все или часть его значений.
const std::shared_ptr<const ColumnAggregateFunction> src; std::shared_ptr<const ColumnAggregateFunction> src;
/// Массив указателей на состояния агрегатных функций, расположенных в пулах. /// Массив указателей на состояния агрегатных функций, расположенных в пулах.
Container_t data; Container_t data;
@ -201,6 +201,11 @@ public:
throw Exception("Method deserializeAndInsertFromArena is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED); throw Exception("Method deserializeAndInsertFromArena is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
} }
void updateHashWithValue(size_t n, SipHash & hash) const override
{
throw Exception("Method updateHashWithValue is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
}
size_t byteSize() const override size_t byteSize() const override
{ {
size_t res = getData().size() * sizeof(getData()[0]); size_t res = getData().size() * sizeof(getData()[0]);
@ -211,21 +216,31 @@ public:
return res; return res;
} }
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override void insertRangeFrom(const IColumn & from, size_t start, size_t length) override
{ {
const ColumnAggregateFunction & src_concrete = static_cast<const ColumnAggregateFunction &>(src); const ColumnAggregateFunction & from_concrete = static_cast<const ColumnAggregateFunction &>(from);
if (start + length > src_concrete.getData().size()) if (start + length > from_concrete.getData().size())
throw Exception("Parameters start = " throw Exception("Parameters start = "
+ toString(start) + ", length = " + toString(start) + ", length = "
+ toString(length) + " are out of bound in ColumnAggregateFunction::insertRangeFrom method" + toString(length) + " are out of bound in ColumnAggregateFunction::insertRangeFrom method"
" (data.size() = " + toString(src_concrete.getData().size()) + ").", " (data.size() = " + toString(from_concrete.getData().size()) + ").",
ErrorCodes::PARAMETER_OUT_OF_BOUND); ErrorCodes::PARAMETER_OUT_OF_BOUND);
if (src && src.get() != &from_concrete)
{
throw Exception("ColumnAggregateFunction could have only one source that owns aggregation states", ErrorCodes::BAD_ARGUMENTS);
}
else
{
/// Keep shared ownership of aggregation states.
src = from_concrete.shared_from_this();
}
auto & data = getData(); auto & data = getData();
size_t old_size = data.size(); size_t old_size = data.size();
data.resize(old_size + length); data.resize(old_size + length);
memcpy(&data[old_size], &src_concrete.getData()[start], length * sizeof(data[0])); memcpy(&data[old_size], &from_concrete.getData()[start], length * sizeof(data[0]));
} }
void popBack(size_t n) override void popBack(size_t n) override

View File

@ -4,6 +4,7 @@
#include <DB/Common/Exception.h> #include <DB/Common/Exception.h>
#include <DB/Common/Arena.h> #include <DB/Common/Arena.h>
#include <DB/Common/SipHash.h>
#include <DB/Columns/IColumn.h> #include <DB/Columns/IColumn.h>
#include <DB/Columns/ColumnsNumber.h> #include <DB/Columns/ColumnsNumber.h>
@ -149,6 +150,16 @@ public:
return pos; return pos;
} }
void updateHashWithValue(size_t n, SipHash & hash) const override
{
size_t array_size = sizeAt(n);
size_t offset = offsetAt(n);
hash.update(reinterpret_cast<const char *>(&array_size), sizeof(array_size));
for (size_t i = 0; i < array_size; ++i)
getData().updateHashWithValue(offset + i, hash);
}
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override; void insertRangeFrom(const IColumn & src, size_t start, size_t length) override;
void insert(const Field & x) override void insert(const Field & x) override
@ -179,6 +190,7 @@ public:
{ {
auto & offsets = getOffsets(); auto & offsets = getOffsets();
size_t nested_n = offsets.back() - offsetAt(offsets.size() - n); size_t nested_n = offsets.back() - offsetAt(offsets.size() - n);
if (nested_n)
getData().popBack(nested_n); getData().popBack(nested_n);
offsets.resize_assume_reserved(offsets.size() - n); offsets.resize_assume_reserved(offsets.size() - n);
} }

View File

@ -136,6 +136,11 @@ public:
throw Exception("Method deserializeAndInsertFromArena is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED); throw Exception("Method deserializeAndInsertFromArena is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
} }
void updateHashWithValue(size_t n, SipHash & hash) const override
{
throw Exception("Method updateHashWithValue is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
}
ColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override ColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override
{ {
if (s != filt.size()) if (s != filt.size())
@ -289,6 +294,9 @@ public:
/** Преобразование из константы в полноценный столбец */ /** Преобразование из константы в полноценный столбец */
ColumnPtr convertToFullColumn() const override; ColumnPtr convertToFullColumn() const override;
/** Create ColumnTuple of constant columns as elements. */
ColumnPtr convertToTupleOfConstants() const;
void getExtremes(Field & min, Field & max) const override; void getExtremes(Field & min, Field & max) const override;
}; };

View File

@ -4,6 +4,7 @@
#include <DB/Common/PODArray.h> #include <DB/Common/PODArray.h>
#include <DB/Common/Arena.h> #include <DB/Common/Arena.h>
#include <DB/Common/SipHash.h>
#include <DB/Common/memcpySmall.h> #include <DB/Common/memcpySmall.h>
#include <DB/Columns/IColumn.h> #include <DB/Columns/IColumn.h>
#include <DB/IO/ReadHelpers.h> #include <DB/IO/ReadHelpers.h>
@ -143,6 +144,11 @@ public:
return pos + n; return pos + n;
} }
void updateHashWithValue(size_t index, SipHash & hash) const override
{
hash.update(reinterpret_cast<const char *>(&chars[n * index]), n);
}
int compareAt(size_t p1, size_t p2, const IColumn & rhs_, int nan_direction_hint) const override int compareAt(size_t p1, size_t p2, const IColumn & rhs_, int nan_direction_hint) const override
{ {
const ColumnFixedString & rhs = static_cast<const ColumnFixedString &>(rhs_); const ColumnFixedString & rhs = static_cast<const ColumnFixedString &>(rhs_);

View File

@ -9,6 +9,7 @@
#include <DB/Common/Collator.h> #include <DB/Common/Collator.h>
#include <DB/Common/PODArray.h> #include <DB/Common/PODArray.h>
#include <DB/Common/Arena.h> #include <DB/Common/Arena.h>
#include <DB/Common/SipHash.h>
#include <DB/Common/memcpySmall.h> #include <DB/Common/memcpySmall.h>
@ -85,43 +86,71 @@ public:
void insert(const Field & x) override void insert(const Field & x) override
{ {
const String & s = DB::get<const String &>(x); const String & s = DB::get<const String &>(x);
size_t old_size = chars.size(); const size_t old_size = chars.size();
size_t size_to_append = s.size() + 1; const size_t size_to_append = s.size() + 1;
const size_t new_size = old_size + size_to_append;
chars.resize(old_size + size_to_append); chars.resize(new_size);
memcpy(&chars[old_size], s.c_str(), size_to_append); memcpy(&chars[old_size], s.c_str(), size_to_append);
offsets.push_back((offsets.size() == 0 ? 0 : offsets.back()) + size_to_append); offsets.push_back(new_size);
} }
void insertFrom(const IColumn & src_, size_t n) override void insertFrom(const IColumn & src_, size_t n) override
{ {
const ColumnString & src = static_cast<const ColumnString &>(src_); const ColumnString & src = static_cast<const ColumnString &>(src_);
size_t old_size = chars.size();
size_t size_to_append = src.sizeAt(n);
size_t offset = src.offsetAt(n);
chars.resize(old_size + size_to_append); if (n != 0)
{
const size_t size_to_append = src.offsets[n] - src.offsets[n - 1];
if (size_to_append == 1)
{
/// shortcut for empty string
chars.push_back(0);
offsets.push_back(chars.size());
}
else
{
const size_t old_size = chars.size();
const size_t offset = src.offsets[n - 1];
const size_t new_size = old_size + size_to_append;
chars.resize(new_size);
memcpySmallAllowReadWriteOverflow15(&chars[old_size], &src.chars[offset], size_to_append); memcpySmallAllowReadWriteOverflow15(&chars[old_size], &src.chars[offset], size_to_append);
offsets.push_back((offsets.size() == 0 ? 0 : offsets.back()) + size_to_append); offsets.push_back(new_size);
}
}
else
{
const size_t old_size = chars.size();
const size_t size_to_append = src.offsets[0];
const size_t new_size = old_size + size_to_append;
chars.resize(new_size);
memcpySmallAllowReadWriteOverflow15(&chars[old_size], &src.chars[0], size_to_append);
offsets.push_back(new_size);
}
} }
void insertData(const char * pos, size_t length) override void insertData(const char * pos, size_t length) override
{ {
size_t old_size = chars.size(); const size_t old_size = chars.size();
const size_t new_size = old_size + length + 1;
chars.resize(old_size + length + 1); chars.resize(new_size);
memcpy(&chars[old_size], pos, length); memcpy(&chars[old_size], pos, length);
chars[old_size + length] = 0; chars[old_size + length] = 0;
offsets.push_back((offsets.size() == 0 ? 0 : offsets.back()) + length + 1); offsets.push_back(new_size);
} }
void insertDataWithTerminatingZero(const char * pos, size_t length) override void insertDataWithTerminatingZero(const char * pos, size_t length) override
{ {
size_t old_size = chars.size(); const size_t old_size = chars.size();
const size_t new_size = old_size + length;
chars.resize(old_size + length); chars.resize(new_size);
memcpy(&chars[old_size], pos, length); memcpy(&chars[old_size], pos, length);
offsets.push_back((offsets.size() == 0 ? 0 : offsets.back()) + length); offsets.push_back(new_size);
} }
void popBack(size_t n) override void popBack(size_t n) override
@ -148,17 +177,27 @@ public:
const char * deserializeAndInsertFromArena(const char * pos) override const char * deserializeAndInsertFromArena(const char * pos) override
{ {
size_t string_size = *reinterpret_cast<const size_t *>(pos); const size_t string_size = *reinterpret_cast<const size_t *>(pos);
pos += sizeof(string_size); pos += sizeof(string_size);
size_t old_size = chars.size(); const size_t old_size = chars.size();
chars.resize(old_size + string_size); const size_t new_size = old_size + string_size;
chars.resize(new_size);
memcpy(&chars[old_size], pos, string_size); memcpy(&chars[old_size], pos, string_size);
offsets.push_back((offsets.size() == 0 ? 0 : offsets.back()) + string_size); offsets.push_back(new_size);
return pos + string_size; return pos + string_size;
} }
void updateHashWithValue(size_t n, SipHash & hash) const override
{
size_t string_size = sizeAt(n);
size_t offset = offsetAt(n);
hash.update(reinterpret_cast<const char *>(&string_size), sizeof(string_size));
hash.update(reinterpret_cast<const char *>(&chars[offset]), string_size);
}
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override void insertRangeFrom(const IColumn & src, size_t start, size_t length) override
{ {
if (length == 0) if (length == 0)

View File

@ -15,7 +15,11 @@ namespace ErrorCodes
} }
/** Столбец, который всего лишь группирует вместе несколько других столбцов. /** Column, that is just group of few another columns.
*
* For constant Tuples, see ColumnConstTuple.
* Mixed constant/non-constant columns is prohibited in tuple
* for implementation simplicity.
*/ */
class ColumnTuple final : public IColumn class ColumnTuple final : public IColumn
{ {
@ -124,6 +128,12 @@ public:
return pos; return pos;
} }
void updateHashWithValue(size_t n, SipHash & hash) const override
{
for (auto & column : columns)
column->updateHashWithValue(n, hash);
}
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override void insertRangeFrom(const IColumn & src, size_t start, size_t length) override
{ {
for (size_t i = 0; i < columns.size(); ++i) for (size_t i = 0; i < columns.size(); ++i)

View File

@ -5,6 +5,7 @@
#include <DB/Common/Exception.h> #include <DB/Common/Exception.h>
#include <DB/Common/Arena.h> #include <DB/Common/Arena.h>
#include <DB/Common/SipHash.h>
#include <DB/IO/WriteBuffer.h> #include <DB/IO/WriteBuffer.h>
#include <DB/IO/WriteHelpers.h> #include <DB/IO/WriteHelpers.h>
@ -182,6 +183,11 @@ public:
return pos + sizeof(T); return pos + sizeof(T);
} }
void updateHashWithValue(size_t n, SipHash & hash) const override
{
hash.update(reinterpret_cast<const char *>(&data[n]), sizeof(T));
}
size_t byteSize() const override size_t byteSize() const override
{ {
return data.size() * sizeof(data[0]); return data.size() * sizeof(data[0]);
@ -259,6 +265,16 @@ public:
res = typename NearestFieldType<T>::Type(data[n]); res = typename NearestFieldType<T>::Type(data[n]);
} }
const T & getElement(size_t n) const
{
return data[n];
}
T & getElement(size_t n)
{
return data[n];
}
UInt64 get64(size_t n) const override UInt64 get64(size_t n) const override
{ {
return unionCastToUInt64(data[n]); return unionCastToUInt64(data[n]);

View File

@ -10,6 +10,9 @@
#include <DB/Core/StringRef.h> #include <DB/Core/StringRef.h>
class SipHash;
namespace DB namespace DB
{ {
@ -162,7 +165,8 @@ public:
/** Удалить одно или несколько значений с конца. /** Удалить одно или несколько значений с конца.
* Используется, чтобы сделать некоторые операции exception-safe, * Используется, чтобы сделать некоторые операции exception-safe,
* когда после вставки значения сделать что-то ещё не удалось, и нужно откатить вставку. * когда после вставки значения сделать что-то ещё не удалось, и нужно откатить вставку.
* Если столбец пуст - поведение не определено. * Если столбец имеет меньше n значений - поведение не определено.
* Если n == 0 - поведение не определено.
*/ */
virtual void popBack(size_t n) = 0; virtual void popBack(size_t n) = 0;
@ -180,10 +184,11 @@ public:
*/ */
virtual const char * deserializeAndInsertFromArena(const char * pos) = 0; virtual const char * deserializeAndInsertFromArena(const char * pos) = 0;
/** Соединить столбец с одним или несколькими другими. /** Update state of hash function with value at index n.
* Используется при склейке маленьких блоков. * On subsequent calls of this method for sequence of column values of arbitary types,
* passed bytes to hash must identify sequence of values unambiguously.
*/ */
//virtual void merge(const Columns & columns) = 0; virtual void updateHashWithValue(size_t n, SipHash & hash) const = 0;
/** Оставить только значения, соответствующие фильтру. /** Оставить только значения, соответствующие фильтру.
* Используется для операции WHERE / HAVING. * Используется для операции WHERE / HAVING.

View File

@ -48,6 +48,11 @@ public:
throw Exception("Method deserializeAndInsertFromArena is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED); throw Exception("Method deserializeAndInsertFromArena is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
} }
void updateHashWithValue(size_t n, SipHash & hash) const override
{
throw Exception("Method updateHashWithValue is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
}
void getExtremes(Field & min, Field & max) const override void getExtremes(Field & min, Field & max) const override
{ {
throw Exception("Method getExtremes is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED); throw Exception("Method getExtremes is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);

View File

@ -78,14 +78,14 @@ class AIOContextPool : public Singleton<AIOContextPool>
AIOContext aio_context{max_concurrent_events}; AIOContext aio_context{max_concurrent_events};
using id_t = size_t; using ID = size_t;
using bytes_read_t = ssize_t; using BytesRead = ssize_t;
/// Autoincremental id used to identify completed requests /// Autoincremental id used to identify completed requests
id_t id{}; ID id{};
mutable std::mutex mutex; mutable std::mutex mutex;
mutable std::condition_variable have_resources; mutable std::condition_variable have_resources;
std::map<id_t, std::promise<bytes_read_t>> promises; std::map<ID, std::promise<BytesRead>> promises;
std::atomic<bool> cancelled{false}; std::atomic<bool> cancelled{false};
std::thread io_completion_monitor{&AIOContextPool::doMonitor, this}; std::thread io_completion_monitor{&AIOContextPool::doMonitor, this};
@ -188,7 +188,7 @@ class AIOContextPool : public Singleton<AIOContextPool>
public: public:
/// Request AIO read operation for iocb, returns a future with number of bytes read /// Request AIO read operation for iocb, returns a future with number of bytes read
std::future<bytes_read_t> post(struct iocb & iocb) std::future<BytesRead> post(struct iocb & iocb)
{ {
std::unique_lock<std::mutex> lock{mutex}; std::unique_lock<std::mutex> lock{mutex};
@ -196,7 +196,7 @@ public:
const auto request_id = id++; const auto request_id = id++;
/// create a promise and put request in "queue" /// create a promise and put request in "queue"
promises.emplace(request_id, std::promise<bytes_read_t>{}); promises.emplace(request_id, std::promise<BytesRead>{});
/// store id in AIO request for further identification /// store id in AIO request for further identification
iocb.aio_data = request_id; iocb.aio_data = request_id;

View File

@ -164,6 +164,12 @@ public:
return buf; return buf;
} }
protected:
static constexpr size_t getStackThreshold()
{
return 0;
}
}; };
@ -209,6 +215,12 @@ public:
memcpy(new_buf, buf, old_size); memcpy(new_buf, buf, old_size);
return new_buf; return new_buf;
} }
protected:
static constexpr size_t getStackThreshold()
{
return N;
}
}; };

View File

@ -34,7 +34,7 @@ private:
/// Получить индекс в массиве freelist-ов для заданного размера. /// Получить индекс в массиве freelist-ов для заданного размера.
static size_t findFreeListIndex(const size_t size) static size_t findFreeListIndex(const size_t size)
{ {
return size <= 8 ? 2 : bit_scan_reverse(size - 1); return size <= 8 ? 2 : bitScanReverse(size - 1);
} }
/// Для выделения блоков не слишком большого размера используется Arena. /// Для выделения блоков не слишком большого размера используется Arena.

View File

@ -1,6 +1,32 @@
#pragma once #pragma once
inline unsigned int bit_scan_reverse(unsigned int x) #include <cstdint>
/** Returns log2 of number, rounded down.
* Compiles to single 'bsr' instruction on x86.
* For zero argument, result is unspecified.
*/
inline unsigned int bitScanReverse(unsigned int x)
{ {
return sizeof(unsigned int) * 8 - 1 - __builtin_clz(x); return sizeof(unsigned int) * 8 - 1 - __builtin_clz(x);
} }
/** For zero argument, result is zero.
* For arguments with most significand bit set, result is zero.
* For other arguments, returns value, rounded up to power of two.
*/
inline size_t roundUpToPowerOfTwoOrZero(size_t n)
{
--n;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
++n;
return n;
}

View File

@ -1,12 +1,42 @@
#pragma once #pragma once
#include <queue> #include <queue>
#include <type_traits>
#include <Poco/Mutex.h> #include <Poco/Mutex.h>
#include <Poco/Semaphore.h> #include <Poco/Semaphore.h>
#include <DB/Core/Types.h> #include <DB/Core/Types.h>
namespace detail
{
template <class T, bool is_nothrow_move_assignable = std::is_nothrow_move_assignable<T>::value>
struct MoveOrCopyIfThrow;
template <class T>
struct MoveOrCopyIfThrow<T, true>
{
void operator()(T && src, T & dst) const
{
dst = std::forward<T>(src);
}
};
template <class T>
struct MoveOrCopyIfThrow<T, false>
{
void operator()(T && src, T & dst) const
{
dst = src;
}
};
template <class T>
void moveOrCopyIfThrow(T && src, T & dst)
{
MoveOrCopyIfThrow<T>()(std::forward<T>(src), dst);
}
};
/** Очень простая thread-safe очередь ограниченной длины. /** Очень простая thread-safe очередь ограниченной длины.
* Если пытаться вынуть элемент из пустой очереди, то поток блокируется, пока очередь не станет непустой. * Если пытаться вынуть элемент из пустой очереди, то поток блокируется, пока очередь не станет непустой.
@ -36,12 +66,23 @@ public:
fill_count.set(); fill_count.set();
} }
template <class ... Args>
void emplace(Args && ... args)
{
empty_count.wait();
{
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
queue.emplace(std::forward<Args>(args)...);
}
fill_count.set();
}
void pop(T & x) void pop(T & x)
{ {
fill_count.wait(); fill_count.wait();
{ {
Poco::ScopedLock<Poco::FastMutex> lock(mutex); Poco::ScopedLock<Poco::FastMutex> lock(mutex);
x = queue.front(); detail::moveOrCopyIfThrow(std::move(queue.front()), x);
queue.pop(); queue.pop();
} }
empty_count.set(); empty_count.set();
@ -61,13 +102,28 @@ public:
return false; return false;
} }
template <class ... Args>
bool tryEmplace(DB::UInt64 milliseconds, Args && ... args)
{
if (empty_count.tryWait(milliseconds))
{
{
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
queue.emplace(std::forward<Args>(args)...);
}
fill_count.set();
return true;
}
return false;
}
bool tryPop(T & x, DB::UInt64 milliseconds = 0) bool tryPop(T & x, DB::UInt64 milliseconds = 0)
{ {
if (fill_count.tryWait(milliseconds)) if (fill_count.tryWait(milliseconds))
{ {
{ {
Poco::ScopedLock<Poco::FastMutex> lock(mutex); Poco::ScopedLock<Poco::FastMutex> lock(mutex);
x = queue.front(); detail::moveOrCopyIfThrow(std::move(queue.front()), x);
queue.pop(); queue.pop();
} }
empty_count.set(); empty_count.set();

View File

@ -2,6 +2,7 @@
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
#include <atomic>
/** Позволяет считать количество одновременно происходящих событий или текущее значение какой-либо метрики. /** Позволяет считать количество одновременно происходящих событий или текущее значение какой-либо метрики.
@ -65,7 +66,7 @@ namespace CurrentMetrics
using Value = int64_t; using Value = int64_t;
/// Счётчики - текущие значения метрик. /// Счётчики - текущие значения метрик.
extern Value values[END]; extern std::atomic<Value> values[END];
/// Выставить значение указанной метрики. /// Выставить значение указанной метрики.
@ -77,7 +78,7 @@ namespace CurrentMetrics
/// Прибавить величину к значению указанной метрики. Вы затем должны вычесть величину самостоятельно. Или см. ниже class Increment. /// Прибавить величину к значению указанной метрики. Вы затем должны вычесть величину самостоятельно. Или см. ниже class Increment.
inline void add(Metric metric, Value value = 1) inline void add(Metric metric, Value value = 1)
{ {
__sync_fetch_and_add(&values[metric], value); values[metric] += value;
} }
inline void sub(Metric metric, Value value = 1) inline void sub(Metric metric, Value value = 1)
@ -89,13 +90,13 @@ namespace CurrentMetrics
class Increment class Increment
{ {
private: private:
Value * what; std::atomic<Value> * what;
Value amount; Value amount;
Increment(Value * what, Value amount) Increment(std::atomic<Value> * what, Value amount)
: what(what), amount(amount) : what(what), amount(amount)
{ {
__sync_fetch_and_add(what, amount); *what += amount;
} }
public: public:
@ -105,7 +106,7 @@ namespace CurrentMetrics
~Increment() ~Increment()
{ {
if (what) if (what)
__sync_fetch_and_sub(what, amount); *what -= amount;
} }
Increment(Increment && old) Increment(Increment && old)
@ -123,14 +124,14 @@ namespace CurrentMetrics
void changeTo(Value new_amount) void changeTo(Value new_amount)
{ {
__sync_fetch_and_add(what, new_amount - amount); *what += new_amount - amount;
amount = new_amount; amount = new_amount;
} }
/// Уменьшить значение раньше вызова деструктора. /// Уменьшить значение раньше вызова деструктора.
void destroy() void destroy()
{ {
__sync_fetch_and_sub(what, amount); *what -= amount;
what = nullptr; what = nullptr;
} }
}; };

View File

@ -50,7 +50,7 @@ public:
column.name = structure[i].first; column.name = structure[i].first;
column.type = data_type_factory.get(structure[i].second); column.type = data_type_factory.get(structure[i].second);
column.column = column.type->createColumn(); column.column = column.type->createColumn();
sample_block.insert(column); sample_block.insert(std::move(column));
} }
} }
@ -124,9 +124,9 @@ public:
void initReadBuffer() void initReadBuffer()
{ {
if (file == "-") if (file == "-")
read_buffer.reset(new ReadBufferFromFileDescriptor(STDIN_FILENO)); read_buffer = std::make_unique<ReadBufferFromFileDescriptor>(STDIN_FILENO);
else else
read_buffer.reset(new ReadBufferFromFile(file)); read_buffer = std::make_unique<ReadBufferFromFile>(file);
} }
/// Извлечение параметров из variables_map, которая строится по командной строке клиента /// Извлечение параметров из variables_map, которая строится по командной строке клиента

View File

@ -6,19 +6,19 @@
#include <Poco/URI.h> #include <Poco/URI.h>
/** Почему-то при методе POST, Poco::Net::HTMLForm не считывает параметры из URL, а считывает только из тела. /** Somehow, in case of POST, Poco::Net::HTMLForm doesn't read parameters from URL, only from body.
* Этот помошник позволяет считывать параметры только из URL. * This helper allows to read parameters just from URL.
*/ */
struct HTMLForm : public Poco::Net::HTMLForm struct HTMLForm : public Poco::Net::HTMLForm
{ {
HTMLForm(Poco::Net::HTTPRequest & request) HTMLForm(const Poco::Net::HTTPRequest & request)
{ {
Poco::URI uri(request.getURI()); Poco::URI uri(request.getURI());
std::istringstream istr(uri.getRawQuery()); std::istringstream istr(uri.getRawQuery());
readUrl(istr); readUrl(istr);
} }
HTMLForm(Poco::URI & uri) HTMLForm(const Poco::URI & uri)
{ {
std::istringstream istr(uri.getRawQuery()); std::istringstream istr(uri.getRawQuery());
readUrl(istr); readUrl(istr);

View File

@ -71,7 +71,7 @@ private:
*/ */
struct SimpleIncrement : private boost::noncopyable struct SimpleIncrement : private boost::noncopyable
{ {
UInt64 value; std::atomic<UInt64> value;
SimpleIncrement(UInt64 start = 0) : value(start) {} SimpleIncrement(UInt64 start = 0) : value(start) {}
@ -82,6 +82,6 @@ struct SimpleIncrement : private boost::noncopyable
UInt64 get() UInt64 get()
{ {
return __sync_add_and_fetch(&value, 1); return ++value;
} }
}; };

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <atomic>
#include <common/Common.h> #include <common/Common.h>
@ -9,9 +10,9 @@
*/ */
class MemoryTracker class MemoryTracker
{ {
Int64 amount = 0; std::atomic<Int64> amount {0};
Int64 peak = 0; std::atomic<Int64> peak {0};
Int64 limit = 0; Int64 limit {0};
/// В целях тестирования exception safety - кидать исключение при каждом выделении памяти с указанной вероятностью. /// В целях тестирования exception safety - кидать исключение при каждом выделении памяти с указанной вероятностью.
double fault_probability = 0; double fault_probability = 0;
@ -43,12 +44,12 @@ public:
Int64 get() const Int64 get() const
{ {
return amount; return amount.load(std::memory_order_relaxed);
} }
Int64 getPeak() const Int64 getPeak() const
{ {
return peak; return peak.load(std::memory_order_relaxed);
} }
void setLimit(Int64 limit_) void setLimit(Int64 limit_)

View File

@ -266,7 +266,7 @@ OptimizedRegularExpressionImpl<b>::OptimizedRegularExpressionImpl(const std::str
if (is_dot_nl) if (is_dot_nl)
options.set_dot_nl(true); options.set_dot_nl(true);
re2.reset(new RegexType(regexp_, options)); re2 = std::make_unique<RegexType>(regexp_, options);
if (!re2->ok()) if (!re2->ok())
throw Poco::Exception("OptimizedRegularExpression: cannot compile re2: " + regexp_ + ", error: " + re2->error()); throw Poco::Exception("OptimizedRegularExpression: cannot compile re2: " + regexp_ + ", error: " + re2->error());

View File

@ -13,6 +13,7 @@
#include <DB/Common/Allocator.h> #include <DB/Common/Allocator.h>
#include <DB/Common/Exception.h> #include <DB/Common/Exception.h>
#include <DB/Common/BitHelpers.h>
namespace DB namespace DB
@ -60,23 +61,9 @@ private:
/// Минимальное количество памяти, которое нужно выделить для num_elements элементов, включая padding. /// Минимальное количество памяти, которое нужно выделить для num_elements элементов, включая padding.
static size_t minimum_memory_for_elements(size_t num_elements) { return byte_size(num_elements) + pad_right; } static size_t minimum_memory_for_elements(size_t num_elements) { return byte_size(num_elements) + pad_right; }
static size_t round_up_to_power_of_two(size_t n)
{
--n;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
++n;
return n;
}
void alloc_for_num_elements(size_t num_elements) void alloc_for_num_elements(size_t num_elements)
{ {
alloc(round_up_to_power_of_two(minimum_memory_for_elements(num_elements))); alloc(roundUpToPowerOfTwoOrZero(minimum_memory_for_elements(num_elements)));
} }
void alloc(size_t bytes) void alloc(size_t bytes)
@ -109,6 +96,17 @@ private:
c_end_of_storage = c_start + bytes - pad_right; c_end_of_storage = c_start + bytes - pad_right;
} }
bool isInitialized() const
{
return (c_start != nullptr) && (c_end != nullptr) && (c_end_of_storage != nullptr);
}
bool isAllocatedFromStack() const
{
constexpr size_t stack_threshold = TAllocator::getStackThreshold();
return (stack_threshold > 0) && (allocated_size() <= stack_threshold);
}
public: public:
using value_type = T; using value_type = T;
@ -155,21 +153,12 @@ public:
PODArray(PODArray && other) PODArray(PODArray && other)
{ {
c_start = other.c_start; this->swap(other);
c_end = other.c_end;
c_end_of_storage = other.c_end_of_storage;
other.c_start = nullptr;
other.c_end = nullptr;
other.c_end_of_storage = nullptr;
} }
PODArray & operator=(PODArray && other) PODArray & operator=(PODArray && other)
{ {
std::swap(c_start, other.c_start); this->swap(other);
std::swap(c_end, other.c_end);
std::swap(c_end_of_storage, other.c_end_of_storage);
return *this; return *this;
} }
@ -198,7 +187,7 @@ public:
void reserve(size_t n) void reserve(size_t n)
{ {
if (n > capacity()) if (n > capacity())
realloc(round_up_to_power_of_two(minimum_memory_for_elements(n))); realloc(roundUpToPowerOfTwoOrZero(minimum_memory_for_elements(n)));
} }
void reserve() void reserve()
@ -278,7 +267,7 @@ public:
{ {
size_t required_capacity = size() + (from_end - from_begin); size_t required_capacity = size() + (from_end - from_begin);
if (required_capacity > capacity()) if (required_capacity > capacity())
reserve(round_up_to_power_of_two(required_capacity)); reserve(roundUpToPowerOfTwoOrZero(required_capacity));
insert_assume_reserved(from_begin, from_end); insert_assume_reserved(from_begin, from_end);
} }
@ -288,7 +277,7 @@ public:
{ {
size_t required_capacity = size() + (from_end - from_begin); size_t required_capacity = size() + (from_end - from_begin);
if (required_capacity > capacity()) if (required_capacity > capacity())
reserve(round_up_to_power_of_two(required_capacity)); reserve(roundUpToPowerOfTwoOrZero(required_capacity));
size_t bytes_to_copy = byte_size(from_end - from_begin); size_t bytes_to_copy = byte_size(from_end - from_begin);
size_t bytes_to_move = (end() - it) * sizeof(T); size_t bytes_to_move = (end() - it) * sizeof(T);
@ -309,11 +298,109 @@ public:
} }
void swap(PODArray & rhs) void swap(PODArray & rhs)
{
/// Swap two PODArray objects, arr1 and arr2, that satisfy the following conditions:
/// - The elements of arr1 are stored on stack.
/// - The elements of arr2 are stored on heap.
auto swap_stack_heap = [](PODArray & arr1, PODArray & arr2)
{
size_t stack_size = arr1.size();
size_t stack_allocated = arr1.allocated_size();
size_t heap_size = arr2.size();
size_t heap_allocated = arr2.allocated_size();
/// Keep track of the stack content we have to copy.
char * stack_c_start = arr1.c_start;
/// arr1 takes ownership of the heap memory of arr2.
arr1.c_start = arr2.c_start;
arr1.c_end_of_storage = arr1.c_start + heap_allocated - arr1.pad_right;
arr1.c_end = arr1.c_start + byte_size(heap_size);
/// Allocate stack space for arr2.
arr2.alloc(stack_allocated);
/// Copy the stack content.
memcpy(arr2.c_start, stack_c_start, byte_size(stack_size));
arr2.c_end = arr2.c_start + byte_size(stack_size);
};
auto do_move = [](PODArray & src, PODArray & dest)
{
if (src.isAllocatedFromStack())
{
dest.dealloc();
dest.alloc(src.allocated_size());
memcpy(dest.c_start, src.c_start, byte_size(src.size()));
dest.c_end = dest.c_start + (src.c_end - src.c_start);
src.c_start = nullptr;
src.c_end = nullptr;
src.c_end_of_storage = nullptr;
}
else
{
std::swap(dest.c_start, src.c_start);
std::swap(dest.c_end, src.c_end);
std::swap(dest.c_end_of_storage, src.c_end_of_storage);
}
};
if (!isInitialized() && !rhs.isInitialized())
return;
else if (!isInitialized() && rhs.isInitialized())
{
do_move(rhs, *this);
return;
}
else if (isInitialized() && !rhs.isInitialized())
{
do_move(*this, rhs);
return;
}
if (isAllocatedFromStack() && rhs.isAllocatedFromStack())
{
size_t min_size = std::min(size(), rhs.size());
size_t max_size = std::max(size(), rhs.size());
for (size_t i = 0; i < min_size; ++i)
std::swap(this->operator[](i), rhs[i]);
if (size() == max_size)
{
for (size_t i = min_size; i < max_size; ++i)
rhs[i] = this->operator[](i);
}
else
{
for (size_t i = min_size; i < max_size; ++i)
this->operator[](i) = rhs[i];
}
size_t lhs_size = size();
size_t lhs_allocated = allocated_size();
size_t rhs_size = rhs.size();
size_t rhs_allocated = rhs.allocated_size();
c_end_of_storage = c_start + rhs_allocated - pad_right;
rhs.c_end_of_storage = rhs.c_start + lhs_allocated - pad_right;
c_end = c_start + byte_size(rhs_size);
rhs.c_end = rhs.c_start + byte_size(lhs_size);
}
else if (isAllocatedFromStack() && !rhs.isAllocatedFromStack())
swap_stack_heap(*this, rhs);
else if (!isAllocatedFromStack() && rhs.isAllocatedFromStack())
swap_stack_heap(rhs, *this);
else
{ {
std::swap(c_start, rhs.c_start); std::swap(c_start, rhs.c_start);
std::swap(c_end, rhs.c_end); std::swap(c_end, rhs.c_end);
std::swap(c_end_of_storage, rhs.c_end_of_storage); std::swap(c_end_of_storage, rhs.c_end_of_storage);
} }
}
void assign(size_t n, const T & x) void assign(size_t n, const T & x)
{ {
@ -326,7 +413,7 @@ public:
{ {
size_t required_capacity = from_end - from_begin; size_t required_capacity = from_end - from_begin;
if (required_capacity > capacity()) if (required_capacity > capacity())
reserve(round_up_to_power_of_two(required_capacity)); reserve(roundUpToPowerOfTwoOrZero(required_capacity));
size_t bytes_to_copy = byte_size(required_capacity); size_t bytes_to_copy = byte_size(required_capacity);
memcpy(c_start, reinterpret_cast<const void *>(&*from_begin), bytes_to_copy); memcpy(c_start, reinterpret_cast<const void *>(&*from_begin), bytes_to_copy);
@ -365,6 +452,11 @@ public:
} }
}; };
template <typename T, size_t INITIAL_SIZE, typename TAllocator, size_t pad_right_>
void swap(PODArray<T, INITIAL_SIZE, TAllocator, pad_right_> & lhs, PODArray<T, INITIAL_SIZE, TAllocator, pad_right_> & rhs)
{
lhs.swap(rhs);
}
/** Для столбцов. Padding-а хватает, чтобы читать и писать xmm-регистр по адресу последнего элемента. */ /** Для столбцов. Padding-а хватает, чтобы читать и писать xmm-регистр по адресу последнего элемента. */
template <typename T, size_t INITIAL_SIZE = 4096, typename TAllocator = Allocator<false>> template <typename T, size_t INITIAL_SIZE = 4096, typename TAllocator = Allocator<false>>

View File

@ -6,6 +6,7 @@
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <common/logger_useful.h> #include <common/logger_useful.h>
#include <DB/Common/Exception.h>
/// This type specifies the possible behaviors of an object pool allocator. /// This type specifies the possible behaviors of an object pool allocator.
enum class PoolMode enum class PoolMode
@ -36,14 +37,14 @@ private:
/** Объект с флагом, используется ли он сейчас. */ /** Объект с флагом, используется ли он сейчас. */
struct PooledObject struct PooledObject
{ {
PooledObject(std::condition_variable & available_, ObjectPtr object_) PooledObject(ObjectPtr object_, PoolBase & pool_)
: object(object_), available(available_) : object(object_), pool(pool_)
{ {
} }
ObjectPtr object; ObjectPtr object;
bool in_use = false; bool in_use = false;
std::condition_variable & available; PoolBase & pool;
}; };
using Objects = std::vector<std::shared_ptr<PooledObject>>; using Objects = std::vector<std::shared_ptr<PooledObject>>;
@ -54,7 +55,12 @@ private:
struct PoolEntryHelper struct PoolEntryHelper
{ {
PoolEntryHelper(PooledObject & data_) : data(data_) { data.in_use = true; } PoolEntryHelper(PooledObject & data_) : data(data_) { data.in_use = true; }
~PoolEntryHelper() { data.in_use = false; data.available.notify_one(); } ~PoolEntryHelper()
{
std::unique_lock<std::mutex> lock(data.pool.mutex);
data.in_use = false;
data.pool.available.notify_one();
}
PooledObject & data; PooledObject & data;
}; };
@ -86,6 +92,13 @@ public:
bool isNull() const { return data == nullptr; } bool isNull() const { return data == nullptr; }
PoolBase * getPool() const
{
if (!data)
throw DB::Exception("attempt to get pool from uninitialized entry");
return &data->data.pool;
}
private: private:
std::shared_ptr<PoolEntryHelper> data; std::shared_ptr<PoolEntryHelper> data;
@ -108,7 +121,7 @@ public:
if (items.size() < max_items) if (items.size() < max_items)
{ {
ObjectPtr object = allocObject(); ObjectPtr object = allocObject();
items.emplace_back(std::make_shared<PooledObject>(available, object)); items.emplace_back(std::make_shared<PooledObject>(object, *this));
return Entry(*items.back()); return Entry(*items.back());
} }
@ -126,7 +139,7 @@ public:
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
while (items.size() < count) while (items.size() < count)
items.emplace_back(std::make_shared<PooledObject>(available, allocObject())); items.emplace_back(std::make_shared<PooledObject>(allocObject(), *this));
} }
private: private:

View File

@ -5,6 +5,7 @@
#include <DB/Common/ProfileEvents.h> #include <DB/Common/ProfileEvents.h>
#include <DB/Common/NetException.h> #include <DB/Common/NetException.h>
#include <DB/Common/Exception.h> #include <DB/Common/Exception.h>
#include <DB/Common/randomSeed.h>
#include <DB/Interpreters/Settings.h> #include <DB/Interpreters/Settings.h>
@ -13,7 +14,6 @@ namespace DB
namespace ErrorCodes namespace ErrorCodes
{ {
extern const int ALL_CONNECTION_TRIES_FAILED; extern const int ALL_CONNECTION_TRIES_FAILED;
extern const int CANNOT_CLOCK_GETTIME;
extern const int LOGICAL_ERROR; extern const int LOGICAL_ERROR;
} }
} }
@ -110,6 +110,19 @@ public:
return {}; return {};
} }
void reportError(const Entry & entry)
{
for (auto & pool : nested_pools)
{
if (pool.pool->contains(entry))
{
++pool.state.error_count;
return;
}
}
throw DB::Exception("Can't find pool to report error.");
}
/** Выделяет до указанного количества соединений для работы /** Выделяет до указанного количества соединений для работы
* Соединения предоставляют доступ к разным репликам одного шарда. * Соединения предоставляют доступ к разным репликам одного шарда.
*/ */
@ -154,11 +167,7 @@ protected:
public: public:
PoolWithErrorCount(const NestedPoolPtr & pool_) : pool(pool_) PoolWithErrorCount(const NestedPoolPtr & pool_) : pool(pool_)
{ {
struct timespec times; srand48_r(randomSeed(), &rand_state);
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &times))
DB::throwFromErrno("Cannot clock_gettime.", DB::ErrorCodes::CANNOT_CLOCK_GETTIME);
srand48_r(reinterpret_cast<intptr_t>(this) ^ times.tv_nsec, &rand_state);
} }
void randomize() void randomize()
@ -173,13 +182,20 @@ protected:
{ {
static bool compare(const State & lhs, const State & rhs) static bool compare(const State & lhs, const State & rhs)
{ {
return std::tie(lhs.priority, lhs.error_count, lhs.random) return std::forward_as_tuple(lhs.priority, lhs.error_count.load(std::memory_order_relaxed), lhs.random)
< std::tie(rhs.priority, rhs.error_count, rhs.random); < std::forward_as_tuple(rhs.priority, rhs.error_count.load(std::memory_order_relaxed), rhs.random);
} }
Int64 priority = 0; Int64 priority {0};
UInt64 error_count = 0; std::atomic<UInt64> error_count {0};
UInt32 random = 0; UInt32 random {0};
State() {}
State(const State & other)
: priority(other.priority),
error_count(other.error_count.load(std::memory_order_relaxed)),
random(other.random) {}
}; };
public: public:
@ -237,7 +253,9 @@ protected:
else if (shift_amount) else if (shift_amount)
{ {
for (auto & pool : *this) for (auto & pool : *this)
pool.state.error_count >>= shift_amount; pool.state.error_count.store(
pool.state.error_count.load(std::memory_order_relaxed) >> shift_amount,
std::memory_order_relaxed);
} }
} }
} }
@ -319,7 +337,7 @@ private:
fail_messages << fail_message.str() << std::endl; fail_messages << fail_message.str() << std::endl;
__sync_fetch_and_add(&pool_ptrs[i].pool->state.error_count, 1); ++pool_ptrs[i].pool->state.error_count;
} }
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#include <atomic>
/** Позволяет считать количество различных событий, произошедших в программе /** Позволяет считать количество различных событий, произошедших в программе
@ -125,13 +126,13 @@ namespace ProfileEvents
/// Счётчики - сколько раз каждое из событий произошло. /// Счётчики - сколько раз каждое из событий произошло.
extern size_t counters[END]; extern std::atomic<size_t> counters[END];
/// Увеличить счётчик события. Потокобезопасно. /// Увеличить счётчик события. Потокобезопасно.
inline void increment(Event event, size_t amount = 1) inline void increment(Event event, size_t amount = 1)
{ {
__sync_fetch_and_add(&counters[event], amount); counters[event] += amount;
} }
} }

View File

@ -14,7 +14,7 @@
#include <cstdint> #include <cstdint>
#include <cstddef> #include <cstddef>
#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) ) #define ROTL(x,b) static_cast<u64>( ((x) << (b)) | ( (x) >> (64 - (b))) )
#define SIPROUND \ #define SIPROUND \
do \ do \

View File

@ -0,0 +1,86 @@
#pragma once
#include <string>
#include <cstring>
namespace detail
{
bool startsWith(const std::string & s, const char * prefix, size_t prefix_size);
bool endsWith(const std::string & s, const char * suffix, size_t suffix_size);
}
inline bool startsWith(const std::string & s, const std::string & prefix)
{
return detail::startsWith(s, prefix.data(), prefix.size());
}
inline bool endsWith(const std::string & s, const std::string & suffix)
{
return detail::endsWith(s, suffix.data(), suffix.size());
}
/// strlen evaluated compile-time.
inline bool startsWith(const std::string & s, const char * prefix)
{
return detail::startsWith(s, prefix, strlen(prefix));
}
inline bool endsWith(const std::string & s, const char * suffix)
{
return detail::endsWith(s, suffix, strlen(suffix));
}
/// More efficient than libc, because doesn't respect locale.
inline bool isASCII(char c)
{
return static_cast<unsigned char>(c) < 0x80;
}
inline bool isAlphaASCII(char c)
{
return (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z');
}
inline bool isNumericASCII(char c)
{
return (c >= '0' && c <= '9');
}
inline bool isAlphaNumericASCII(char c)
{
return isAlphaASCII(c)
|| isNumericASCII(c);
}
inline bool isWordCharASCII(char c)
{
return isAlphaNumericASCII(c)
|| c == '_';
}
inline bool isWhitespaceASCII(char c)
{
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
}
/// Works assuming isAlphaASCII.
inline char toLowerIfAlphaASCII(char c)
{
return c | 0x20;
}
inline char toUpperIfAlphaASCII(char c)
{
return c & (~0x20);
}
inline char alternateCaseIfAlphaASCII(char c)
{
return c ^ 0x20;
}

View File

@ -0,0 +1,61 @@
#pragma once
#include <cstdint>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <queue>
#include <vector>
/** Very simple thread pool similar to boost::threadpool.
* Advantages:
* - catches exceptions and rethrows on wait.
*/
class ThreadPool
{
private:
using Job = std::function<void()>;
public:
/// Size is constant, all threads are created immediately.
ThreadPool(size_t m_size);
/// Add new job. Locks until free thread in pool become available or exception in one of threads was thrown.
/// If an exception in some thread was thrown, method silently returns, and exception will be rethrown only on call to 'wait' function.
void schedule(Job job);
/// Wait for all currently active jobs to be done.
/// You may call schedule and wait many times in arbitary order.
/// If any thread was throw an exception, first exception will be rethrown from this method,
/// and exception will be cleared.
void wait();
/// Waits for all threads. Doesn't rethrow exceptions (use 'wait' method to rethrow exceptions).
/// You should not destroy object while calling schedule or wait methods from another threads.
~ThreadPool();
size_t size() const { return m_size; }
/// Returns number of active jobs.
size_t active() const;
private:
mutable std::mutex mutex;
std::condition_variable has_free_thread;
std::condition_variable has_new_job_or_shutdown;
const size_t m_size;
size_t active_jobs = 0;
bool shutdown = false;
std::queue<Job> jobs;
std::vector<std::thread> threads;
std::exception_ptr first_exception;
void worker();
};

View File

@ -25,8 +25,10 @@ struct UInt128
struct UInt128Hash struct UInt128Hash
{ {
DefaultHash<UInt64> hash64; size_t operator()(UInt128 x) const
size_t operator()(UInt128 x) const { return hash64(hash64(x.first) ^ x.second); } {
return Hash128to64({x.first, x.second});
}
}; };
#if defined(__x86_64__) #if defined(__x86_64__)
@ -89,6 +91,15 @@ struct UInt256
UInt256 & operator= (const UInt64 rhs) { a = rhs; b = 0; c = 0; d = 0; return *this; } UInt256 & operator= (const UInt64 rhs) { a = rhs; b = 0; c = 0; d = 0; return *this; }
}; };
struct UInt256Hash
{
size_t operator()(UInt256 x) const
{
/// NOTE suboptimal
return Hash128to64({Hash128to64({x.a, x.b}), Hash128to64({x.c, x.d})});
}
};
#if defined(__x86_64__) #if defined(__x86_64__)
struct UInt256HashCRC32 struct UInt256HashCRC32

Some files were not shown because too many files have changed in this diff Show More