Compare commits

...

2 Commits

Author SHA1 Message Date
wangdan
68344c354a no message 2021-10-19 15:30:39 +08:00
wangdan
8c688c52ef no message 2021-10-19 15:29:57 +08:00
1371 changed files with 280245 additions and 2 deletions

78
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,78 @@
/*
* 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.
*/
pipeline {
agent {
label 'Hadoop'
}
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(daysToKeepStr: '14'))
timeout(time: 2, unit: 'HOURS')
timestamps()
}
triggers {
cron('@daily')
}
stages {
stage('Prepare') {
matrix {
agent any
axes {
axis {
name 'JAVA_VERSION'
values 'jdk_1.8_latest', 'jdk_11_latest'
}
}
tools {
maven "maven_latest"
jdk "${JAVA_VERSION}"
}
stages {
stage('BuildAndTest') {
steps {
sh "git clean -fxd"
sh "mvn verify spotbugs:check checkstyle:check -Pfull-build -Dsurefire-forkcount=4"
}
post {
always {
junit '**/target/surefire-reports/TEST-*.xml'
archiveArtifacts '**/target/*.jar'
}
// Jenkins pipeline jobs fill slaves on PRs without this :(
cleanup() {
script {
sh label: 'Cleanup workspace', script: '''
# See HADOOP-13951
chmod -R u+rxw "${WORKSPACE}"
'''
deleteDir()
}
}
}
}
}
}
}
}
}

63
Jenkinsfile-PreCommit Normal file
View File

@ -0,0 +1,63 @@
/*
* 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.
*/
pipeline {
agent {
label 'Hadoop'
}
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(daysToKeepStr: '14'))
timeout(time: 2, unit: 'HOURS')
timestamps()
}
tools {
maven "maven_latest"
jdk "jdk_1.8_latest"
}
stages {
stage('BuildAndTest') {
steps {
git 'https://github.com/apache/zookeeper'
sh "git clean -fxd"
sh "mvn verify spotbugs:check checkstyle:check -Pfull-build -Dsurefire-forkcount=4"
}
post {
always {
junit '**/target/surefire-reports/TEST-*.xml'
}
}
}
}
post {
// Jenkins pipeline jobs fill slaves on PRs without this :(
cleanup() {
script {
sh label: 'Cleanup workspace', script: '''
# See HADOOP-13951
chmod -R u+rxw "${WORKSPACE}"
'''
deleteDir()
}
}
}
}

61
Jenkinsfile-owasp Normal file
View File

@ -0,0 +1,61 @@
/*
* 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.
*/
pipeline {
agent {
label 'Hadoop'
}
options {
buildDiscarder(logRotator(daysToKeepStr: '14'))
timeout(time: 2, unit: 'HOURS')
timestamps()
}
tools {
maven "maven_latest"
jdk "jdk_1.8_latest"
}
stages {
stage('BuildAndTest') {
steps {
sh "git clean -fxd"
sh "mvn clean package -DskipTests dependency-check:check"
}
post {
always {
archiveArtifacts '**/target/dependency-check-*'
}
}
}
}
post {
// Jenkins pipeline jobs fill slaves on PRs without this :(
cleanup() {
script {
sh label: 'Cleanup workspace', script: '''
# See HADOOP-13951
chmod -R u+rxw "${WORKSPACE}"
'''
deleteDir()
}
}
}
}

202
LICENSE.txt Normal file
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.

11
NOTICE.txt Normal file
View File

@ -0,0 +1,11 @@
Apache ZooKeeper
Copyright 2009-2021 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
This product includes software components originally
developed for Airlift (https://github.com/airlift/airlift),
licensed under the Apache 2.0 license. The licensing terms
for Airlift code can be found at:
https://github.com/airlift/airlift/blob/master/LICENSE

View File

@ -1,3 +1,46 @@
# zookeeper-souce-note
# Apache ZooKeeper [![Build Status](https://travis-ci.org/apache/zookeeper.svg?branch=master)](https://travis-ci.org/apache/zookeeper) [![Maven Central](https://img.shields.io/maven-central/v/org.apache.zookeeper/zookeeper)](https://zookeeper.apache.org/releases.html) [![License](https://img.shields.io/github/license/apache/zookeeper)](https://github.com/apache/zookeeper/blob/master/LICENSE.txt)
![alt text](https://zookeeper.apache.org/images/zookeeper_small.gif "ZooKeeper")
For the latest information about Apache ZooKeeper, please visit our website at:
http://zookeeper.apache.org/
and our wiki, at:
https://cwiki.apache.org/confluence/display/ZOOKEEPER
---------------------------
Packaging/release artifacts
Either downloaded from https://zookeeper.apache.org/releases.html or
found in zookeeper-assembly/target directory after building the project with maven.
apache-zookeeper-[version].tar.gz
Contains all the source files which can be built by running:
mvn clean install
To generate an aggregated apidocs for zookeeper-server and zookeeper-jute:
mvn javadoc:aggregate
(generated files will be at target/site/apidocs)
apache-zookeeper-[version]-bin.tar.gz
Contains all the jar files required to run ZooKeeper
Full documentation can also be found in the docs folder
As of version 3.5.5, the parent, zookeeper and zookeeper-jute artifacts
are deployed to the central repository after the release
is voted on and approved by the Apache ZooKeeper PMC:
https://repo1.maven.org/maven2/org/apache/zookeeper/zookeeper/
## Java 8
If you are going to compile with Java 1.8, you should use a
recent release at u211 or above.
# Contributing
We always welcome new contributors to the project! See [How to Contribute](https://cwiki.apache.org/confluence/display/ZOOKEEPER/HowToContribute) for details on how to submit patch through pull request and our contribution workflow.
zookeeper 源码注释

76
README_packaging.md Normal file
View File

@ -0,0 +1,76 @@
# README file for Packaging Notes
The ZooKeeper project publishes releases as tarballs. For ZooKeeper packages
specific to your OS (such as rpm and deb), consider using Apache Bigtop:
http://bigtop.apache.org/
## Requirements
- you need maven to build the java code
- gcc, cppunit, openssl and python-setuptools are required to build C and python bindings. (only needed when using `-Pfull-build`)
On RHEL machine:
```
yum install cppunit
yum install python-setuptools
yum install openssl openssl-devel
```
On Ubuntu (in case of 16.4+):
```
apt-get install libcppunit-dev
apt-get install python-setuptools python2.7-dev
apt-get install openssl libssl-dev
```
## Package build command (using maven)
Commands to clean everything and build the tarball package without executing the tests: `mvn clean install -DskipTests`
`zookeeper-assembly/target/apache-zookeeper-<version>-bin.tar.gz` tarball file structure layout:
- `/bin` - User executables
- `/conf` - Configuration files
- `/lib` - ZooKeeper JAR files and all the required java library dependencies
- `/docs` - Documents
Beside the binary tarball, you can find the whole original source project packaged into:
`zookeeper-assembly/target/apache-zookeeper-<version>.tar.gz`
### Building the C client (using maven)
To also build the C client, you need to activate the `full-build` profile:
```
mvn clean -Pfull-build
mvn install -Pfull-build -DskipTests
```
Optional parameters you might consider when using maven:
- `-Pfull-build` - activates the full-build profile, causing the C client to be built
- `-DskipTests` - this parameter will skip both java and C++ unit test execution during the build
- `-Pc-test-coverage` - activates the test coverage calculation during the execution of C client tests
- `-Dc-client-openssl` - specify ssl support and openssl library location. Default value: `yes`, resulting in
the autodetection of the openssl library. If the openssl library will not be detected,
then a warning will be shown and the C client will be compiled without SSL support.
Use `-Dc-client-openssl=no` to explicitly disable SSL feature in C client. Or use
`-Dc-client-openssl=/path/to/openssl/` if you want to use a non-default / specific
openssl library location.
Please note: if you don't provide the `-Pfull-build` parameter, then the C client will not be built, the C client tests
will not be executed and the previous C client builds will no be cleaned up (e.g. with simply using `mvn clean`).
The compiled C client can be found here:
- `zookeeper-client/zookeeper-client-c/target/c/bin` - User executable
- `zookeeper-client/zookeeper-client-c/target/c/lib` - Native libraries
- `zookeeper-client/zookeeper-client-c/target/c/include/zookeeper` - Native library headers
The same folders gets archived to the `zookeeper-assembly/target/apache-zookeeper-<version>-lib.tar.gz` file, assuming
you activated the `full-build` maven profile.

6
bin/README.txt Normal file
View File

@ -0,0 +1,6 @@
This directory contain scripts that allow easy access (classpath in particular)
to the ZooKeeper server and command line client.
Files ending in .sh are unix and cygwin compatible
Files ending in .cmd are msdos/windows compatible

53
bin/zkCleanup.sh Normal file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env bash
# 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.
#
# This script cleans up old transaction logs and snapshots
#
#
# If this scripted is run out of /usr/bin or some other system bin directory
# it should be linked to and not copied. Things like java jar files are found
# relative to the canonical path of this script.
#
# use POSIX interface, symlink is followed automatically
ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN="$(dirname "${ZOOBIN}")"
ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"
if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
. "$ZOOBINDIR"/../libexec/zkEnv.sh
else
. "$ZOOBINDIR"/zkEnv.sh
fi
ZOODATADIR="$(grep "^[[:space:]]*dataDir=" "$ZOOCFG" | sed -e 's/.*=//')"
ZOODATALOGDIR="$(grep "^[[:space:]]*dataLogDir=" "$ZOOCFG" | sed -e 's/.*=//')"
ZOO_LOG_FILE=zookeeper-$USER-cleanup-$HOSTNAME.log
if [ "x$ZOODATALOGDIR" = "x" ]
then
"$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-Dzookeeper.log.file=${ZOO_LOG_FILE}" \
-cp "$CLASSPATH" $JVMFLAGS \
org.apache.zookeeper.server.PurgeTxnLog "$ZOODATADIR" $*
else
"$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-Dzookeeper.log.file=${ZOO_LOG_FILE}" \
-cp "$CLASSPATH" $JVMFLAGS \
org.apache.zookeeper.server.PurgeTxnLog "$ZOODATALOGDIR" "$ZOODATADIR" $*
fi

26
bin/zkCli.cmd Normal file
View File

@ -0,0 +1,26 @@
@echo off
REM Licensed to the Apache Software Foundation (ASF) under one or more
REM contributor license agreements. See the NOTICE file distributed with
REM this work for additional information regarding copyright ownership.
REM The ASF licenses this file to You under the Apache License, Version 2.0
REM (the "License"); you may not use this file except in compliance with
REM the License. You may obtain a copy of the License at
REM
REM http://www.apache.org/licenses/LICENSE-2.0
REM
REM Unless required by applicable law or agreed to in writing, software
REM distributed under the License is distributed on an "AS IS" BASIS,
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
REM See the License for the specific language governing permissions and
REM limitations under the License.
setlocal
call "%~dp0zkEnv.cmd"
set ZOO_LOG_FILE=zookeeper-%USERNAME%-cli-%COMPUTERNAME%.log
set ZOOMAIN=org.apache.zookeeper.ZooKeeperMain
call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" "-Dzookeeper.log.file=%ZOO_LOG_FILE%" -cp "%CLASSPATH%" %ZOOMAIN% %*
endlocal

43
bin/zkCli.sh Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
# 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.
#
# This script cleans up old transaction logs and snapshots
#
#
# If this scripted is run out of /usr/bin or some other system bin directory
# it should be linked to and not copied. Things like java jar files are found
# relative to the canonical path of this script.
#
# use POSIX interface, symlink is followed automatically
ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN="$(dirname "${ZOOBIN}")"
ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"
if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
. "$ZOOBINDIR"/../libexec/zkEnv.sh
else
. "$ZOOBINDIR"/zkEnv.sh
fi
ZOO_LOG_FILE=zookeeper-$USER-cli-$HOSTNAME.log
"$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-Dzookeeper.log.file=${ZOO_LOG_FILE}" \
-cp "$CLASSPATH" $CLIENT_JVMFLAGS $JVMFLAGS \
org.apache.zookeeper.ZooKeeperMain "$@"

54
bin/zkEnv.cmd Normal file
View File

@ -0,0 +1,54 @@
@echo off
REM Licensed to the Apache Software Foundation (ASF) under one or more
REM contributor license agreements. See the NOTICE file distributed with
REM this work for additional information regarding copyright ownership.
REM The ASF licenses this file to You under the Apache License, Version 2.0
REM (the "License"); you may not use this file except in compliance with
REM the License. You may obtain a copy of the License at
REM
REM http://www.apache.org/licenses/LICENSE-2.0
REM
REM Unless required by applicable law or agreed to in writing, software
REM distributed under the License is distributed on an "AS IS" BASIS,
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
REM See the License for the specific language governing permissions and
REM limitations under the License.
set ZOOCFGDIR=%~dp0%..\conf
set ZOO_LOG_DIR=%~dp0%..\logs
set ZOO_LOG4J_PROP=INFO,CONSOLE
REM for sanity sake assume Java 1.6
REM see: http://java.sun.com/javase/6/docs/technotes/tools/windows/java.html
REM add the zoocfg dir to classpath
set CLASSPATH=%ZOOCFGDIR%
REM make it work in the release
SET CLASSPATH=%~dp0..\*;%~dp0..\lib\*;%CLASSPATH%
REM make it work for developers
SET CLASSPATH=%~dp0..\build\classes;%~dp0..\build\lib\*;%CLASSPATH%
set ZOOCFG=%ZOOCFGDIR%\zoo.cfg
@REM setup java environment variables
if not defined JAVA_HOME (
echo Error: JAVA_HOME is not set.
goto :eof
)
set JAVA_HOME=%JAVA_HOME:"=%
if not exist "%JAVA_HOME%"\bin\java.exe (
echo Error: JAVA_HOME is incorrectly set: %JAVA_HOME%
echo Expected to find java.exe here: %JAVA_HOME%\bin\java.exe
goto :eof
)
REM strip off trailing \ from JAVA_HOME or java does not start
if "%JAVA_HOME:~-1%" EQU "\" set "JAVA_HOME=%JAVA_HOME:~0,-1%"
set JAVA="%JAVA_HOME%"\bin\java

148
bin/zkEnv.sh Normal file
View File

@ -0,0 +1,148 @@
#!/usr/bin/env bash
# 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.
# This script should be sourced into other zookeeper
# scripts to setup the env variables
# We use ZOOCFGDIR if defined,
# otherwise we use /etc/zookeeper
# or the conf directory that is
# a sibling of this script's directory.
# Or you can specify the ZOOCFGDIR using the
# '--config' option in the command line.
ZOOBINDIR="${ZOOBINDIR:-/usr/bin}"
ZOOKEEPER_PREFIX="${ZOOBINDIR}/.."
#check to see if the conf dir is given as an optional argument
if [ $# -gt 1 ]
then
if [ "--config" = "$1" ]
then
shift
confdir=$1
shift
ZOOCFGDIR=$confdir
fi
fi
if [ "x$ZOOCFGDIR" = "x" ]
then
if [ -e "${ZOOKEEPER_PREFIX}/conf" ]; then
ZOOCFGDIR="$ZOOBINDIR/../conf"
else
ZOOCFGDIR="$ZOOBINDIR/../etc/zookeeper"
fi
fi
if [ -f "${ZOOCFGDIR}/zookeeper-env.sh" ]; then
. "${ZOOCFGDIR}/zookeeper-env.sh"
fi
if [ "x$ZOOCFG" = "x" ]
then
ZOOCFG="zoo.cfg"
fi
ZOOCFG="$ZOOCFGDIR/$ZOOCFG"
if [ -f "$ZOOCFGDIR/java.env" ]
then
. "$ZOOCFGDIR/java.env"
fi
if [ "x${ZOO_LOG_DIR}" = "x" ]
then
ZOO_LOG_DIR="$ZOOKEEPER_PREFIX/logs"
fi
if [ "x${ZOO_LOG4J_PROP}" = "x" ]
then
ZOO_LOG4J_PROP="INFO,CONSOLE"
fi
if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
JAVA="$JAVA_HOME/bin/java"
elif type -p java; then
JAVA=java
else
echo "Error: JAVA_HOME is not set and java could not be found in PATH." 1>&2
exit 1
fi
#add the zoocfg dir to classpath
CLASSPATH="$ZOOCFGDIR:$CLASSPATH"
for i in "$ZOOBINDIR"/../zookeeper-server/src/main/resources/lib/*.jar
do
CLASSPATH="$i:$CLASSPATH"
done
#make it work in the binary package
#(use array for LIBPATH to account for spaces within wildcard expansion)
if ls "${ZOOKEEPER_PREFIX}"/share/zookeeper/zookeeper-*.jar > /dev/null 2>&1; then
LIBPATH=("${ZOOKEEPER_PREFIX}"/share/zookeeper/*.jar)
else
#release tarball format
for i in "$ZOOBINDIR"/../zookeeper-*.jar
do
CLASSPATH="$i:$CLASSPATH"
done
LIBPATH=("${ZOOBINDIR}"/../lib/*.jar)
fi
for i in "${LIBPATH[@]}"
do
CLASSPATH="$i:$CLASSPATH"
done
#make it work for developers
for d in "$ZOOBINDIR"/../build/lib/*.jar
do
CLASSPATH="$d:$CLASSPATH"
done
for d in "$ZOOBINDIR"/../zookeeper-server/target/lib/*.jar
do
CLASSPATH="$d:$CLASSPATH"
done
#make it work for developers
CLASSPATH="$ZOOBINDIR/../build/classes:$CLASSPATH"
#make it work for developers
CLASSPATH="$ZOOBINDIR/../zookeeper-server/target/classes:$CLASSPATH"
case "`uname`" in
CYGWIN*|MINGW*) cygwin=true ;;
*) cygwin=false ;;
esac
if $cygwin
then
CLASSPATH=`cygpath -wp "$CLASSPATH"`
fi
#echo "CLASSPATH=$CLASSPATH"
# default heap for zookeeper server
ZK_SERVER_HEAP="${ZK_SERVER_HEAP:-1000}"
export SERVER_JVMFLAGS="-Xmx${ZK_SERVER_HEAP}m $SERVER_JVMFLAGS"
# default heap for zookeeper client
ZK_CLIENT_HEAP="${ZK_CLIENT_HEAP:-256}"
export CLIENT_JVMFLAGS="-Xmx${ZK_CLIENT_HEAP}m $CLIENT_JVMFLAGS"

141
bin/zkServer-initialize.sh Normal file
View File

@ -0,0 +1,141 @@
#!/usr/bin/env bash
# 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.
#
# If this scripted is run out of /usr/bin or some other system bin directory
# it should be linked to and not copied. Things like java jar files are found
# relative to the canonical path of this script.
#
# use POSIX interface, symlink is followed automatically
ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN="$(dirname "${ZOOBIN}")"
ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"
if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
. "$ZOOBINDIR"/../libexec/zkEnv.sh
else
. "$ZOOBINDIR"/zkEnv.sh
fi
usage() {
# the configfile will be properly formatted as long as the
# configfile path is less then 40 chars, otw the line will look a
# bit weird, but otherwise it's fine
printf "usage: $0 <parameters>
Optional parameters:
-h Display this message
--help Display this message
--configfile=%-40s ZooKeeper config file
--myid=# Set the myid to be used, if any (1-255)
--force Force creation of the data/txnlog dirs
" "$ZOOCFG"
exit 1
}
if [ $? != 0 ] ; then
usage
exit 1
fi
initialize() {
if [ ! -e "$ZOOCFG" ]; then
echo "Unable to find config file at $ZOOCFG"
exit 1
fi
ZOO_DATADIR="$(grep "^[[:space:]]*dataDir" "$ZOOCFG" | sed -e 's/.*=//')"
ZOO_DATALOGDIR="$(grep "^[[:space:]]*dataLogDir" "$ZOOCFG" | sed -e 's/.*=//')"
if [ -z "$ZOO_DATADIR" ]; then
echo "Unable to determine dataDir from $ZOOCFG"
exit 1
fi
if [ $FORCE ]; then
echo "Force enabled, data/txnlog directories will be re-initialized"
else
# we create if version-2 exists (ie real data), not the
# parent. See comments in following section for more insight
if [ -d "$ZOO_DATADIR/version-2" ]; then
echo "ZooKeeper data directory already exists at $ZOO_DATADIR (or use --force to force re-initialization)"
exit 1
fi
if [ -n "$ZOO_DATALOGDIR" ] && [ -d "$ZOO_DATALOGDIR/version-2" ]; then
echo "ZooKeeper txnlog directory already exists at $ZOO_DATALOGDIR (or use --force to force re-initialization)"
exit 1
fi
fi
# remove the child files that we're (not) interested in, not the
# parent. this allows for parent to be installed separately, and
# permissions to be set based on overarching requirements. by
# default we'll use the permissions of the user running this
# script for the files contained by the parent. note also by using
# -p the parent(s) will be created if it doesn't already exist
rm -rf "$ZOO_DATADIR/myid" 2>/dev/null >/dev/null
rm -rf "$ZOO_DATADIR/version-2" 2>/dev/null >/dev/null
mkdir -p "$ZOO_DATADIR/version-2"
if [ -n "$ZOO_DATALOGDIR" ]; then
rm -rf "$ZOO_DATALOGDIR/myid" 2>/dev/null >/dev/null
rm -rf "$ZOO_DATALOGDIR/version-2" 2>/dev/null >/dev/null
mkdir -p "$ZOO_DATALOGDIR/version-2"
fi
if [ $MYID ]; then
echo "Using myid of $MYID"
echo $MYID > "$ZOO_DATADIR/myid"
else
echo "No myid provided, be sure to specify it in $ZOO_DATADIR/myid if using non-standalone"
fi
touch "$ZOO_DATADIR/initialize"
}
while [ ! -z "$1" ]; do
case "$1" in
--configfile)
ZOOCFG=$2; shift 2
;;
--configfile=?*)
ZOOCFG=${1#*=}; shift 1
;;
--myid)
MYID=$2; shift 2
;;
--myid=?*)
MYID=${1#*=}; shift 1
;;
--force)
FORCE=1; shift 1
;;
-h)
usage
;;
--help)
usage
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done
initialize

26
bin/zkServer.cmd Normal file
View File

@ -0,0 +1,26 @@
@echo off
REM Licensed to the Apache Software Foundation (ASF) under one or more
REM contributor license agreements. See the NOTICE file distributed with
REM this work for additional information regarding copyright ownership.
REM The ASF licenses this file to You under the Apache License, Version 2.0
REM (the "License"); you may not use this file except in compliance with
REM the License. You may obtain a copy of the License at
REM
REM http://www.apache.org/licenses/LICENSE-2.0
REM
REM Unless required by applicable law or agreed to in writing, software
REM distributed under the License is distributed on an "AS IS" BASIS,
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
REM See the License for the specific language governing permissions and
REM limitations under the License.
setlocal
call "%~dp0zkEnv.cmd"
set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain
set ZOO_LOG_FILE=zookeeper-%USERNAME%-server-%COMPUTERNAME%.log
echo on
call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" "-Dzookeeper.log.file=%ZOO_LOG_FILE%" "-XX:+HeapDumpOnOutOfMemoryError" "-XX:OnOutOfMemoryError=cmd /c taskkill /pid %%%%p /t /f" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*
endlocal

325
bin/zkServer.sh Normal file
View File

@ -0,0 +1,325 @@
#!/usr/bin/env bash
# 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.
#
# If this scripted is run out of /usr/bin or some other system bin directory
# it should be linked to and not copied. Things like java jar files are found
# relative to the canonical path of this script.
#
# TODO_MA 马中华 注释: 如果一个大数据技术组件的底层源码实现是 java
# TODO_MA 马中华 注释: 那么 shell 命令的规范,就一定是先准备各种参数,然后通过 java 命令启动一个 JVM 执行某个类的 main()
# use POSIX interface, symlink is followed automatically
ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN="$(dirname "${ZOOBIN}")"
ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"
if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
. "$ZOOBINDIR"/../libexec/zkEnv.sh
else
. "$ZOOBINDIR"/zkEnv.sh
fi
# See the following page for extensive details on setting
# up the JVM to accept JMX remote management:
# http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html
# by default we allow local JMX connections
if [ "x$JMXLOCALONLY" = "x" ]
then
JMXLOCALONLY=false
fi
if [ "x$JMXDISABLE" = "x" ] || [ "$JMXDISABLE" = 'false' ]
then
echo "ZooKeeper JMX enabled by default" >&2
if [ "x$JMXPORT" = "x" ]
then
# for some reason these two options are necessary on jdk6 on Ubuntu
# accord to the docs they are not necessary, but otw jconsole cannot
# do a local attach
ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMain"
else
if [ "x$JMXAUTH" = "x" ]
then
JMXAUTH=false
fi
if [ "x$JMXSSL" = "x" ]
then
JMXSSL=false
fi
if [ "x$JMXLOG4J" = "x" ]
then
JMXLOG4J=true
fi
echo "ZooKeeper remote JMX Port set to $JMXPORT" >&2
echo "ZooKeeper remote JMX authenticate set to $JMXAUTH" >&2
echo "ZooKeeper remote JMX ssl set to $JMXSSL" >&2
echo "ZooKeeper remote JMX log4j set to $JMXLOG4J" >&2
ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=$JMXPORT -Dcom.sun.management.jmxremote.authenticate=$JMXAUTH -Dcom.sun.management.jmxremote.ssl=$JMXSSL -Dzookeeper.jmx.log4j.disable=$JMXLOG4J org.apache.zookeeper.server.quorum.QuorumPeerMain"
fi
else
echo "JMX disabled by user request" >&2
# TODO_MA 马中华 注释: 运行主类
# TODO_MA 马中华 注释ZK JVM 进程的名称: QuorumPeerMain
# TODO_MA 马中华 注释QuorumPeer + Main ==> 这个类的作用,就是启动 QuorumPeer
# TODO_MA 马中华 注释QuorumPeer 代表了一台服务器的全部功能实现!
ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
fi
if [ "x$SERVER_JVMFLAGS" != "x" ]
then
JVMFLAGS="$SERVER_JVMFLAGS $JVMFLAGS"
fi
if [ "x$2" != "x" ]
then
ZOOCFG="$ZOOCFGDIR/$2"
fi
# if we give a more complicated path to the config, don't screw around in $ZOOCFGDIR
if [ "x$(dirname "$ZOOCFG")" != "x$ZOOCFGDIR" ]
then
ZOOCFG="$2"
fi
if $cygwin
then
ZOOCFG=`cygpath -wp "$ZOOCFG"`
# cygwin has a "kill" in the shell itself, gets confused
KILL=/bin/kill
else
KILL=kill
fi
echo "Using config: $ZOOCFG" >&2
case "$OSTYPE" in
*solaris*)
GREP=/usr/xpg4/bin/grep
;;
*)
GREP=grep
;;
esac
ZOO_DATADIR="$($GREP "^[[:space:]]*dataDir" "$ZOOCFG" | sed -e 's/.*=//')"
ZOO_DATADIR="$(echo -e "${ZOO_DATADIR}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
ZOO_DATALOGDIR="$($GREP "^[[:space:]]*dataLogDir" "$ZOOCFG" | sed -e 's/.*=//')"
# iff autocreate is turned off and the datadirs don't exist fail
# immediately as we can't create the PID file, etc..., anyway.
if [ -n "$ZOO_DATADIR_AUTOCREATE_DISABLE" ]; then
if [ ! -d "$ZOO_DATADIR/version-2" ]; then
echo "ZooKeeper data directory is missing at $ZOO_DATADIR fix the path or run initialize"
exit 1
fi
if [ -n "$ZOO_DATALOGDIR" ] && [ ! -d "$ZOO_DATALOGDIR/version-2" ]; then
echo "ZooKeeper txnlog directory is missing at $ZOO_DATALOGDIR fix the path or run initialize"
exit 1
fi
ZOO_DATADIR_AUTOCREATE="-Dzookeeper.datadir.autocreate=false"
fi
if [ -z "$ZOOPIDFILE" ]; then
if [ ! -d "$ZOO_DATADIR" ]; then
mkdir -p "$ZOO_DATADIR"
fi
ZOOPIDFILE="$ZOO_DATADIR/zookeeper_server.pid"
else
# ensure it exists, otw stop will fail
mkdir -p "$(dirname "$ZOOPIDFILE")"
fi
if [ ! -w "$ZOO_LOG_DIR" ] ; then
mkdir -p "$ZOO_LOG_DIR"
fi
ZOO_LOG_FILE=zookeeper-$USER-server-$HOSTNAME.log
_ZOO_DAEMON_OUT="$ZOO_LOG_DIR/zookeeper-$USER-server-$HOSTNAME.out"
# TODO_MA 马中华 注释: zkServer.sh start
# TODO_MA 马中华 注释: $1 = start
case $1 in
start)
echo -n "Starting zookeeper ... "
if [ -f "$ZOOPIDFILE" ]; then
if kill -0 `cat "$ZOOPIDFILE"` > /dev/null 2>&1; then
echo $command already running as process `cat "$ZOOPIDFILE"`.
exit 1
fi
fi
# TODO_MA 马中华 注释: 核心的启动命令4
# TODO_MA 马中华 注释: $JAVA = $JAVA_HOME/bin/java
# TODO_MA 马中华 注释: $ZOOMAIN = 核心java类 = QuorumPeerMain
# TODO_MA 马中华 注释: "$ZOOCFG" = zoo.cfg 的路径 = $ZOOKEEPER_HOME/conf/zoo.cfg
nohup "$JAVA" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" \
"-Dzookeeper.log.file=${ZOO_LOG_FILE}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='kill -9 %p' \
-cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
if [ $? -eq 0 ]
then
case "$OSTYPE" in
*solaris*)
/bin/echo "${!}\\c" > "$ZOOPIDFILE"
;;
*)
/bin/echo -n $! > "$ZOOPIDFILE"
;;
esac
if [ $? -eq 0 ];
then
sleep 1
pid=$(cat "${ZOOPIDFILE}")
if ps -p "${pid}" > /dev/null 2>&1; then
echo STARTED
else
echo FAILED TO START
exit 1
fi
else
echo FAILED TO WRITE PID
exit 1
fi
else
echo SERVER DID NOT START
exit 1
fi
;;
start-foreground)
ZOO_CMD=(exec "$JAVA")
if [ "${ZOO_NOEXEC}" != "" ]; then
ZOO_CMD=("$JAVA")
fi
"${ZOO_CMD[@]}" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" \
"-Dzookeeper.log.file=${ZOO_LOG_FILE}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='kill -9 %p' \
-cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG"
;;
print-cmd)
echo "\"$JAVA\" $ZOO_DATADIR_AUTOCREATE -Dzookeeper.log.dir=\"${ZOO_LOG_DIR}\" \
-Dzookeeper.log.file=\"${ZOO_LOG_FILE}\" -Dzookeeper.root.logger=\"${ZOO_LOG4J_PROP}\" \
-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='kill -9 %p' \
-cp \"$CLASSPATH\" $JVMFLAGS $ZOOMAIN \"$ZOOCFG\" > \"$_ZOO_DAEMON_OUT\" 2>&1 < /dev/null"
;;
stop)
echo -n "Stopping zookeeper ... "
if [ ! -f "$ZOOPIDFILE" ]
then
echo "no zookeeper to stop (could not find file $ZOOPIDFILE)"
else
$KILL $(cat "$ZOOPIDFILE")
rm "$ZOOPIDFILE"
sleep 1
echo STOPPED
fi
exit 0
;;
version)
ZOOMAIN=org.apache.zookeeper.version.VersionInfoMain
$JAVA -cp "$CLASSPATH" $ZOOMAIN 2> /dev/null
;;
restart)
shift
"$0" stop ${@}
sleep 3
"$0" start ${@}
;;
status)
# -q is necessary on some versions of linux where nc returns too quickly, and no stat result is output
isSSL="false"
clientPortAddress=`$GREP "^[[:space:]]*clientPortAddress[^[:alpha:]]" "$ZOOCFG" | sed -e 's/.*=//'`
if ! [ $clientPortAddress ]
then
clientPortAddress="localhost"
fi
clientPort=`$GREP "^[[:space:]]*clientPort[^[:alpha:]]" "$ZOOCFG" | sed -e 's/.*=//'`
if ! [[ "$clientPort" =~ ^[0-9]+$ ]]
then
dataDir=`$GREP "^[[:space:]]*dataDir" "$ZOOCFG" | sed -e 's/.*=//'`
myid=`cat "$dataDir/myid" 2> /dev/null`
if ! [[ "$myid" =~ ^[0-9]+$ ]] ; then
echo "myid could not be determined, will not able to locate clientPort in the server configs."
else
clientPortAndAddress=`$GREP "^[[:space:]]*server.$myid=.*;.*" "$ZOOCFG" | sed -e 's/.*=//' | sed -e 's/.*;//'`
if [ ! "$clientPortAndAddress" ] ; then
echo "Client port not found in static config file. Looking in dynamic config file."
dynamicConfigFile=`$GREP "^[[:space:]]*dynamicConfigFile" "$ZOOCFG" | sed -e 's/.*=//'`
clientPortAndAddress=`$GREP "^[[:space:]]*server.$myid=.*;.*" "$dynamicConfigFile" | sed -e 's/.*=//' | sed -e 's/.*;//'`
fi
if [ ! "$clientPortAndAddress" ] ; then
echo "Client port not found in the server configs"
else
if [[ "$clientPortAndAddress" =~ ^.*:[0-9]+ ]] ; then
if [[ "$clientPortAndAddress" =~ \[.*\]:[0-9]+ ]] ; then
# Extracts address from address:port for example extracts 127::1 from "[127::1]:2181"
clientPortAddress=`echo "$clientPortAndAddress" | sed -e 's|\[||' | sed -e 's|\]:.*||'`
else
clientPortAddress=`echo "$clientPortAndAddress" | sed -e 's/:.*//'`
fi
fi
clientPort=`echo "$clientPortAndAddress" | sed -e 's/.*://'`
fi
fi
fi
if [ ! "$clientPort" ] ; then
echo "Client port not found. Looking for secureClientPort in the static config."
secureClientPort=`$GREP "^[[:space:]]*secureClientPort[^[:alpha:]]" "$ZOOCFG" | sed -e 's/.*=//'`
if [ "$secureClientPort" ] ; then
isSSL="true"
clientPort=$secureClientPort
clientPortAddress=`$GREP "^[[:space:]]*secureClientPortAddress[^[:alpha:]]" "$ZOOCFG" | sed -e 's/.*=//'`
if ! [ $clientPortAddress ]
then
clientPortAddress="localhost"
fi
else
echo "Unable to find either secure or unsecure client port in any configs. Terminating."
exit 1
fi
fi
echo "Client port found: $clientPort. Client address: $clientPortAddress. Client SSL: $isSSL."
STAT=`"$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-Dzookeeper.log.file=${ZOO_LOG_FILE}" \
-cp "$CLASSPATH" $CLIENT_JVMFLAGS $JVMFLAGS org.apache.zookeeper.client.FourLetterWordMain \
$clientPortAddress $clientPort srvr $isSSL 2> /dev/null \
| $GREP Mode`
if [ "x$STAT" = "x" ]
then
if [ "$isSSL" = "true" ] ; then
echo " "
echo "Note: We used secureClientPort ($secureClientPort) to establish connection, but we failed. The 'status'"
echo " command establishes a client connection to the server to execute diagnostic commands. Please make sure you"
echo " provided all the Client SSL connection related parameters in the CLIENT_JVMFLAGS environment variable! E.g.:"
echo " CLIENT_JVMFLAGS=\"-Dzookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty"
echo " -Dzookeeper.ssl.trustStore.location=/tmp/clienttrust.jks -Dzookeeper.ssl.trustStore.password=password"
echo " -Dzookeeper.ssl.keyStore.location=/tmp/client.jks -Dzookeeper.ssl.keyStore.password=password"
echo " -Dzookeeper.client.secure=true\" ./zkServer.sh status"
echo " "
fi
echo "Error contacting service. It is probably not running."
exit 1
else
echo $STAT
exit 0
fi
;;
*)
echo "Usage: $0 [--config <conf-dir>] {start|start-foreground|stop|version|restart|status|print-cmd}" >&2
esac

24
bin/zkSnapShotToolkit.cmd Normal file
View File

@ -0,0 +1,24 @@
@echo off
REM Licensed to the Apache Software Foundation (ASF) under one or more
REM contributor license agreements. See the NOTICE file distributed with
REM this work for additional information regarding copyright ownership.
REM The ASF licenses this file to You under the Apache License, Version 2.0
REM (the "License"); you may not use this file except in compliance with
REM the License. You may obtain a copy of the License at
REM
REM http://www.apache.org/licenses/LICENSE-2.0
REM
REM Unless required by applicable law or agreed to in writing, software
REM distributed under the License is distributed on an "AS IS" BASIS,
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
REM See the License for the specific language governing permissions and
REM limitations under the License.
setlocal
call "%~dp0zkEnv.cmd"
set ZOOMAIN=org.apache.zookeeper.server.SnapshotFormatter
call %JAVA% -cp "%CLASSPATH%" %ZOOMAIN% %*
endlocal

38
bin/zkSnapShotToolkit.sh Normal file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env bash
# 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.
#
# If this scripted is run out of /usr/bin or some other system bin directory
# it should be linked to and not copied. Things like java jar files are found
# relative to the canonical path of this script.
#
# use POSIX interface, symlink is followed automatically
ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN="$(dirname "${ZOOBIN}")"
ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"
if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
. "$ZOOBINDIR"/../libexec/zkEnv.sh
else
. "$ZOOBINDIR"/zkEnv.sh
fi
"$JAVA" -cp "$CLASSPATH" $JVMFLAGS \
org.apache.zookeeper.server.SnapshotFormatter "$@"

24
bin/zkTxnLogToolkit.cmd Normal file
View File

@ -0,0 +1,24 @@
@echo off
REM Licensed to the Apache Software Foundation (ASF) under one or more
REM contributor license agreements. See the NOTICE file distributed with
REM this work for additional information regarding copyright ownership.
REM The ASF licenses this file to You under the Apache License, Version 2.0
REM (the "License"); you may not use this file except in compliance with
REM the License. You may obtain a copy of the License at
REM
REM http://www.apache.org/licenses/LICENSE-2.0
REM
REM Unless required by applicable law or agreed to in writing, software
REM distributed under the License is distributed on an "AS IS" BASIS,
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
REM See the License for the specific language governing permissions and
REM limitations under the License.
setlocal
call "%~dp0zkEnv.cmd"
set ZOOMAIN=org.apache.zookeeper.server.persistence.TxnLogToolkit
call %JAVA% -cp "%CLASSPATH%" %ZOOMAIN% %*
endlocal

38
bin/zkTxnLogToolkit.sh Normal file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env bash
# 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.
#
# If this scripted is run out of /usr/bin or some other system bin directory
# it should be linked to and not copied. Things like java jar files are found
# relative to the canonical path of this script.
#
# use POSIX interface, symlink is followed automatically
ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN="$(dirname "${ZOOBIN}")"
ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"
if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
. "$ZOOBINDIR"/../libexec/zkEnv.sh
else
. "$ZOOBINDIR"/zkEnv.sh
fi
"$JAVA" -cp "$CLASSPATH" $JVMFLAGS \
org.apache.zookeeper.server.persistence.TxnLogToolkit "$@"

63
checkstyle-simple.xml Normal file
View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<!-- This is a checkstyle configuration file. For descriptions of
what the following rules do, please see the checkstyle configuration
page at http://checkstyle.sourceforge.net/config.html -->
<module name="Checker">
<!-- Prevent *Tests.java as tools may not pick them up -->
<module name="RegexpOnFilename">
<property name="fileNamePattern" value=".*Tests\.java$" />
</module>
<module name="SuppressionFilter">
<property name="file" value="${checkstyle.suppressions.file}" default="suppressions.xml" />
</module>
<!-- All Java AST specific tests live under TreeWalker module. -->
<module name="TreeWalker">
<!-- Allow use of comment to suppress javadocstyle -->
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
<property name="checkFormat" value="$1"/>
</module>
<module name="TodoComment">
<!-- Checks that disallowed strings are not used in comments. -->
<property name="format" value="(@author)" />
</module>
<module name="PackageName">
<!-- Validates identifiers for package names against the
supplied expression. -->
<!-- Here the default checkstyle rule restricts package name parts to
seven characters, this is not in line with common practice at Google.
-->
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
<property name="severity" value="error"/>
</module>
</module>
</module>

436
checkstyle-strict.xml Normal file
View File

@ -0,0 +1,436 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<!-- This is a checkstyle configuration file. For descriptions of
what the following rules do, please see the checkstyle configuration
page at http://checkstyle.sourceforge.net/config.html -->
<module name="Checker">
<module name="FileTabCharacter">
<!-- Checks that there are no tab characters in the file. -->
</module>
<module name="RegexpSingleline">
<!-- Checks that TODOs don't have stuff in parenthesis, e.g., username. -->
<property name="format" value="((//.*)|(\*.*))TODO\(" />
<property name="message" value="TODO comments must not include usernames." />
<property name="severity" value="error" />
</module>
<module name="RegexpSingleline">
<property name="format" value="\s+$"/>
<property name="message" value="Trailing whitespace"/>
<property name="severity" value="error"/>
</module>
<module name="RegexpSingleline">
<property name="format" value="Throwables.propagate\("/>
<property name="message" value="Throwables.propagate is deprecated"/>
<property name="severity" value="error"/>
</module>
<!-- Prevent *Tests.java as tools may not pick them up -->
<module name="RegexpOnFilename">
<property name="fileNamePattern" value=".*Tests\.java$" />
</module>
<module name="SuppressionFilter">
<property name="file" value="${checkstyle.suppressions.file}" default="suppressions.xml" />
</module>
<!-- All Java AST specific tests live under TreeWalker module. -->
<module name="TreeWalker">
<!-- Allow use of comment to suppress javadocstyle -->
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
<property name="checkFormat" value="$1"/>
</module>
<module name="TodoComment">
<!-- Checks that disallowed strings are not used in comments. -->
<property name="format" value="(FIXME)|(XXX)|(@author)" />
</module>
<!--
IMPORT CHECKS
-->
<module name="RedundantImport">
<!-- Checks for redundant import statements. -->
<property name="severity" value="error"/>
<message key="import.redundancy"
value="Redundant import {0}."/>
</module>
<module name="ImportOrder">
<property name="severity" value="error"/>
<!-- This ensures that static imports go first. -->
<property name="option" value="top"/>
<property name="sortStaticImportsAlphabetically" value="true"/>
<property name="tokens" value="STATIC_IMPORT, IMPORT"/>
<message key="import.ordering"
value="Import {0} appears after other imports that it should precede"/>
</module>
<module name="AvoidStarImport">
<property name="severity" value="error"/>
</module>
<module name="IllegalImport">
<property name="illegalPkgs" value="autovalue.shaded, avro.shaded, bk-shade, com.google.api.client.repackaged, com.google.appengine.repackaged, io.netty.util.internal"/>
</module>
<module name="RedundantModifier">
<!-- Checks for redundant modifiers on various symbol definitions.
See: http://checkstyle.sourceforge.net/config_modifier.html#RedundantModifier
-->
<property name="tokens" value="METHOD_DEF, VARIABLE_DEF, ANNOTATION_FIELD_DEF, INTERFACE_DEF, CLASS_DEF, ENUM_DEF"/>
</module>
<!--
IllegalImport cannot blacklist classes, and c.g.api.client.util is used for some shaded
code and some useful code. So we need to fall back to Regexp.
-->
<module name="RegexpSinglelineJava">
<property name="format" value="com\.google\.api\.client\.util\.(ByteStreams|Charsets|Collections2|Joiner|Lists|Maps|Objects|Preconditions|Sets|Strings|Throwables)"/>
</module>
<!--
Require static importing from Preconditions.
-->
<module name="RegexpSinglelineJava">
<property name="format" value="^import com.google.common.base.Preconditions;$"/>
<property name="message" value="Static import functions from Guava Preconditions"/>
</module>
<module name="UnusedImports">
<property name="severity" value="error"/>
<property name="processJavadoc" value="true"/>
<message key="import.unused"
value="Unused import: {0}."/>
</module>
<!--
JAVADOC CHECKS
-->
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
<module name="JavadocMethod">
<property name="scope" value="protected"/>
<property name="severity" value="error"/>
<property name="allowMissingJavadoc" value="true"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
<property name="allowUndeclaredRTE" value="true"/>
</module>
<!-- Check that paragraph tags are used correctly in Javadoc. -->
<module name="JavadocParagraph"/>
<module name="JavadocType">
<property name="scope" value="protected"/>
<property name="severity" value="error"/>
<property name="allowMissingParamTags" value="true"/>
</module>
<module name="JavadocStyle">
<property name="severity" value="error"/>
<property name="checkHtml" value="true"/>
</module>
<!--
NAMING CHECKS
-->
<!-- Item 38 - Adhere to generally accepted naming conventions -->
<module name="PackageName">
<!-- Validates identifiers for package names against the
supplied expression. -->
<!-- Here the default checkstyle rule restricts package name parts to
seven characters, this is not in line with common practice at Google.
-->
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
<property name="severity" value="error"/>
</module>
<module name="TypeNameCheck">
<!-- Validates static, final fields against the
expression "^[A-Z][a-zA-Z0-9]*$". -->
<metadata name="altname" value="TypeName"/>
<property name="severity" value="error"/>
</module>
<module name="ConstantNameCheck">
<!-- Validates non-private, static, final fields against the supplied
public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
<metadata name="altname" value="ConstantName"/>
<property name="applyToPublic" value="true"/>
<property name="applyToProtected" value="true"/>
<property name="applyToPackage" value="true"/>
<property name="applyToPrivate" value="false"/>
<property name="format" value="^([A-Z][A-Za-z0-9_]*|FLAG_.*)$"/>
<message key="name.invalidPattern"
value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
<property name="severity" value="error"/>
</module>
<module name="StaticVariableNameCheck">
<!-- Validates static, non-final fields against the supplied
expression "^[a-z][a-zA-Z0-9]*_?$". -->
<metadata name="altname" value="StaticVariableName"/>
<property name="applyToPublic" value="true"/>
<property name="applyToProtected" value="true"/>
<property name="applyToPackage" value="true"/>
<property name="applyToPrivate" value="true"/>
<property name="format" value="^[a-z][a-zA-Z0-9]*_?$"/>
<property name="severity" value="error"/>
</module>
<module name="MemberNameCheck">
<!-- Validates non-static members against the supplied expression. -->
<metadata name="altname" value="MemberName"/>
<property name="applyToPublic" value="true"/>
<property name="applyToProtected" value="true"/>
<property name="applyToPackage" value="true"/>
<property name="applyToPrivate" value="true"/>
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
<property name="severity" value="error"/>
</module>
<module name="MethodNameCheck">
<!-- Validates identifiers for method names. -->
<metadata name="altname" value="MethodName"/>
<property name="format" value="(^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$|Void)"/>
<property name="severity" value="error"/>
</module>
<module name="ParameterName">
<!-- Validates identifiers for method parameters against the
expression "^[a-z][a-zA-Z0-9]*$". -->
<property name="severity" value="error"/>
</module>
<module name="LocalFinalVariableName">
<!-- Validates identifiers for local final variables against the
expression "^[a-z][a-zA-Z0-9]*$". -->
<property name="severity" value="error"/>
</module>
<module name="LocalVariableName">
<!-- Validates identifiers for local variables against the
expression "^[a-z][a-zA-Z0-9]*$". -->
<property name="severity" value="error"/>
</module>
<!-- Type parameters must be either one of the four blessed letters
T, K, V, W, X or else be capital-case terminated with a T,
such as MyGenericParameterT -->
<module name="ClassTypeParameterName">
<property name="format" value="^(((T|K|V|W|X|R)[0-9]*)|([A-Z][a-z][a-zA-Z]*))$"/>
<property name="severity" value="error"/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="^(((T|K|V|W|X|R)[0-9]*)|([A-Z][a-z][a-zA-Z]*T))$"/>
<property name="severity" value="error"/>
</module>
<module name="InterfaceTypeParameterName">
<property name="format" value="^(((T|K|V|W|X|R)[0-9]*)|([A-Z][a-z][a-zA-Z]*T))$"/>
<property name="severity" value="error"/>
</module>
<!--
LENGTH and CODING CHECKS
-->
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="120"/>
<property name="severity" value="error"/>
<!--
The default ignore pattern exempts the following elements:
- import statements
- long URLs inside comments
-->
<property name="ignorePattern"
value="^(package .*;\s*)|(import .*;\s*)|( *\* .*https?://.*)$"/>
</module>
<module name="LeftCurly">
<!-- Checks for placement of the left curly brace ('{'). -->
<property name="severity" value="error"/>
</module>
<module name="RightCurly">
<!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
the same line. e.g., the following example is fine:
<pre>
if {
...
} else
</pre>
-->
<!-- This next example is not fine:
<pre>
if {
...
}
else
</pre>
-->
<property name="option" value="same"/>
<property name="severity" value="error"/>
</module>
<!-- Checks for braces around if and else blocks -->
<module name="NeedBraces">
<property name="severity" value="error"/>
<property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
</module>
<module name="UpperEll">
<!-- Checks that long constants are defined with an upper ell.-->
<property name="severity" value="error"/>
</module>
<module name="FallThrough">
<!-- Warn about falling through to the next case statement. Similar to
javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
on the last non-blank line preceding the fallen-into case contains 'fall through' (or
some other variants that we don't publicized to promote consistency).
-->
<property name="reliefPattern"
value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
<property name="severity" value="error"/>
</module>
<!-- Checks for over-complicated boolean expressions. -->
<module name="SimplifyBooleanExpression"/>
<!-- Detects empty statements (standalone ";" semicolon). -->
<module name="EmptyStatement"/>
<!--
MODIFIERS CHECKS
-->
<module name="ModifierOrder">
<!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
8.4.3. The prescribed order is:
public, protected, private, abstract, static, final, transient, volatile,
synchronized, native, strictfp
-->
<property name="severity" value="error"/>
</module>
<!--
WHITESPACE CHECKS
-->
<module name="WhitespaceAround">
<!-- Checks that various tokens are surrounded by whitespace.
This includes most binary operators and keywords followed
by regular or curly braces.
-->
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
<property name="severity" value="error"/>
</module>
<module name="WhitespaceAfter">
<!-- Checks that commas, semicolons and typecasts are followed by
whitespace.
-->
<property name="tokens" value="COMMA, SEMI, TYPECAST"/>
</module>
<module name="NoWhitespaceAfter">
<!-- Checks that there is no whitespace after various unary operators.
Linebreaks are allowed.
-->
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
UNARY_PLUS"/>
<property name="allowLineBreaks" value="true"/>
<property name="severity" value="error"/>
</module>
<module name="NoWhitespaceBefore">
<!-- Checks that there is no whitespace before various unary operators.
Linebreaks are allowed.
-->
<property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
<property name="allowLineBreaks" value="true"/>
<property name="severity" value="error"/>
</module>
<module name="OperatorWrap">
<!-- Checks that operators like + and ? appear at newlines rather than
at the end of the previous line.
-->
<property name="option" value="NL"/>
<property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL,
GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD,
NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/>
</module>
<module name="OperatorWrap">
<!-- Checks that assignment operators are at the end of the line. -->
<property name="option" value="eol"/>
<property name="tokens" value="ASSIGN"/>
</module>
<module name="ParenPad">
<!-- Checks that there is no whitespace before close parens or after
open parens.
-->
<property name="severity" value="error"/>
</module>
</module>
</module>

View File

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!--
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. See accompanying LICENSE file.
-->
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<!-- suppress all checks in the generated directories -->
<suppress checks=".*" files=".+[\\/]classes[\\/].+\.java" />
<suppress checks=".*" files=".+[\\/]generated[\\/].+\.java" />
<suppress checks=".*" files=".+[\\/]generated-sources[\\/].+\.java" />
<suppress checks=".*" files=".+[\\/]generated-test-sources[\\/].+\.java" />
<suppress checks="LineLength" files=".+[\\/]jute[\\/].+\.java"/>
<!-- TODO ZOOKEEPER-3508 -->
<suppress checks="LineLength" files=".+[\\/]zookeeper-server[\\/].+\.java"/>
<!-- TODO ZOOKEEPER-3507 -->
<suppress checks=".*Name.*" files=".+[\\/]zookeeper-server[\\/].+\.java"/>
<!-- TODO ZOOKEEPER-3469 -->
<suppress checks="Javadoc.+" files=".+[\\/]zookeeper-server[\\/].+\.java"/>
</suppressions>

24
conf/configuration.xsl Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="configuration">
<html>
<body>
<table border="1">
<tr>
<td>name</td>
<td>value</td>
<td>description</td>
</tr>
<xsl:for-each select="property">
<tr>
<td><a name="{name}"><xsl:value-of select="name"/></a></td>
<td><xsl:value-of select="value"/></td>
<td><xsl:value-of select="description"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

82
conf/log4j.properties Normal file
View File

@ -0,0 +1,82 @@
# Copyright 2012 The Apache Software Foundation
#
# 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.
# Define some default values that can be overridden by system properties
zookeeper.root.logger=INFO, CONSOLE
zookeeper.console.threshold=INFO
zookeeper.log.dir=.
zookeeper.log.file=zookeeper.log
zookeeper.log.threshold=INFO
zookeeper.log.maxfilesize=256MB
zookeeper.log.maxbackupindex=20
zookeeper.tracelog.dir=${zookeeper.log.dir}
zookeeper.tracelog.file=zookeeper_trace.log
log4j.rootLogger=${zookeeper.root.logger}
#
# console
# Add "console" to rootlogger above if you want to use this
#
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=${zookeeper.console.threshold}
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
#
# Add ROLLINGFILE to rootLogger to get log file output
#
log4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLINGFILE.Threshold=${zookeeper.log.threshold}
log4j.appender.ROLLINGFILE.File=${zookeeper.log.dir}/${zookeeper.log.file}
log4j.appender.ROLLINGFILE.MaxFileSize=${zookeeper.log.maxfilesize}
log4j.appender.ROLLINGFILE.MaxBackupIndex=${zookeeper.log.maxbackupindex}
log4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
#
# Add TRACEFILE to rootLogger to get log file output
# Log TRACE level and above messages to a log file
#
log4j.appender.TRACEFILE=org.apache.log4j.FileAppender
log4j.appender.TRACEFILE.Threshold=TRACE
log4j.appender.TRACEFILE.File=${zookeeper.tracelog.dir}/${zookeeper.tracelog.file}
log4j.appender.TRACEFILE.layout=org.apache.log4j.PatternLayout
### Notice we are including log4j's NDC here (%x)
log4j.appender.TRACEFILE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L][%x] - %m%n
#
# zk audit logging
#
zookeeper.auditlog.file=zookeeper_audit.log
zookeeper.auditlog.threshold=INFO
audit.logger=INFO, RFAAUDIT
log4j.logger.org.apache.zookeeper.audit.Log4jAuditLogger=${audit.logger}
log4j.additivity.org.apache.zookeeper.audit.Log4jAuditLogger=false
log4j.appender.RFAAUDIT=org.apache.log4j.RollingFileAppender
log4j.appender.RFAAUDIT.File=${zookeeper.log.dir}/${zookeeper.auditlog.file}
log4j.appender.RFAAUDIT.layout=org.apache.log4j.PatternLayout
log4j.appender.RFAAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
log4j.appender.RFAAUDIT.Threshold=${zookeeper.auditlog.threshold}
# Max log file size of 10MB
log4j.appender.RFAAUDIT.MaxFileSize=10MB
log4j.appender.RFAAUDIT.MaxBackupIndex=10

36
conf/zoo.cfg Normal file
View File

@ -0,0 +1,36 @@
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial synchronization phase can take
initLimit=10
# The number of ticks that can pass between sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/home/bigdata/data/zkdata
dataLogDir=/home/bigdata/data/zklog/
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
# electionAlg=3 = FastLeaderElection
electionAlg=3
maxClientCnxns=60
# 服务器的类型: observer/participant具有选举权的节点leader follower
peerType=observer/participant
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
autopurge.purgeInterval=1
server.2=bigdata02:2888
server.3=bigdata03:2888:3888
server.4=bigdata04:2888:3888:participant
server.5=bigdata05:2888:3888:observer

36
conf/zoo_sample.cfg Normal file
View File

@ -0,0 +1,36 @@
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
## Metrics Providers
#
# https://prometheus.io Metrics Exporter
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true

31
dev/docker/Dockerfile Normal file
View File

@ -0,0 +1,31 @@
#
# 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.
#
FROM maven:3.6.3-jdk-8
RUN apt-get update
RUN apt-get install -y \
g++ \
cmake \
autoconf \
pkg-config \
libcppunit-dev \
libtool \
openssl \
libssl-dev

72
dev/docker/run.sh Normal file
View File

@ -0,0 +1,72 @@
#!/bin/bash
# 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.
set -e -x -u
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
export IMAGE_NAME="zookeeper/dev"
pushd ${SCRIPT_DIR}
docker build --rm=true -t ${IMAGE_NAME} .
popd
if [ "$(uname -s)" == "Linux" ]; then
USER_NAME=${SUDO_USER:=$USER}
USER_ID=$(id -u "${USER_NAME}")
GROUP_ID=$(id -g "${USER_NAME}")
LOCAL_HOME=$(realpath ~)
else # boot2docker uid and gid
USER_NAME=$USER
USER_ID=1000
GROUP_ID=50
LOCAL_HOME="/Users/${USER_NAME}"
fi
docker build -t "${IMAGE_NAME}-${USER_NAME}" - <<UserSpecificDocker
FROM ${IMAGE_NAME}
RUN groupadd --non-unique -g ${GROUP_ID} ${USER_NAME} && \
useradd -g ${GROUP_ID} -u ${USER_ID} -k /root -m ${USER_NAME}
ENV HOME /home/${USER_NAME}
UserSpecificDocker
ZOOKEEPER_ROOT=${SCRIPT_DIR}/../..
CMD="
echo
echo 'Welcome to Apache ZooKeeper Development Env'
echo 'To build, execute'
echo ' mvn clean install'
echo
bash
"
pushd ${ZOOKEEPER_ROOT}
docker run -i -t \
--rm=true \
-w ${ZOOKEEPER_ROOT} \
-u "${USER}" \
-v "$(realpath $ZOOKEEPER_ROOT):${ZOOKEEPER_ROOT}" \
-v "${LOCAL_HOME}:/home/${USER_NAME}" \
${IMAGE_NAME}-${USER_NAME} \
bash -c "${CMD}"
popd

11
excludeFindBugsFilter.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<!-- this work work on JDK11 https://github.com/spotbugs/spotbugs-maven-plugin/issues/92 -->
<Bug pattern="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE"/>
<!-- this problem is to be addressed in ZOOKEEPER-3227 -->
<Bug pattern="DM_DEFAULT_ENCODING"/>
</FindBugsFilter>

54
owaspSuppressions.xml Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.2.xsd">
<suppress>
<!-- ZOOKEEPER-3217 -->
<cve>CVE-2018-8088</cve>
</suppress>
<suppress>
<!-- ZOOKEEPER-3262 -->
<cve>CVE-2018-8012</cve>
</suppress>
<suppress>
<!-- ZOOKEEPER-3262 -->
<cve>CVE-2016-5017</cve>
</suppress>
<suppress>
<!-- https://github.com/jeremylong/DependencyCheck/issues/1653
False positive on Netty 4.x-->
<cve>CVE-2018-12056</cve>
</suppress>
<suppress>
<!-- Seems like false positive - we are not using Prometheus
2.x, rather the client which lastest is 0.6. at the time of
this writing -->
<cve>CVE-2019-3826</cve>
</suppress>
<suppress>
<!-- false positive for us, it is about log4j server in log4j-1.2.17.jar
ZOOKEEPER-3677 -->
<cve>CVE-2019-17571</cve>
</suppress>
<suppress>
<!-- it only affects the log4j SmtpAppender users. As Log4J 1.2 is EOL now, we can't fix this unless we
upgrade to log4j 2. See ZOOKEEPER-3817 -->
<cve>CVE-2020-9488</cve>
</suppress>
</suppressions>

997
pom.xml Normal file
View File

@ -0,0 +1,997 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
/**
* 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.
*/
-->
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache</groupId>
<artifactId>apache</artifactId>
<version>23</version>
<relativePath />
<!-- no parent resolution -->
</parent>
<groupId>org.apache.zookeeper</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<!-- to change version: mvn -\-batch-mode release:update-versions -DdevelopmentVersion=3.6.0-SNAPSHOT -->
<version>3.6.3</version>
<name>Apache ZooKeeper</name>
<description>
ZooKeeper is a centralized service for maintaining configuration information, naming,
providing distributed synchronization, and providing group services. All of these kinds
of services are used in some form or another by distributed applications. Each time they
are implemented there is a lot of work that goes into fixing the bugs and race conditions
that are inevitable. Because of the difficulty of implementing these kinds of services,
applications initially usually skimp on them ,which make them brittle in the presence of
change and difficult to manage. Even when done correctly, different implementations of
these services lead to management complexity when the applications are deployed.
</description>
<url>http://zookeeper.apache.org</url>
<inceptionYear>2008</inceptionYear>
<!-- Set here so we can consistently use the correct name, even on branches with
an ASF parent pom older than v15. Also uses the url from v18.
-->
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<modules>
<module>zookeeper-docs</module>
<module>zookeeper-jute</module>
<module>zookeeper-server</module>
<module>zookeeper-metrics-providers</module>
<module>zookeeper-client</module>
<module>zookeeper-recipes</module>
<module>zookeeper-assembly</module>
<module>zookeeper-compatibility-tests</module>
</modules>
<scm>
<connection>scm:git:https://gitbox.apache.org/repos/asf/zookeeper.git</connection>
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/zookeeper.git</developerConnection>
<url>https://gitbox.apache.org/repos/asf/zookeeper.git</url>
<tag>release-3.6.3-2</tag>
</scm>
<issueManagement>
<system>JIRA</system>
<url>http://issues.apache.org/jira/browse/ZOOKEEPER</url>
</issueManagement>
<ciManagement>
<system>jenkins</system>
<url>https://ci-hadoop.apache.org/view/ZooKeeper/</url>
</ciManagement>
<mailingLists>
<mailingList>
<name>User List</name>
<subscribe>user-subscribe@zookeeper.apache.org</subscribe>
<unsubscribe>user-unsubscribe@zookeeper.apache.org</unsubscribe>
<post>user@zookeeper.apache.org</post>
<archive>http://mail-archives.apache.org/mod_mbox/zookeeper-user/</archive>
</mailingList>
<mailingList>
<name>Developer List</name>
<subscribe>dev-subscribe@zookeeper.apache.org</subscribe>
<unsubscribe>dev-unsubscribe@zookeeper.apache.org</unsubscribe>
<post>dev@zookeeper.apache.org</post>
<archive>http://mail-archives.apache.org/mod_mbox/zookeeper-dev/</archive>
</mailingList>
<mailingList>
<name>Commits List</name>
<subscribe>commits-subscribe@zookeeper.apache.org</subscribe>
<unsubscribe>commits-unsubscribe@zookeeper.apache.org</unsubscribe>
<archive>http://mail-archives.apache.org/mod_mbox/zookeeper-commits/</archive>
</mailingList>
<mailingList>
<name>Issues List</name>
<subscribe>issues-subscribe@zookeeper.apache.org</subscribe>
<unsubscribe>issues-unsubscribe@zookeeper.apache.org</unsubscribe>
<archive>https://lists.apache.org/list.html?issues@zookeeper.apache.org</archive>
</mailingList>
<mailingList>
<name>Notifications List</name>
<subscribe>notifications-subscribe@zookeeper.apache.org</subscribe>
<unsubscribe>notifications-unsubscribe@zookeeper.apache.org</unsubscribe>
<archive>https://lists.apache.org/list.html?notifications@zookeeper.apache.org</archive>
</mailingList>
</mailingLists>
<developers>
<developer>
<id>tdunning</id>
<name>Ted Dunning </name>
<email>tdunning@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>camille</id>
<name>Camille Fournier</name>
<email>camille@apache.org</email>
<timezone>-5</timezone>
</developer>
<developer>
<id>phunt</id>
<name>Patrick Hunt</name>
<email>phunt@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>fpj</id>
<name>Flavio Junqueira</name>
<email>fpj@apache.org</email>
<timezone>+0</timezone>
</developer>
<developer>
<id>ivank</id>
<name>Ivan Kelly</name>
<email>ivank@apache.org</email>
<timezone>+2</timezone>
</developer>
<developer>
<id>mahadev</id>
<name>Mahadev Konar</name>
<email>mahadev@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>michim</id>
<name>Michi Mutsuzaki</name>
<email>michim@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>cnauroth</id>
<name>Chris Nauroth</name>
<email>cnauroth@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>breed</id>
<name>Benjamin Reed</name>
<email>breed@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>henry</id>
<name>Henry Robinson</name>
<email>henry@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>rgs</id>
<name>Raul Gutierrez Segales</name>
<email>rgs@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>rakeshr</id>
<name>Rakesh Radhakrishnan</name>
<email>rakeshr@apache.org</email>
<timezone>+5:30</timezone>
</developer>
<developer>
<id>hanm</id>
<name>Michael Han</name>
<email>hanm@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>gkesavan</id>
<name>Giridharan Kesavan</name>
<email>gkesavan@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>akornev</id>
<name>Andrew Kornev</name>
<email>akornev@apache.org</email>
</developer>
<developer>
<id>shralex</id>
<name>Alex Shraer</name>
<email>shralex@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>thawan</id>
<name>Thawan Kooburat</name>
<email>thawan@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>hdeng</id>
<name>Hongchao Deng</name>
<email>hdeng@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>arshad</id>
<name>Mohammad Arshad</name>
<email>arshad@apache.org</email>
<timezone>+5:30</timezone>
</developer>
<developer>
<id>afine</id>
<name>Abraham Fine</name>
<email>afine@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>andor</id>
<name>Andor Molnar</name>
<email>andor@apache.org</email>
<timezone>+1</timezone>
</developer>
<developer>
<id>lvfangmin</id>
<name>Allan Lyu</name>
<email>fangmin@apache.org</email>
<timezone>-8</timezone>
</developer>
<developer>
<id>eolivelli</id>
<name>Enrico Olivelli</name>
<email>eolivelli@apache.org</email>
<timezone>+1</timezone>
</developer>
</developers>
<profiles>
<profile>
<id>full-build</id>
<modules>
<module>zookeeper-it</module>
<module>zookeeper-contrib</module>
</modules>
</profile>
<profile>
<id>fatjar</id>
<modules>
<module>zookeeper-it</module>
<module>zookeeper-contrib</module>
</modules>
</profile>
<profile>
<id>java-build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>apache-release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.apache.resources</groupId>
<artifactId>apache-source-release-assembly-descriptor</artifactId>
<version>1.0.6</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>source-release-assembly-tar-gz</id>
<phase>initialize</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<runOnlyAtExecutionRoot>true</runOnlyAtExecutionRoot>
<descriptorRefs>
<!-- defined in Apache Parent Pom -->
<descriptorRef>${sourceReleaseAssemblyDescriptor}</descriptorRef>
</descriptorRefs>
<finalName>apache-zookeeper-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<formats>
<format>tar.gz</format>
</formats>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>m2e</id>
<activation>
<property>
<name>m2e.version</name>
</property>
</activation>
<properties>
<maven.compiler.release>8</maven.compiler.release>
</properties>
</profile>
<profile>
<id>jdk-release-flag</id>
<activation>
<jdk>[9,)</jdk>
</activation>
<properties>
<maven.compiler.release>8</maven.compiler.release>
</properties>
</profile>
</profiles>
<properties>
<!-- maven properties -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<dependency.locations.enabled>false</dependency.locations.enabled>
<surefire-forkcount>8</surefire-forkcount>
<!-- dependency versions -->
<slf4j.version>1.7.25</slf4j.version>
<audience-annotations.version>0.5.0</audience-annotations.version>
<jmockit.version>1.48</jmockit.version>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<mockito.version>2.27.0</mockito.version>
<hamcrest.version>1.3</hamcrest.version>
<commons-cli.version>1.2</commons-cli.version>
<netty.version>4.1.63.Final</netty.version>
<jetty.version>9.4.39.v20210325</jetty.version>
<jackson.version>2.10.5.1</jackson.version>
<json.version>1.1.1</json.version>
<jline.version>2.14.6</jline.version>
<snappy.version>1.1.7</snappy.version>
<kerby.version>2.0.0</kerby.version>
<bouncycastle.version>1.60</bouncycastle.version>
<commons-collections.version>3.2.2</commons-collections.version>
<dropwizard.version>3.2.5</dropwizard.version>
<spotbugsannotations.version>4.0.2</spotbugsannotations.version>
<checkstyle.version>8.17</checkstyle.version>
<enforcer.version>3.0.0-M3</enforcer.version>
<!-- parameter to pass to C client build -->
<c-client-openssl>yes</c-client-openssl>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>${hamcrest.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons-collections.version}</version>
</dependency>
<dependency>
<groupId>org.apache.yetus</groupId>
<artifactId>audience-annotations</artifactId>
<version>${audience-annotations.version}</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>${commons-cli.version}</version>
</dependency>
<dependency>
<groupId>org.apache.kerby</groupId>
<artifactId>kerb-core</artifactId>
<version>${kerby.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.kerby</groupId>
<artifactId>kerb-simplekdc</artifactId>
<version>${kerby.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.kerby</groupId>
<artifactId>kerby-config</artifactId>
<version>${kerby.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${dropwizard.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>${json.version}</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
<version>${jline.version}</version>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>${spotbugsannotations.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId>
<version>${snappy.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<showWarnings>true</showWarnings>
<compilerArgs>
<compilerArg>-Werror</compilerArg>
<compilerArg>-Xlint:deprecation</compilerArg>
<compilerArg>-Xlint:unchecked</compilerArg>
<compilerArg>-Xlint:-options</compilerArg>
<compilerArg>-Xdoclint:-missing</compilerArg>
<!-- https://issues.apache.org/jira/browse/MCOMPILER-205 -->
<compilerArg>-Xpkginfo:always</compilerArg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifestEntries>
<Implementation-Build>${mvngit.commit.id}</Implementation-Build>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<doclint>none</doclint>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<version>1.11.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
</plugin>
<plugin>
<groupId>com.github.koraktor</groupId>
<artifactId>mavanagaiata</artifactId>
<version>0.9.4</version>
<configuration>
<skipNoGit>true</skipNoGit>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>net.nicoulaj.maven.plugins</groupId>
<artifactId>checksum-maven-plugin</artifactId>
<version>1.8</version>
</plugin>
<plugin>
<groupId>org.openclover</groupId>
<artifactId>clover-maven-plugin</artifactId>
<version>4.3.1</version>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.0.0</version>
<configuration>
<excludeFilterFile>excludeFindBugsFilter.xml</excludeFilterFile>
</configuration>
</plugin>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>5.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.0</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>${checkstyle.version}</version>
</dependency>
</dependencies>
<configuration>
<configLocation>checkstyle-strict.xml</configLocation>
<suppressionsLocation>checkstyleSuppressions.xml</suppressionsLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failOnViolation>true</failOnViolation>
<includeResources>false</includeResources>
<includeTestResources>false</includeTestResources>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
<executions>
<execution>
<id>checkstyle</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- we don't need this plugin-->
<plugin>
<artifactId>maven-remote-resources-plugin</artifactId>
<executions>
<execution>
<id>process-resource-bundles</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>com.github.koraktor</groupId>
<artifactId>mavanagaiata</artifactId>
<executions>
<execution>
<id>find-current-git-revision</id>
<goals>
<goal>commit</goal>
</goals>
<phase>validate</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.openclover</groupId>
<artifactId>clover-maven-plugin</artifactId>
<configuration>
<generateHtml>true</generateHtml>
<generateXml>true</generateXml>
<includes>
<include>org/apache/zookeeper/**/*</include>
</includes>
<excludes>
<exclude>org/apache/zookeeper/version/**/*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<phase>pre-site</phase>
<goals>
<goal>instrument</goal>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<exportAntProperties>true</exportAntProperties>
<target>
<property environment="env" />
<exec executable="hostname" outputproperty="host.name" />
</target>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>Jar Tests Package</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<includes>
<include>org/**</include>
<include>META_INF/**</include>
</includes>
<skipIfEmpty>true</skipIfEmpty>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
<execution>
<id>aggregate</id>
<phase>site</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
<configuration>
<overview>zookeeper-server/src/main/resources/overview.html</overview>
<excludePackageNames>*.recipes.*</excludePackageNames>
</configuration>
</plugin>
<plugin>
<!-- Maven's deploy plugin only creates checksums during the deployment of the jar artifacts to repo. -->
<!-- We also want to sign tarballs. Nicoulaj's plugin is the recommended solution by the community. -->
<groupId>net.nicoulaj.maven.plugins</groupId>
<artifactId>checksum-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>artifacts</goal>
</goals>
</execution>
</executions>
<configuration>
<algorithms>
<algorithm>SHA-512</algorithm>
</algorithms>
<appendFilename>true</appendFilename>
</configuration>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<format>ALL</format>
<failBuildOnCVSS>0</failBuildOnCVSS>
<suppressionFiles>
<suppressionsFile>owaspSuppressions.xml</suppressionsFile>
</suppressionFiles>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/log4j.properties</exclude>
<exclude>**/README.md</exclude>
<exclude>**/findbugsExcludeFile.xml</exclude>
<exclude>**/checkstyle-noframes-sorted.xsl</exclude>
<exclude>**/configure.ac</exclude>
<exclude>**/Makefile.am</exclude>
<exclude>conf/zoo_sample.cfg</exclude>
<exclude>conf/configuration.xsl</exclude>
<exclude>.travis.yml</exclude>
<exclude>excludeFindBugsFilter.xml</exclude>
<exclude>README_packaging.md</exclude>
<exclude>src/main/resources/markdown/skin/*</exclude>
<exclude>src/main/resources/markdown/html/*</exclude>
<exclude>src/main/resources/markdown/images/*</exclude>
<!-- contrib -->
<exclude>**/JMX-RESOURCES</exclude>
<exclude>**/src/main/resources/mainClasses</exclude>
<exclude>**/Changes</exclude>
<exclude>**/MANIFEST</exclude>
<exclude>**/src/test/zoo.cfg</exclude>
<exclude>**/src/main/resources/webapp/org/apache/zookeeper/graph/resources/*</exclude>
<exclude>**/src/main/java/com/nitido/utils/toaster/Toaster.java</exclude>
<exclude>**/TODO</exclude>
<!-- c client -->
<exclude>**/acinclude.m4</exclude>
<exclude>**/aminclude.am</exclude>
<exclude>**/src/hashtable/*</exclude>
<exclude>**/include/winconfig.h</exclude>
<exclude>**/tests/wrappers.opt</exclude>
<exclude>**/tests/zoo.cfg</exclude>
<exclude>**/tests/wrappers-mt.opt</exclude>
<exclude>**/c-doc.Doxyfile</exclude>
</excludes>
<consoleOutput>true</consoleOutput>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<!-- update the version inside the C sources -->
<preparationGoals>clean install -DskipTests antrun:run@replace-cclient-files-during-release scm:add@add-cclient-files-during-release scm:checkin@commit-cclient-files-during-release</preparationGoals>
<completionGoals>clean install -DskipTests antrun:run@replace-cclient-files-during-release scm:add@add-cclient-files-during-release scm:checkin@commit-cclient-files-during-release</completionGoals>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<inherited>false</inherited>
<executions>
<execution>
<id>add-cclient-files-during-release</id>
<phase>none</phase>
<goals>
<goal>add</goal>
</goals>
<configuration>
<pushChanges>false</pushChanges>
<includes>zookeeper-client/zookeeper-client-c/CMakeLists.txt,zookeeper-client/zookeeper-client-c/configure.ac,zookeeper-client/zookeeper-client-c/include/zookeeper_version.h</includes>
</configuration>
</execution>
<execution>
<id>commit-cclient-files-during-release</id>
<phase>none</phase>
<goals>
<!-- git commit -->
<goal>checkin</goal>
</goals>
<configuration>
<pushChanges>false</pushChanges>
<message>Prepared ${project.version}</message>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${enforcer.version}</version>
<executions>
<execution>
<id>banned-commons-lang</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<excludes>
<exclude>commons-lang:commons-lang</exclude>
</excludes>
<searchTransitive>false</searchTransitive>
<message>We don't use commons-lang any more, so do not depend on it directly.</message>
</bannedDependencies>
</rules>
</configuration>
</execution>
<execution>
<id>banned-commons-lang3</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<excludes>
<exclude>org.apache.commons:commons-lang3</exclude>
</excludes>
<searchTransitive>false</searchTransitive>
<message>We don't use commons-lang3, so do not depend on it directly.</message>
</bannedDependencies>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>${project.basedir}src/main/java/resources</directory>
<excludes>
<exclude>**/*.*</exclude>
</excludes>
</resource>
</resources>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.openclover</groupId>
<artifactId>clover-maven-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</project>

533
zk-merge-pr.py Normal file
View File

@ -0,0 +1,533 @@
#!/usr/bin/env python
#
# 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.
#
# Utility for creating well-formed pull request merges and pushing them to Apache. This script is a modified version
# of the one created by the Spark project (https://github.com/apache/spark/blob/master/dev/merge_spark_pr.py).
#
# Usage: ./zk-merge-pr.py (see config env vars below)
#
# This utility assumes you already have a local ZooKeeper git folder and that you
# have added remotes corresponding to both:
# (i) the github apache ZooKeeper mirror and
# (ii) the apache ZooKeeper git repo.
import json
import os
import re
import subprocess
import sys
import urllib.request, urllib.error, urllib.parse
import getpass
try:
import jira.client
JIRA_IMPORTED = True
except ImportError:
JIRA_IMPORTED = False
PROJECT_NAME = "zookeeper"
CAPITALIZED_PROJECT_NAME = PROJECT_NAME.upper()
# Remote name which points to the GitHub site
PR_REMOTE_NAME = os.environ.get("PR_REMOTE_NAME", "apache-github")
# Remote name which points to Apache git
PUSH_REMOTE_NAME = os.environ.get("PUSH_REMOTE_NAME", "apache")
# ASF JIRA username
JIRA_USERNAME = os.environ.get("JIRA_USERNAME", "")
# ASF JIRA password
JIRA_PASSWORD = os.environ.get("JIRA_PASSWORD", "")
# OAuth key used for issuing requests against the GitHub API. If this is not defined, then requests
# will be unauthenticated. You should only need to configure this if you find yourself regularly
# exceeding your IP's unauthenticated request rate limit. You can create an OAuth key at
# https://github.com/settings/tokens. This script only requires the "public_repo" scope.
GITHUB_OAUTH_KEY = os.environ.get("GITHUB_OAUTH_KEY")
GITHUB_USER = os.environ.get("GITHUB_USER", "apache")
GITHUB_BASE = "https://github.com/%s/%s/pull" % (GITHUB_USER, PROJECT_NAME)
GITHUB_API_BASE = "https://api.github.com/repos/%s/%s" % (GITHUB_USER, PROJECT_NAME)
JIRA_BASE = "https://issues.apache.org/jira/browse"
JIRA_API_BASE = "https://issues.apache.org/jira"
# Prefix added to temporary branches
TEMP_BRANCH_PREFIX = "PR_TOOL"
# TODO Introduce a convention as this is too brittle
RELEASE_BRANCH_PREFIX = "branch-"
DEV_BRANCH_NAME = "master"
DEFAULT_FIX_VERSION = os.environ.get("DEFAULT_FIX_VERSION", "branch-3.5")
def get_json(url):
try:
request = urllib.request.Request(url)
if GITHUB_OAUTH_KEY:
request.add_header('Authorization', 'token %s' % GITHUB_OAUTH_KEY)
return json.load(urllib.request.urlopen(request))
except urllib.error.HTTPError as e:
if "X-RateLimit-Remaining" in e.headers and e.headers["X-RateLimit-Remaining"] == '0':
print("Exceeded the GitHub API rate limit; see the instructions in " + \
"zk-merge-pr.py to configure an OAuth token for making authenticated " + \
"GitHub requests.")
else:
print("Unable to fetch URL, exiting: %s" % url)
sys.exit(-1)
def fail(msg):
print(msg)
clean_up()
sys.exit(-1)
def run_cmd(cmd):
print(cmd)
if isinstance(cmd, list):
return subprocess.check_output(cmd, encoding='utf8')
else:
return subprocess.check_output(cmd.split(" "), encoding='utf8')
def continue_maybe(prompt):
result = input("\n%s (y/n): " % prompt)
if result.lower().strip() != "y":
fail("Okay, exiting")
def clean_up():
if original_head != get_current_branch():
print("Restoring head pointer to %s" % original_head)
run_cmd("git checkout %s" % original_head)
branches = run_cmd("git branch").replace(" ", "").split("\n")
for branch in [x for x in branches if x.startswith(TEMP_BRANCH_PREFIX)]:
print("Deleting local branch %s" % branch)
run_cmd("git branch -D %s" % branch)
def get_current_branch():
return run_cmd("git rev-parse --abbrev-ref HEAD").replace("\n", "")
# merge the requested PR and return the merge hash
def merge_pr(pr_num, target_ref, title, body, pr_repo_desc):
pr_branch_name = "%s_MERGE_PR_%s" % (TEMP_BRANCH_PREFIX, pr_num)
target_branch_name = "%s_MERGE_PR_%s_%s" % (TEMP_BRANCH_PREFIX, pr_num, target_ref.upper())
run_cmd("git fetch %s pull/%s/head:%s" % (PR_REMOTE_NAME, pr_num, pr_branch_name))
run_cmd("git fetch %s %s:%s" % (PUSH_REMOTE_NAME, target_ref, target_branch_name))
run_cmd("git checkout %s" % target_branch_name)
had_conflicts = False
try:
run_cmd(['git', 'merge', pr_branch_name, '--squash'])
except Exception as e:
msg = "Error merging: %s\nWould you like to manually fix-up this merge?" % e
continue_maybe(msg)
msg = "Okay, please fix any conflicts and 'git add' conflicting files... Finished?"
continue_maybe(msg)
had_conflicts = True
commit_authors = run_cmd(['git', 'log', 'HEAD..%s' % pr_branch_name,
'--pretty=format:%an <%ae>']).split("\n")
distinct_authors = sorted(set(commit_authors),
key=lambda x: commit_authors.count(x), reverse=True)
primary_author = input(
"Enter primary author in the format of \"name <email>\" [%s]: " %
distinct_authors[0])
if primary_author == "":
primary_author = distinct_authors[0]
reviewers = input(
"Enter reviewers in the format of \"name1 <email1>, name2 <email2>\": ").strip()
commits = run_cmd(['git', 'log', 'HEAD..%s' % pr_branch_name,
'--pretty=format:%h [%an] %s']).split("\n")
if len(commits) > 1:
result = input("List pull request commits in squashed commit message? (y/n): ")
if result.lower().strip() == "y":
should_list_commits = True
else:
should_list_commits = False
else:
should_list_commits = False
merge_message_flags = []
merge_message_flags += ["-m", title]
if body is not None:
# We remove @ symbols from the body to avoid triggering e-mails
# to people every time someone creates a public fork of the project.
merge_message_flags += ["-m", body.replace("@", "")]
authors = "\n".join(["Author: %s" % a for a in distinct_authors])
merge_message_flags += ["-m", authors]
if (reviewers != ""):
merge_message_flags += ["-m", "Reviewers: %s" % reviewers]
if had_conflicts:
committer_name = run_cmd("git config --get user.name").strip()
committer_email = run_cmd("git config --get user.email").strip()
message = "This patch had conflicts when merged, resolved by\nCommitter: %s <%s>" % (
committer_name, committer_email)
merge_message_flags += ["-m", message]
# The string "Closes #%s" string is required for GitHub to correctly close the PR
close_line = "Closes #%s from %s" % (pr_num, pr_repo_desc)
if should_list_commits:
close_line += " and squashes the following commits:"
merge_message_flags += ["-m", close_line]
if should_list_commits:
merge_message_flags += ["-m", "\n".join(commits)]
run_cmd(['git', 'commit', '--author="%s"' % primary_author] + merge_message_flags)
continue_maybe("Merge complete (local ref %s). Push to %s?" % (
target_branch_name, PUSH_REMOTE_NAME))
try:
run_cmd('git push %s %s:%s' % (PUSH_REMOTE_NAME, target_branch_name, target_ref))
except Exception as e:
clean_up()
fail("Exception while pushing: %s" % e)
merge_hash = run_cmd("git rev-parse %s" % target_branch_name)[:8]
clean_up()
print(("Pull request #%s merged!" % pr_num))
print(("Merge hash: %s" % merge_hash))
return merge_hash
def cherry_pick(pr_num, merge_hash, default_branch):
pick_ref = input("Enter a branch name [%s]: " % default_branch)
if pick_ref == "":
pick_ref = default_branch
pick_branch_name = "%s_PICK_PR_%s_%s" % (TEMP_BRANCH_PREFIX, pr_num, pick_ref.upper())
run_cmd("git fetch %s %s:%s" % (PUSH_REMOTE_NAME, pick_ref, pick_branch_name))
run_cmd("git checkout %s" % pick_branch_name)
try:
run_cmd("git cherry-pick -sx %s" % merge_hash)
except Exception as e:
msg = "Error cherry-picking: %s\nWould you like to manually fix-up this merge?" % e
continue_maybe(msg)
msg = "Okay, please fix any conflicts and finish the cherry-pick. Finished?"
continue_maybe(msg)
continue_maybe("Pick complete (local ref %s). Push to %s?" % (
pick_branch_name, PUSH_REMOTE_NAME))
try:
run_cmd('git push %s %s:%s' % (PUSH_REMOTE_NAME, pick_branch_name, pick_ref))
except Exception as e:
clean_up()
fail("Exception while pushing: %s" % e)
pick_hash = run_cmd("git rev-parse %s" % pick_branch_name)[:8]
clean_up()
print(("Pull request #%s picked into %s!" % (pr_num, pick_ref)))
print(("Pick hash: %s" % pick_hash))
return pick_ref
def fix_version_from_branch(branch, versions):
# Note: Assumes this is a sorted (newest->oldest) list of un-released versions
if branch == DEV_BRANCH_NAME:
versions = [x for x in versions if x == DEFAULT_FIX_VERSION]
if len(versions) > 0:
return versions[0]
else:
return None
else:
versions = [x for x in versions if x.startswith(branch)]
if len(versions) > 0:
return versions[-1]
else:
return None
def resolve_jira_issue(merge_branches, comment, default_jira_id=""):
asf_jira = jira.client.JIRA({'server': JIRA_API_BASE},
basic_auth=(JIRA_USERNAME, JIRA_PASSWORD))
jira_id = input("Enter a JIRA id [%s]: " % default_jira_id)
if jira_id == "":
jira_id = default_jira_id
try:
issue = asf_jira.issue(jira_id)
except Exception as e:
fail("ASF JIRA could not find %s\n%s" % (jira_id, e))
cur_status = issue.fields.status.name
cur_summary = issue.fields.summary
cur_assignee = issue.fields.assignee
if cur_assignee is None:
cur_assignee = "NOT ASSIGNED!!!"
else:
cur_assignee = cur_assignee.displayName
if cur_status == "Resolved" or cur_status == "Closed":
fail("JIRA issue %s already has status '%s'" % (jira_id, cur_status))
print(("=== JIRA %s ===" % jira_id))
print(("summary\t\t%s\nassignee\t%s\nstatus\t\t%s\nurl\t\t%s/%s\n" % (
cur_summary, cur_assignee, cur_status, JIRA_BASE, jira_id)))
versions = asf_jira.project_versions(CAPITALIZED_PROJECT_NAME)
versions = sorted(versions, key=lambda x: x.name, reverse=True)
versions = [x for x in versions if x.raw['released'] is False]
version_names = [x.name for x in versions]
default_fix_versions = [fix_version_from_branch(x, version_names) for x in merge_branches]
default_fix_versions = [x for x in default_fix_versions if x != None]
default_fix_versions = ",".join(default_fix_versions)
fix_versions = input("Enter comma-separated fix version(s) [%s]: " % default_fix_versions)
if fix_versions == "":
fix_versions = default_fix_versions
fix_versions = fix_versions.replace(" ", "").split(",")
def get_version_json(version_str):
return filter(lambda v: v.name == version_str, versions)[0].raw
jira_fix_versions = [get_version_json(v) for v in fix_versions]
resolve = filter(lambda a: a['name'] == "Resolve Issue", asf_jira.transitions(jira_id))[0]
resolution = filter(lambda r: r.raw['name'] == "Fixed", asf_jira.resolutions())[0]
asf_jira.transition_issue(
jira_id, resolve["id"], fixVersions = jira_fix_versions,
comment = comment, resolution = {'id': resolution.raw['id']})
print("Successfully resolved %s with fixVersions=%s!" % (jira_id, fix_versions))
def resolve_jira_issues(title, merge_branches, comment):
jira_ids = re.findall("%s-[0-9]{4,5}" % CAPITALIZED_PROJECT_NAME, title)
if len(jira_ids) == 0:
resolve_jira_issue(merge_branches, comment)
for jira_id in jira_ids:
resolve_jira_issue(merge_branches, comment, jira_id)
def standardize_jira_ref(text):
"""
Standardize the jira reference commit message prefix to "PROJECT_NAME-XXX: Issue"
>>> standardize_jira_ref("%s-5954: Top by key" % CAPITALIZED_PROJECT_NAME)
'ZOOKEEPER-5954: Top by key'
>>> standardize_jira_ref("%s-5821: ParquetRelation2 CTAS should check if delete is successful" % PROJECT_NAME)
'ZOOKEEPER-5821: ParquetRelation2 CTAS should check if delete is successful'
>>> standardize_jira_ref("%s-4123: [WIP] Show new dependencies added in pull requests" % PROJECT_NAME)
'ZOOKEEPER-4123: [WIP] Show new dependencies added in pull requests'
>>> standardize_jira_ref("%s 5954: Top by key" % PROJECT_NAME)
'ZOOKEEPER-5954: Top by key'
>>> standardize_jira_ref("%s-979: a LRU scheduler for load balancing in TaskSchedulerImpl" % PROJECT_NAME)
'ZOOKEEPER-979: a LRU scheduler for load balancing in TaskSchedulerImpl'
>>> standardize_jira_ref("%s-1094: Support MiMa for reporting binary compatibility across versions." % CAPITALIZED_PROJECT_NAME)
'ZOOKEEPER-1094: Support MiMa for reporting binary compatibility across versions.'
>>> standardize_jira_ref("%s-1146: [WIP] Vagrant support" % CAPITALIZED_PROJECT_NAME)
'ZOOKEEPER-1146: [WIP] Vagrant support'
>>> standardize_jira_ref("%s-1032: If Yarn app fails before registering, app master stays aroun..." % PROJECT_NAME)
'ZOOKEEPER-1032: If Yarn app fails before registering, app master stays aroun...'
>>> standardize_jira_ref("%s-6250 %s-6146 %s-5911: Types are now reserved words in DDL parser." % (PROJECT_NAME, PROJECT_NAME, CAPITALIZED_PROJECT_NAME))
'ZOOKEEPER-6250 ZOOKEEPER-6146 ZOOKEEPER-5911: Types are now reserved words in DDL parser.'
>>> standardize_jira_ref("Additional information for users building from source code")
'Additional information for users building from source code'
"""
jira_refs = []
components = []
# Extract JIRA ref(s):
pattern = re.compile(r'(%s[-\s]*[0-9]{3,6})+' % CAPITALIZED_PROJECT_NAME, re.IGNORECASE)
for ref in pattern.findall(text):
# Add brackets, replace spaces with a dash, & convert to uppercase
jira_refs.append(re.sub(r'\s+', '-', ref.upper()))
text = text.replace(ref, '')
# Extract project name component(s):
# Look for alphanumeric chars, spaces, dashes, periods, and/or commas
pattern = re.compile(r'(\[[\w\s,-\.]+\])', re.IGNORECASE)
for component in pattern.findall(text):
components.append(component.upper())
text = text.replace(component, '')
# Cleanup any remaining symbols:
pattern = re.compile(r'^\W+(.*)', re.IGNORECASE)
if (pattern.search(text) is not None):
text = pattern.search(text).groups()[0]
# Assemble full text (JIRA ref(s), module(s), remaining text)
jira_prefix = ' '.join(jira_refs).strip()
if jira_prefix:
jira_prefix = jira_prefix + ": "
clean_text = jira_prefix + ' '.join(components).strip() + " " + text.strip()
# Replace multiple spaces with a single space, e.g. if no jira refs and/or components were included
clean_text = re.sub(r'\s+', ' ', clean_text.strip())
return clean_text
def get_remote_repos():
repos = run_cmd("git remote -v").split()
dict = {}
for i in range(0, len(repos), 3):
dict[repos[i]] = repos[i+1]
return dict
def check_git_remote():
repos = get_remote_repos()
# check if all remote endpoints' URLs point to project git repo
name = PROJECT_NAME + ".git"
for url in list(repos.values()):
if not url.endswith(name):
fail("Error: not a %s git repo or at least one remote is invalid" % PROJECT_NAME)
if not PR_REMOTE_NAME in repos:
fail("Error: PR_REMOTE_NAME (%s) environment variable has not been set!" % PR_REMOTE_NAME)
if not PUSH_REMOTE_NAME in repos:
fail("Error: PUSH_REMOTE_NAME (%s) environment variable has not been set!" % PUSH_REMOTE_NAME)
def check_jira_env():
global JIRA_PASSWORD
if JIRA_IMPORTED:
if JIRA_USERNAME.strip() != "" and JIRA_PASSWORD.strip() == "":
inform_pwd = input("JIRA_USERNAME set but JIRA_PASSWORD is not. Want to inform it? ")
if inform_pwd.strip() == "y":
JIRA_PASSWORD = getpass.getpass('JIRA PASSWORD: ')
if JIRA_USERNAME.strip() == "" or JIRA_PASSWORD.strip() == "":
msg ="JIRA_USERNAME and/or JIRA_PASSWORD are not set. Want to continue? "
continue_maybe(msg)
else:
msg = "JIRA lib not installed. Want to continue? "
continue_maybe(msg)
def main():
global original_head
original_head = get_current_branch()
check_jira_env()
check_git_remote()
branches = get_json("%s/branches" % GITHUB_API_BASE)
branch_names = [x for x in [x['name'] for x in branches] if x.startswith(RELEASE_BRANCH_PREFIX)]
# Assumes branch names can be sorted lexicographically
latest_branch = sorted(branch_names, reverse=True)[0]
pr_num = input("Which pull request would you like to merge? (e.g. 34): ")
pr = get_json("%s/pulls/%s" % (GITHUB_API_BASE, pr_num))
pr_events = get_json("%s/issues/%s/events" % (GITHUB_API_BASE, pr_num))
url = pr["url"]
pr_title = pr["title"]
commit_title = input("Commit title [%s]: " % pr_title)
if commit_title == "":
commit_title = pr_title
# Decide whether to use the modified title or not
modified_title = standardize_jira_ref(commit_title)
if modified_title != commit_title:
print("I've re-written the title as follows to match the standard format:")
print("Original: %s" % commit_title)
print("Modified: %s" % modified_title)
result = input("Would you like to use the modified title? (y/n): ")
if result.lower().strip() == "y":
commit_title = modified_title
print("Using modified title:")
else:
print("Using original title:")
print(commit_title)
body = pr["body"]
target_ref = pr["base"]["ref"]
user_login = pr["user"]["login"]
base_ref = pr["head"]["ref"]
pr_repo_desc = "%s/%s" % (user_login, base_ref)
# Merged pull requests don't appear as merged in the GitHub API;
# Instead, they're closed by asfgit.
merge_commits = \
[e for e in pr_events if e["actor"]["login"] == "asfgit" and e["event"] == "closed"]
if merge_commits:
merge_hash = merge_commits[0]["commit_id"]
message = get_json("%s/commits/%s" % (GITHUB_API_BASE, merge_hash))["commit"]["message"]
print("Pull request %s has already been merged, assuming you want to backport" % pr_num)
commit_is_downloaded = run_cmd(['git', 'rev-parse', '--quiet', '--verify',
"%s^{commit}" % merge_hash]).strip() != ""
if not commit_is_downloaded:
fail("Couldn't find any merge commit for #%s, you may need to update HEAD." % pr_num)
print("Found commit %s:\n%s" % (merge_hash, message))
cherry_pick(pr_num, merge_hash, latest_branch)
sys.exit(0)
if not bool(pr["mergeable"]):
msg = "Pull request %s is not mergeable in its current form.\n" % pr_num + \
"Continue? (experts only!)"
continue_maybe(msg)
print(("\n=== Pull Request #%s ===" % pr_num))
print(("PR title\t%s\nCommit title\t%s\nSource\t\t%s\nTarget\t\t%s\nURL\t\t%s" % (
pr_title, commit_title, pr_repo_desc, target_ref, url)))
continue_maybe("Proceed with merging pull request #%s?" % pr_num)
merged_refs = [target_ref]
merge_hash = merge_pr(pr_num, target_ref, commit_title, body, pr_repo_desc)
pick_prompt = "Would you like to pick %s into another branch?" % merge_hash
while input("\n%s (y/n): " % pick_prompt).lower().strip() == "y":
merged_refs = merged_refs + [cherry_pick(pr_num, merge_hash, latest_branch)]
if JIRA_IMPORTED:
if JIRA_USERNAME and JIRA_PASSWORD:
continue_maybe("Would you like to update an associated JIRA?")
jira_comment = "Issue resolved by pull request %s\n[%s/%s]" % (pr_num, GITHUB_BASE, pr_num)
resolve_jira_issues(commit_title, merged_refs, jira_comment)
else:
print("JIRA_USERNAME and JIRA_PASSWORD not set")
print("Exiting without trying to close the associated JIRA.")
else:
print("Could not find jira-python library. Run 'sudo pip install jira' to install.")
print("Exiting without trying to close the associated JIRA.")
if __name__ == "__main__":
import doctest
(failure_count, test_count) = doctest.testmod()
if (failure_count):
exit(-1)
main()

178
zookeeper-assembly/pom.xml Normal file
View File

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
/**
* 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.
*/
-->
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.zookeeper</groupId>
<artifactId>parent</artifactId>
<version>3.6.3</version>
<relativePath>..</relativePath>
</parent>
<artifactId>zookeeper-assembly</artifactId>
<packaging>pom</packaging>
<name>Apache ZooKeeper - Assembly</name>
<description>ZooKeeper Assembly</description>
<profiles>
<profile>
<id>full-build</id>
<properties>
<skip.lib.artifact>false</skip.lib.artifact>
</properties>
</profile>
</profiles>
<properties>
<rw.file.permission>0644</rw.file.permission>
<rwx.file.permission>0755</rwx.file.permission>
<skip.lib.artifact>true</skip.lib.artifact>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper-docs</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper-jute</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper-client</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper-prometheus-metrics</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper-recipes</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<!-- list here all the jars we want to put in "lib"
and are in scope 'provided' -->
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
</dependency>
<dependency>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
</dependency>
<dependency>
<groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>bin-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${project.basedir}/src/main/assembly/bin-package.xml</descriptor>
</descriptors>
<finalName>apache-zookeeper-${project.version}-bin</finalName>
<appendAssemblyId>false</appendAssemblyId>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
<execution>
<id>lib-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${project.basedir}/src/main/assembly/lib-package.xml</descriptor>
</descriptors>
<finalName>apache-zookeeper-${project.version}-lib</finalName>
<appendAssemblyId>false</appendAssemblyId>
<tarLongFileMode>posix</tarLongFileMode>
<skipAssembly>${skip.lib.artifact}</skipAssembly>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<!-- this module isn't to be deployed to Maven Central -->
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,84 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<!--
/**
* 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.
*/
-->
<id>bin-package</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<componentDescriptors>
<componentDescriptor>src/main/assembly/components.xml</componentDescriptor>
</componentDescriptors>
<dependencySets>
<dependencySet>
<includes>
<include>*:*</include>
</includes>
<excludes>
<exclude>org.apache.zookeeper:zookeeper-recipes</exclude>
<exclude>org.apache.zookeeper:zookeeper-client</exclude>
<exclude>org.apache.zookeeper:zookeeper-docs</exclude>
</excludes>
<useProjectArtifact>false</useProjectArtifact>
<useTransitiveDependencies>true</useTransitiveDependencies>
<outputDirectory>lib</outputDirectory>
<fileMode>${rw.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
<useStrictFiltering>true</useStrictFiltering>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<!-- ZooKeeper generated documents -->
<directory>${project.basedir}/../zookeeper-docs/target/html</directory>
<outputDirectory>docs</outputDirectory>
<fileMode>${rw.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
<fileSet>
<!-- ZooKeeper jute generated api document -->
<directory>${project.basedir}/../zookeeper-jute/target/apidocs</directory>
<outputDirectory>docs/apidocs/zookeeper-jute</outputDirectory>
<fileMode>${rw.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
<fileSet>
<!-- ZooKeeper server generated api document -->
<directory>${project.basedir}/../zookeeper-server/target/apidocs</directory>
<outputDirectory>docs/apidocs/zookeeper-server</outputDirectory>
<fileMode>${rw.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
<fileSet>
<!-- License files for 3rd party libs -->
<directory>${project.basedir}/../zookeeper-server/src/main/resources/lib</directory>
<includes>
<include>*.txt</include>
</includes>
<outputDirectory>lib</outputDirectory>
<fileMode>${rw.file.permission}</fileMode>
</fileSet>
</fileSets>
</assembly>

View File

@ -0,0 +1,49 @@
<?xml version="1.0"?>
<!--
/**
* 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.
*/
-->
<component>
<!-- Resources that both bin and source package include -->
<fileSets>
<fileSet>
<directory>${project.basedir}/..</directory>
<outputDirectory>.</outputDirectory>
<includes>
<include>NOTICE.txt</include>
<include>LICENSE.txt</include>
<include>README.md</include>
<include>README_packaging.md</include>
</includes>
<fileMode>${rw.file.permission}</fileMode>
</fileSet>
<fileSet>
<directory>${project.basedir}/../conf</directory>
<outputDirectory>conf</outputDirectory>
<fileMode>${rw.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
<fileSet>
<directory>${project.basedir}/../bin</directory>
<outputDirectory>bin</outputDirectory>
<fileMode>${rwx.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
</fileSets>
</component>

View File

@ -0,0 +1,64 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<!--
/**
* 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.
*/
-->
<id>lib-package</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<!-- ZooKeeper C client lib and include files -->
<directory>${project.basedir}/../zookeeper-client/zookeeper-client-c/target/c</directory>
<outputDirectory>usr</outputDirectory>
<includes>
<include>include/**/*</include>
<include>lib/*</include>
</includes>
<fileMode>${rw.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
<fileSet>
<!-- ZooKeeper C client binaries-->
<directory>${project.basedir}/../zookeeper-client/zookeeper-client-c/target/c</directory>
<outputDirectory>usr</outputDirectory>
<includes>
<include>bin/*</include>
</includes>
<fileMode>${rwx.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
<fileSet>
<!-- ZooKeeper license -->
<directory>${project.basedir}/../zookeeper-client/zookeeper-client-c</directory>
<includes>
<include>LICENSE</include>
</includes>
<outputDirectory>/</outputDirectory>
<fileMode>${rw.file.permission}</fileMode>
<directoryMode>${rwx.file.permission}</directoryMode>
</fileSet>
</fileSets>
</assembly>

58
zookeeper-client/pom.xml Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
/**
* 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.
*/
-->
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.zookeeper</groupId>
<artifactId>parent</artifactId>
<version>3.6.3</version>
<relativePath>..</relativePath>
</parent>
<artifactId>zookeeper-client</artifactId>
<packaging>pom</packaging>
<name>Apache ZooKeeper - Client</name>
<description>ZooKeeper client</description>
<profiles>
<profile>
<id>full-build</id>
<modules>
<module>zookeeper-client-c</module>
</modules>
</profile>
<profile>
<id>java-build</id>
<modules />
</profile>
</profiles>
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<!-- this module isn't to be deployed to Maven Central -->
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,267 @@
# 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.
cmake_minimum_required(VERSION 3.5)
project(zookeeper VERSION 3.6.3)
set(email user@zookeeper.apache.org)
set(description "zookeeper C client")
# general options
if(UNIX)
add_compile_options(-Wall -fPIC)
elseif(WIN32)
add_compile_options(/W3)
endif()
add_definitions(-DUSE_STATIC_LIB)
# TODO: Enable /WX and /W4 on Windows. Currently there are ~1000 warnings.
# TODO: Add Solaris support.
# TODO: Add a shared library option.
# TODO: Specify symbols to export.
# TODO: Generate doxygen documentation.
# Sync API option
option(WANT_SYNCAPI "Enables Sync API support" ON)
if(WANT_SYNCAPI)
add_definitions(-DTHREADED)
endif()
# CppUnit option
if(WIN32 OR APPLE)
# The tests do not yet compile on Windows or macOS,
# so we set this to off by default.
#
# Note that CMake does not have expressions except in conditionals,
# so we're left with this if/else/endif pattern.
set(DEFAULT_WANT_CPPUNIT OFF)
else()
set(DEFAULT_WANT_CPPUNIT ON)
endif()
option(WANT_CPPUNIT "Enables CppUnit and tests" ${DEFAULT_WANT_CPPUNIT})
# SOCK_CLOEXEC
option(WANT_SOCK_CLOEXEC "Enables SOCK_CLOEXEC on sockets" OFF)
include(CheckSymbolExists)
check_symbol_exists(SOCK_CLOEXEC sys/socket.h HAVE_SOCK_CLOEXEC)
if(WANT_SOCK_CLOEXEC AND HAVE_SOCK_CLOEXEC)
set(SOCK_CLOEXEC_ENABLED 1)
endif()
# The function `to_have(in out)` converts a header name like `arpa/inet.h`
# into an Autotools style preprocessor definition `HAVE_ARPA_INET_H`.
# This is then set or unset in `configure_file()` step.
#
# Note that CMake functions do not have return values; instead an "out"
# variable must be passed, and explicitly set with parent scope.
function(to_have in out)
string(TOUPPER ${in} str)
string(REGEX REPLACE "/|\\." "_" str ${str})
set(${out} "HAVE_${str}" PARENT_SCOPE)
endfunction()
# include file checks
foreach(f generated/zookeeper.jute.h generated/zookeeper.jute.c)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${f}")
to_have(${f} name)
set(${name} 1)
else()
message(FATAL_ERROR
"jute files are missing!\n"
"Please run 'ant compile_jute' while in the ZooKeeper top level directory.")
endif()
endforeach()
# header checks
include(CheckIncludeFile)
set(check_headers
arpa/inet.h
dlfcn.h
fcntl.h
inttypes.h
memory.h
netdb.h
netinet/in.h
stdint.h
stdlib.h
string.h
strings.h
sys/socket.h
sys/stat.h
sys/time.h
sys/types.h
unistd.h
sys/utsname.h)
foreach(f ${check_headers})
to_have(${f} name)
check_include_file(${f} ${name})
endforeach()
# function checks
include(CheckFunctionExists)
set(check_functions
getcwd
gethostbyname
gethostname
getlogin
getpwuid_r
gettimeofday
getuid
memmove
memset
poll
socket
strchr
strdup
strerror
strtol)
foreach(fn ${check_functions})
to_have(${fn} name)
check_function_exists(${fn} ${name})
endforeach()
# library checks
set(check_libraries rt m pthread)
foreach(lib ${check_libraries})
to_have("lib${lib}" name)
find_library(${name} ${lib})
endforeach()
# IPv6 check
include(CheckStructHasMember)
check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" ZOO_IPV6_ENABLED)
# configure
configure_file(cmake_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/config.h)
# hashtable library
set(hashtable_sources src/hashtable/hashtable_itr.c src/hashtable/hashtable.c)
add_library(hashtable STATIC ${hashtable_sources})
target_include_directories(hashtable PUBLIC include)
target_link_libraries(hashtable PUBLIC $<$<OR:$<PLATFORM_ID:Linux>,$<PLATFORM_ID:FreeBSD>>:m>)
# zookeeper library
set(zookeeper_sources
src/zookeeper.c
src/recordio.c
generated/zookeeper.jute.c
src/zk_log.c
src/zk_hashtable.c
src/addrvec.c)
if(WANT_SYNCAPI)
list(APPEND zookeeper_sources src/mt_adaptor.c)
else()
list(APPEND zookeeper_sources src/st_adaptor.c)
endif()
if(WIN32)
list(APPEND zookeeper_sources src/winport.c)
endif()
add_library(zookeeper STATIC ${zookeeper_sources})
target_include_directories(zookeeper PUBLIC include ${CMAKE_CURRENT_BINARY_DIR}/include generated)
target_link_libraries(zookeeper PUBLIC
hashtable
$<$<PLATFORM_ID:Linux>:rt> # clock_gettime
$<$<PLATFORM_ID:Windows>:ws2_32>) # Winsock 2.0
option(WITH_OPENSSL "turn ON/OFF SSL support, or define openssl library location (default: ON)" ON)
message("-- using WITH_OPENSSL=${WITH_OPENSSL}")
if(NOT WITH_OPENSSL STREQUAL "OFF")
if(NOT WITH_OPENSSL STREQUAL "ON")
set(OPENSSL_ROOT_DIR,${WITH_OPENSSL})
endif()
find_package(OpenSSL)
if(OPENSSL_FOUND)
target_compile_definitions(zookeeper PUBLIC HAVE_OPENSSL_H)
target_link_libraries(zookeeper PUBLIC OpenSSL::SSL OpenSSL::Crypto)
message("-- OpenSSL libraries found! will build with SSL support.")
else()
message("-- WARNING: unable to find OpenSSL libraries! will build without SSL support.")
endif()
endif()
if(WANT_SYNCAPI AND NOT WIN32)
find_package(Threads REQUIRED)
target_link_libraries(zookeeper PUBLIC Threads::Threads)
endif()
# cli executable
add_executable(cli src/cli.c)
target_link_libraries(cli zookeeper)
# load_gen executable
if(WANT_SYNCAPI AND NOT WIN32)
add_executable(load_gen src/load_gen.c)
target_link_libraries(load_gen zookeeper)
endif()
# tests
set(test_sources
tests/TestDriver.cc
tests/LibCMocks.cc
tests/LibCSymTable.cc
tests/MocksBase.cc
tests/ZKMocks.cc
tests/Util.cc
tests/ThreadingUtil.cc
tests/TestZookeeperInit.cc
tests/TestZookeeperClose.cc
tests/TestReconfig.cc
tests/TestReconfigServer.cc
tests/TestClientRetry.cc
tests/TestOperations.cc
tests/TestMulti.cc
tests/TestWatchers.cc
tests/TestClient.cc
tests/ZooKeeperQuorumServer.cc
tests/TestReadOnlyClient.cc
tests/TestLogClientEnv.cc)
if(WANT_SYNCAPI)
list(APPEND test_sources tests/PthreadMocks.cc)
endif()
if(WANT_CPPUNIT)
set (CMAKE_CXX_STANDARD 11)
add_executable(zktest ${test_sources})
target_include_directories(zktest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(zktest
PRIVATE -DZKSERVER_CMD="${CMAKE_CURRENT_SOURCE_DIR}/tests/zkServer.sh")
# TODO: Use `find_library()` for `cppunit`.
target_link_libraries(zktest zookeeper cppunit dl)
# This reads the link flags from the file `tests/wrappers.opt` into
# the variable `symbol_wrappers` for use in `target_link_libraries`.
# It is a holdover from the original build system.
file(STRINGS tests/wrappers.opt symbol_wrappers)
if(WANT_SYNCAPI)
file(STRINGS tests/wrappers-mt.opt symbol_wrappers_mt)
endif()
target_link_libraries(zktest ${symbol_wrappers} ${symbol_wrappers_mt})
enable_testing()
add_test(NAME zktest_runner COMMAND zktest)
set_property(TEST zktest_runner PROPERTY ENVIRONMENT
"ZKROOT=${CMAKE_CURRENT_SOURCE_DIR}/../.."
"CLASSPATH=$CLASSPATH:$CLOVER_HOME/lib/clover*.jar")
endif()

View File

@ -0,0 +1,116 @@
Release 2.1.1
2008-04-30 Andrew Kornev <akornev@users.sourceforge.net>
* changed the distributino package name to "c-client-src"
Release 2.1.0
2008-04-30 Andrew Kornev <akornev@users.sourceforge.net>
* added the client latency diagnostics; the client prints a warning when the
reponse latency exceeds 20ms
* modified logging format to report the znode path for which the zookeeper
operation is called
* fixed a minor bug where error messages were missing for some of the newer
zookeeper error codes (ZCLOSING and ZNOTHING).
* improved logging by adding the XID to the message to make it easy to match
requests to responses
* fixed the bug causing sporadic session termination and timeouts
* added a new return code to zookeeper_process() -- ZNOTHING --
that indicates that the socket has no more data to read
* more unit tests added
Release 1.1.3
2008-02-07 Andrew Kornev <akornev@users.sourceforge.net>
* get_xid() is not thread-safe (xid initialization race condition
in the multi-threaded mode).
* the I/O thread doesnt automatically terminate on AUTH_FAILURE and
SESSION_EXPIRED events.
* all session events should be processed on the completion thread.
* PING operation doesnt atomically enqueue the completion and
send buffers like other operations do.
* corrected zookeeper_init() doxygen docs.
* new unit tests added.
Release 1.1.2
2008-01-24 Andrew Kornev <akornev@users.sourceforge.net>
* fixed a race condition caused by the code in zookeeper_process()
and free_completions() setting sc->complete to 1 without proper
synchronization;
* fixed zoo_get() not updating buffer_len value with the actual
buffer length on return; added missing enter_critical/leave_critical
calls to the async ZK operations.
* Replaced select() with poll() to fix the problem with the FD_SET
macro causing stack corruption for FDs higher than 1024
* Added zoo_set_log_stream() to the public API. The function allows
applications to specify a different log file.
* Removed unused declarations from zookeeper.h (ACL related)
* changed zoo_get() signature to take a pointer to buffer length.
The function sets the parameter to the actual data length upon return.
* the watcher callback now takes the zhandle as its first parameter. This
is to avoid a race condition in the multi-threaded client when a watcher
is called before zookeeper_init() has returned.
* fixed zookeeper_close() resource leaks and race conditions,
fixed the race condition causing xid mismatch.
* added support for cppunit, added new targets: "check" and "run-check"
to build and run unit tests.
* Changed the signature of zookeeper_init(): it now takes a context pointer
as a parameter. This is to avoid a race condition in the multi-threaded client.
* Using a self-pipe rather than SIGUSR1 to wake up select() in the I/O thread
* Added the doxygen target to the autoconf scripts
* Pulled out the logging functionality from zookeeper.c to zk_log.c/.h.
Fixed a minor issue with PING responses being unnecessarily put on
the completion queue rather than simply dropped. Make use of DLL_EXPORT
symbol for building shared lib on cygwin.
* Implemented new Zookeeper operation sync() to flush the leader channel
to ensure that all updates have reached the followers.
* Synchronous methods not being handled properly on disconnect
* breed: fixed an incorrect parameter passed to zookeeper API by
the Sync API wrapper functions
* breed: the set and delete commands now support both Sync and Async API.
Prefix the command name with an 'a' to call the Async API: aset, adelete
* Make sure mutexes and condition variables are properly initialized
and destroyed
* Fixed zookeeper_close() causing core dumps with mt_adaptor
Release 1.0.0
2007-11-27 Andrew Kornev <akornev@users.sourceforge.net>
* configure.ac and Makefile.am added support for GNU autotools
* recordio.c/.h updated jute IO routines to use bit-explicit integer types
(int32_t vs. int, and int64_t vs. long long)
* README rough draft

View File

@ -0,0 +1,234 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006 Free Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that the
`configure' script does not know about. Run `./configure --help' for
details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out automatically,
but needs to determine by the type of machine the package will run on.
Usually, assuming the package is built to be run on the _same_
architectures, `configure' can figure that out, but if it prints a
message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share, you
can create a site shell script called `config.site' that gives default
values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@ -0,0 +1,335 @@
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.
===========================================================================================
=== The following part contains the dual OpenSSL and SSLeay license ===
=== for OpenSSL versions 1.1.1, 1.1.0, 1.0.2 and all prior releases ===
=== (see https://www.openssl.org/source/license.html) ===
===========================================================================================
LICENSE ISSUES
==============
The OpenSSL toolkit stays under a double license, i.e. both the conditions of
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts.
OpenSSL License
---------------
/* ====================================================================
* Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED 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 OpenSSL PROJECT OR
* ITS 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.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
Original SSLeay License
-----------------------
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/

View File

@ -0,0 +1,154 @@
# need this for Doxygen integration
include $(top_srcdir)/aminclude.am
AUTOMAKE_OPTIONS = serial-tests
if SOLARIS
SOLARIS_CPPFLAGS = -D_POSIX_PTHREAD_SEMANTICS
SOLARIS_LIB_LDFLAGS = -lnsl -lsocket
endif
if WANT_OPENSSL
OPENSSL_CPPFLAGS = -DHAVE_OPENSSL_H
OPENSSL_LIB_LDFLAGS = -lssl -lcrypto
endif
AM_CPPFLAGS = -I${srcdir}/include -I${srcdir}/tests -I${srcdir}/generated $(SOLARIS_CPPFLAGS) $(OPENSSL_CPPFLAGS)
AM_CFLAGS = -Wall -Werror -Wdeclaration-after-statement
AM_CXXFLAGS = -Wall $(USEIPV6)
LIB_LDFLAGS = -no-undefined -version-info 2 $(SOLARIS_LIB_LDFLAGS) $(OPENSSL_LIB_LDFLAGS)
# Additional flags for coverage testing (if enabled)
if ENABLEGCOV
AM_CFLAGS += -fprofile-arcs -ftest-coverage
AM_LDFLAGS = -lgcov
endif
pkginclude_HEADERS = include/zookeeper.h include/zookeeper_version.h include/zookeeper_log.h include/proto.h include/recordio.h generated/zookeeper.jute.h
EXTRA_DIST=LICENSE
HASHTABLE_SRC = src/hashtable/hashtable_itr.h src/hashtable/hashtable_itr.c \
src/hashtable/hashtable_private.h src/hashtable/hashtable.h src/hashtable/hashtable.c
noinst_LTLIBRARIES = libhashtable.la
libhashtable_la_SOURCES = $(HASHTABLE_SRC)
COMMON_SRC = src/zookeeper.c include/zookeeper.h include/zookeeper_version.h include/zookeeper_log.h\
src/recordio.c include/recordio.h include/proto.h \
src/zk_adaptor.h generated/zookeeper.jute.c \
src/zk_log.c src/zk_hashtable.h src/zk_hashtable.c \
src/addrvec.h src/addrvec.c
# These are the symbols (classes, mostly) we want to export from our library.
EXPORT_SYMBOLS = '(zoo_|zookeeper_|zhandle|Z|format_log_message|log_message|logLevel|deallocate_|allocate_|zerror|is_unrecoverable)'
noinst_LTLIBRARIES += libzkst.la
libzkst_la_SOURCES =$(COMMON_SRC) src/st_adaptor.c
libzkst_la_LIBADD = -lm $(CLOCK_GETTIME_LIBS)
lib_LTLIBRARIES = libzookeeper_st.la
libzookeeper_st_la_SOURCES =
libzookeeper_st_la_LIBADD=libzkst.la libhashtable.la
libzookeeper_st_la_DEPENDENCIES=libzkst.la libhashtable.la
libzookeeper_st_la_LDFLAGS = $(LIB_LDFLAGS) -export-symbols-regex $(EXPORT_SYMBOLS)
if WANT_SYNCAPI
noinst_LTLIBRARIES += libzkmt.la
libzkmt_la_SOURCES =$(COMMON_SRC) src/mt_adaptor.c
libzkmt_la_CFLAGS = -DTHREADED
libzkmt_la_LIBADD = -lm $(CLOCK_GETTIME_LIBS)
lib_LTLIBRARIES += libzookeeper_mt.la
libzookeeper_mt_la_SOURCES =
libzookeeper_mt_la_LIBADD=libzkmt.la libhashtable.la -lpthread
libzookeeper_mt_la_DEPENDENCIES=libzkmt.la libhashtable.la
libzookeeper_mt_la_LDFLAGS = $(LIB_LDFLAGS) -export-symbols-regex $(EXPORT_SYMBOLS)
endif
bin_PROGRAMS = cli_st
cli_st_SOURCES = src/cli.c
cli_st_LDADD = libzookeeper_st.la
if WANT_SYNCAPI
bin_PROGRAMS += cli_mt load_gen
cli_mt_SOURCES = src/cli.c
cli_mt_LDADD = libzookeeper_mt.la
cli_mt_CFLAGS = -DTHREADED
load_gen_SOURCES = src/load_gen.c
load_gen_LDADD = libzookeeper_mt.la
load_gen_CFLAGS = -DTHREADED
endif
#########################################################################
# build and run unit tests
EXTRA_DIST+=$(wildcard ${srcdir}/tests/*.cc) $(wildcard ${srcdir}/tests/*.h) \
${srcdir}/tests/wrappers.opt ${srcdir}/tests/wrappers-mt.opt
# These tests are ordered in a logical manner such that each builds upon basic
# functionality tested in prior tests. e.g. the most basic functionality is
# tested in TestZookeeperInit and TestZookeeperClose and as such should be tested
# first as a foundation with more complex test suites to follow.
TEST_SOURCES = \
tests/TestDriver.cc \
tests/LibCMocks.cc \
tests/LibCSymTable.cc \
tests/MocksBase.cc \
tests/ZKMocks.cc \
tests/Util.cc \
tests/ThreadingUtil.cc \
tests/TestZookeeperInit.cc \
tests/TestZookeeperClose.cc \
tests/TestReconfig.cc \
tests/TestReconfigServer.cc \
tests/TestClientRetry.cc \
tests/TestOperations.cc \
tests/TestMulti.cc \
tests/TestWatchers.cc \
tests/TestClient.cc \
tests/ZooKeeperQuorumServer.cc \
tests/ZooKeeperQuorumServer.h \
tests/TestReadOnlyClient.cc \
tests/TestLogClientEnv.cc \
tests/TestServerRequireClientSASLAuth.cc \
$(NULL)
if SOLARIS
SHELL_SYMBOL_WRAPPERS = cat ${srcdir}/tests/wrappers.opt
SYMBOL_WRAPPERS=$(SHELL_SYMBOL_WRAPPERS:sh)
else
SYMBOL_WRAPPERS=$(shell cat ${srcdir}/tests/wrappers.opt)
endif
check_PROGRAMS = zktest-st
TESTS_ENVIRONMENT = ZKROOT=${srcdir}/../.. \
CLASSPATH=$$CLASSPATH:$$CLOVER_HOME/lib/clover*.jar
nodist_zktest_st_SOURCES = $(TEST_SOURCES)
zktest_st_LDADD = libzkst.la libhashtable.la $(CPPUNIT_LIBS) $(OPENSSL_LIB_LDFLAGS) -ldl
zktest_st_CXXFLAGS = -DUSE_STATIC_LIB $(CPPUNIT_CFLAGS) $(USEIPV6) $(SOLARIS_CPPFLAGS)
zktest_st_LDFLAGS = -shared $(SYMBOL_WRAPPERS) $(SOLARIS_LIB_LDFLAGS)
if WANT_SYNCAPI
check_PROGRAMS += zktest-mt
nodist_zktest_mt_SOURCES = $(TEST_SOURCES) tests/PthreadMocks.cc
zktest_mt_LDADD = libzkmt.la libhashtable.la -lpthread $(CPPUNIT_LIBS) $(OPENSSL_LIB_LDFLAGS) -ldl
zktest_mt_CXXFLAGS = -DUSE_STATIC_LIB -DTHREADED $(CPPUNIT_CFLAGS) $(USEIPV6)
if SOLARIS
SHELL_SYMBOL_WRAPPERS_MT = cat ${srcdir}/tests/wrappers-mt.opt
SYMBOL_WRAPPERS_MT=$(SYMBOL_WRAPPERS) $(SHELL_SYMBOL_WRAPPERS_MT:sh)
else
SYMBOL_WRAPPERS_MT=$(SYMBOL_WRAPPERS) $(shell cat ${srcdir}/tests/wrappers-mt.opt)
endif
zktest_mt_LDFLAGS = -shared $(SYMBOL_WRAPPERS_MT) $(SOLARIS_LIB_LDFLAGS)
endif
TESTS = $(check_PROGRAMS)
clean-local: clean-check
$(RM) $(DX_CLEANFILES)
clean-check:
$(RM) $(nodist_zktest_st_OBJECTS) $(nodist_zktest_mt_OBJECTS)

View File

@ -0,0 +1,41 @@
Apache ZooKeeper
Copyright 2009-2011 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
----------
include/winstdint.h is included only for Windows Client support, as follows:
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2008 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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,163 @@
Zookeeper C client library
This package provides a C client interface to Zookeeper server.
For the latest information about ZooKeeper, please visit our website at:
http://zookeeper.apache.org/
and our wiki, at:
https://cwiki.apache.org/confluence/display/ZOOKEEPER
Full documentation for this release can also be found in ../../docs/index.html
OVERVIEW
The client supports two types of APIs -- synchronous and asynchronous.
Asynchronous API provides non-blocking operations with completion callbacks and
relies on the application to implement event multiplexing on its behalf.
On the other hand, Synchronous API provides a blocking flavor of
zookeeper operations and runs its own event loop in a separate thread.
Sync and Async APIs can be mixed and matched within the same application.
The package includes two shared libraries: zookeeper_st and
zookeeper_mt. The former only provides the Async API and is not
thread-safe. The only reason this library exists is to support the
platforms were pthread library is not available or unstable
(i.e. FreeBSD 4.x). In all other cases the application developers are
advised to link against zookeeper_mt as it includes support for both
Sync and Async API.
INSTALLATION
If you're building the client from a source checkout you need to
follow the steps outlined below. If you're building from a release
tar downloaded from Apache please skip to step 2.
1) do a "ant compile_jute" from the zookeeper top level directory (.../trunk).
This will create a directory named "generated" under zookeeper-client/zookeeper-client-c.
Skip to step 3.
2) unzip/untar the source tarball and cd to the zookeeper-x.x.x/zookeeper-client/zookeeper-client-c directory
3) change directory to zookeeper-client/zookeeper-client-c and do a "autoreconf -if" to bootstrap
autoconf, automake and libtool. Please make sure you have autoconf
version 2.59 or greater installed. If cppunit is installed in a non-standard
directory, you need to specify where to find cppunit.m4. For example, if
cppunit is installed under /usr/local, run:
ACLOCAL="aclocal -I /usr/local/share/aclocal" autoreconf -if
4) do a "./configure [OPTIONS]" to generate the makefile. See INSTALL
for general information about running configure. Additionally, the
configure supports the following options:
--enable-debug enables optimization and enables debug info compiler
options, disabled by default
--without-syncapi disables Sync API support; zookeeper_mt library won't
be built, enabled by default
--disable-static do not build static libraries, enabled by default
--disable-shared do not build shared libraries, enabled by default
--without-cppunit do not build the test library, enabled by default.
5) do a "make" or "make install" to build the libraries and install them.
Alternatively, you can also build and run a unit test suite (and
you probably should). Please make sure you have cppunit-1.10.x or
higher installed before you execute step 4. Once ./configure has
finished, do a "make check". It will build the libraries, build
the tests and run them.
6) to generate doxygen documentation do a "make doxygen-doc". All
documentations will be placed to a new subfolder named docs. By
default only HTML documentation is generated. For information on
other document formats please use "./configure --help"
Alternatively you can use the CMake build system. On Windows, this is required.
Follow steps 1 and 2 above, and then continue here.
1) do a "cmake [OPTIONS]" to generate the makefile or msbuild files (the correct
build system will be generated based on your platform). Some options from above
are supported:
-DCMAKE_BUILD_TYPE Debug by default, Release enables optimzation etc.
-DWANT_SYNCAPI ON by default, OFF disables the Sync API support
-DWANT_CPPUNIT ON except on Windows, OFF disables the tests
-DWITH_OPENSSL ON by default, OFF disables the SSL support. You can also
specify a custom path by -DWITH_OPENSSL=/path/to/openssl/
-DBUILD_SHARED_LIBS not yet supported, only static libraries are built
other CMake options see "cmake --help" for generic options, such as generator
2) do a "cmake --build ." to build the default targets. Alternatively you can
invoke "make" or "msbuild" manually. If the tests were enabled, use "ctest -V"
to run them.
Current limitations of the CMake build system include lack of Solaris support,
no shared library option, no explicitly exported symbols (all are exported by
default), no versions on the libraries, and no documentation generation.
Features of CMake include a single, easily consumed cross-platform build system
to generate the ZooKeeper C Client libraries for any project, with little to no
configuration.
EXAMPLE/SAMPLE C CLIENT SHELL
NOTE: the ZooKeeper C client shell (cli_st and cli_mt) is meant as a
example/sample of ZooKeeper C client API usage. It is not a full
fledged client and not meant for production usage - see the Java
client shell for a fully featured shell.
You can test your client by running a zookeeper server (see
instructions on the project wiki page on how to run it) and connecting
to it using the zookeeper shell application cli that is built as part
of the installation procedure.
cli_mt (multithreaded, built against zookeeper_mt library) is shown in
this example, but you could also use cli_st (singlethreaded, built
against zookeeper_st library):
$ cli_mt zookeeper_host:9876
To start a client with read-only mode enabled, use the -r flag:
$ cli_mt -r zookeeper_host:9876
This is a client application that gives you a shell for executing
simple zookeeper commands. Once successfully started and connected to
the server it displays a shell prompt.
You can now enter zookeeper commands. For example, to create a node:
> create /my_new_node
To verify that the node's been created:
> ls /
You should see a list of nodes who are the children of the root node "/".
Here's a list of command supported by the cli shell:
ls <path> -- list children of a znode identified by <path>. The
command set a children watch on the znode.
get <path> -- get the value of a znode at <path>
set <path> <value> -- set the value of a znode at <path> to <value>
create [+e|+s] <path> -- create a znode as a child of znode <path>;
use +e option to create an ephemeral znode,
use +s option to create a znode with a sequence number
appended to the name. The operation will fail if
the parent znode (the one identified by <path>) doesn't
exist.
delete <path> -- delete the znode at <path>. The command will fail if the znode
has children.
sync <path> -- make sure all pending updates have been applied to znode at <path>
exists <path> -- returns a result code indicating whether the znode at <path>
exists. The command also sets a znode watch.
myid -- prints out the current zookeeper session id.
quit -- exit the shell.
In order to be able to use the zookeeper API in your application you have to
1) remember to include the zookeeper header
#include <zookeeper/zookeeper.h>
2) use -DTHREADED compiler option to enable Sync API; in this case you should
be linking your code against zookeeper_mt library
Please take a look at cli.c to understand how to use the two API types.
(TODO: some kind of short tutorial would be helpful, I guess)

View File

@ -0,0 +1,327 @@
# This file is part of Autoconf. -*- Autoconf -*-
# Copyright (C) 2004 Oren Ben-Kiki
# This file is distributed under the same terms as the Autoconf macro files.
# Generate automatic documentation using Doxygen. Works in concert with the
# aminclude.m4 file and a compatible doxygen configuration file. Defines the
# following public macros:
#
# DX_???_FEATURE(ON|OFF) - control the default setting of a Doxygen feature.
# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics,
# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI'
# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF',
# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment
# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide'
# paper size.
#
# By default, HTML, PDF and PS documentation is generated as this seems to be
# the most popular and portable combination. MAN pages created by Doxygen are
# usually problematic, though by picking an appropriate subset and doing some
# massaging they might be better than nothing. CHM and RTF are specific for MS
# (note that you can't generate both HTML and CHM at the same time). The XML is
# rather useless unless you apply specialized post-processing to it.
#
# The macro mainly controls the default state of the feature. The use can
# override the default by specifying --enable or --disable. The macros ensure
# that contradictory flags are not given (e.g., --enable-doxygen-html and
# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.)
# Finally, each feature will be automatically disabled (with a warning) if the
# required programs are missing.
#
# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with
# the following parameters: a one-word name for the project for use as a
# filename base etc., an optional configuration file name (the default is
# 'Doxyfile', the same as Doxygen's default), and an optional output directory
# name (the default is 'doxygen-doc').
## ----------##
## Defaults. ##
## ----------##
DX_ENV=""
AC_DEFUN([DX_FEATURE_doc], ON)
AC_DEFUN([DX_FEATURE_dot], ON)
AC_DEFUN([DX_FEATURE_man], OFF)
AC_DEFUN([DX_FEATURE_html], ON)
AC_DEFUN([DX_FEATURE_chm], OFF)
AC_DEFUN([DX_FEATURE_chi], OFF)
AC_DEFUN([DX_FEATURE_rtf], OFF)
AC_DEFUN([DX_FEATURE_xml], OFF)
AC_DEFUN([DX_FEATURE_pdf], ON)
AC_DEFUN([DX_FEATURE_ps], ON)
## --------------- ##
## Private macros. ##
## --------------- ##
# DX_ENV_APPEND(VARIABLE, VALUE)
# ------------------------------
# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen.
AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])])
# DX_DIRNAME_EXPR
# ---------------
# Expand into a shell expression prints the directory part of a path.
AC_DEFUN([DX_DIRNAME_EXPR],
[[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
# -------------------------------------
# Expands according to the M4 (static) status of the feature.
AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
# ----------------------------------
# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
AC_DEFUN([DX_REQUIRE_PROG], [
AC_PATH_TOOL([$1], [$2])
if test "$DX_FLAG_$[DX_CURRENT_FEATURE$$1]" = 1; then
AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)
fi
])
# DX_TEST_FEATURE(FEATURE)
# ------------------------
# Expand to a shell expression testing whether the feature is active.
AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
# -------------------------------------------------
# Verify that a required features has the right state before trying to turn on
# the DX_CURRENT_FEATURE.
AC_DEFUN([DX_CHECK_DEPEND], [
test "$DX_FLAG_$1" = "$2" \
|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
requires, contradicts) doxygen-DX_CURRENT_FEATURE])
])
# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
# ----------------------------------------------------------
# Turn off the DX_CURRENT_FEATURE if the required feature is off.
AC_DEFUN([DX_CLEAR_DEPEND], [
test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)
])
# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
# CHECK_DEPEND, CLEAR_DEPEND,
# REQUIRE, DO-IF-ON, DO-IF-OFF)
# --------------------------------------------
# Parse the command-line option controlling a feature. CHECK_DEPEND is called
# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
# otherwise CLEAR_DEPEND is called to turn off the default state if a required
# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
AC_DEFUN([DX_ARG_ABLE], [
AC_DEFUN([DX_CURRENT_FEATURE], [$1])
AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
AC_ARG_ENABLE(doxygen-$1,
[AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
[--enable-doxygen-$1]),
DX_IF_FEATURE([$1], [don't $2], [$2]))],
[
case "$enableval" in
#(
y|Y|yes|Yes|YES)
AC_SUBST([DX_FLAG_$1], 1)
$3
;; #(
n|N|no|No|NO)
AC_SUBST([DX_FLAG_$1], 0)
;; #(
*)
AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
;;
esac
], [
AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
$4
])
if DX_TEST_FEATURE([$1]); then
$5
:
fi
if DX_TEST_FEATURE([$1]); then
AM_CONDITIONAL(DX_COND_$1, :)
$6
:
else
AM_CONDITIONAL(DX_COND_$1, false)
$7
:
fi
])
## -------------- ##
## Public macros. ##
## -------------- ##
# DX_XXX_FEATURE(DEFAULT_STATE)
# -----------------------------
AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])
# ---------------------------------------------------------
# PROJECT also serves as the base name for the documentation files.
# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc".
AC_DEFUN([DX_INIT_DOXYGEN], [
# Files:
AC_SUBST([DX_PROJECT], [$1])
AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])])
AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])])
# Environment variables used inside doxygen.cfg:
DX_ENV_APPEND(SRCDIR, $srcdir)
DX_ENV_APPEND(PROJECT, $DX_PROJECT)
DX_ENV_APPEND(DOCDIR, $DX_DOCDIR)
DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
# Doxygen itself:
DX_ARG_ABLE(doc, [generate any doxygen documentation],
[],
[],
[DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
DX_REQUIRE_PROG([DX_PERL], perl)],
[DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
# Dot for graphics:
DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_DOT], dot)],
[DX_ENV_APPEND(HAVE_DOT, YES)
DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
[DX_ENV_APPEND(HAVE_DOT, NO)])
# Man pages generation:
DX_ARG_ABLE(man, [generate doxygen manual pages],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_MAN, YES)],
[DX_ENV_APPEND(GENERATE_MAN, NO)])
# RTF file generation:
DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_RTF, YES)],
[DX_ENV_APPEND(GENERATE_RTF, NO)])
# XML file generation:
DX_ARG_ABLE(xml, [generate doxygen XML documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_XML, YES)],
[DX_ENV_APPEND(GENERATE_XML, NO)])
# (Compressed) HTML help generation:
DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_HHC], hhc)],
[DX_ENV_APPEND(HHC_PATH, $DX_HHC)
DX_ENV_APPEND(GENERATE_HTML, YES)
DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
[DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
# Seperate CHI file generation.
DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],
[DX_CHECK_DEPEND(chm, 1)],
[DX_CLEAR_DEPEND(chm, 1)],
[],
[DX_ENV_APPEND(GENERATE_CHI, YES)],
[DX_ENV_APPEND(GENERATE_CHI, NO)])
# Plain HTML pages generation:
DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
[DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
[DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
[],
[DX_ENV_APPEND(GENERATE_HTML, YES)],
[DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
# PostScript file generation:
DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_LATEX], latex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_DVIPS], dvips)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# PDF file generation:
DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# LaTeX generation for PS and/or PDF:
if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
AM_CONDITIONAL(DX_COND_latex, :)
DX_ENV_APPEND(GENERATE_LATEX, YES)
else
AM_CONDITIONAL(DX_COND_latex, false)
DX_ENV_APPEND(GENERATE_LATEX, NO)
fi
# Paper size for PS and/or PDF:
AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
[a4wide (default), a4, letter, legal or executive])
case "$DOXYGEN_PAPER_SIZE" in
#(
"")
AC_SUBST(DOXYGEN_PAPER_SIZE, "")
;; #(
a4wide|a4|letter|legal|executive)
DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
;; #(
*)
AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
;;
esac
#For debugging:
#echo DX_FLAG_doc=$DX_FLAG_doc
#echo DX_FLAG_dot=$DX_FLAG_dot
#echo DX_FLAG_man=$DX_FLAG_man
#echo DX_FLAG_html=$DX_FLAG_html
#echo DX_FLAG_chm=$DX_FLAG_chm
#echo DX_FLAG_chi=$DX_FLAG_chi
#echo DX_FLAG_rtf=$DX_FLAG_rtf
#echo DX_FLAG_xml=$DX_FLAG_xml
#echo DX_FLAG_pdf=$DX_FLAG_pdf
#echo DX_FLAG_ps=$DX_FLAG_ps
#echo DX_ENV=$DX_ENV
])
# CHECK_CPPUNIT
# ------------------
# Check for cppunit presence.
AC_DEFUN([CHECK_CPPUNIT], [
ifdef(
[AM_PATH_CPPUNIT],
[AM_PATH_CPPUNIT($1)],
[ifdef(
[PKG_CHECK_MODULES],
[PKG_CHECK_MODULES([CPPUNIT], [cppunit >= $1])],
[m4_fatal([Missing AM_PATH_CPPUNIT or PKG_CHECK_MODULES m4 macro.])]
)]
)
])

View File

@ -0,0 +1,186 @@
# Copyright (C) 2004 Oren Ben-Kiki
# This file is distributed under the same terms as the Automake macro files.
# Generate automatic documentation using Doxygen. Goals and variables values
# are controlled by the various DX_COND_??? conditionals set by autoconf.
#
# The provided goals are:
# doxygen-doc: Generate all doxygen documentation.
# doxygen-run: Run doxygen, which will generate some of the documentation
# (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post
# processing required for the rest of it (PS, PDF, and some MAN).
# doxygen-man: Rename some doxygen generated man pages.
# doxygen-ps: Generate doxygen PostScript documentation.
# doxygen-pdf: Generate doxygen PDF documentation.
#
# Note that by default these are not integrated into the automake goals. If
# doxygen is used to generate man pages, you can achieve this integration by
# setting man3_MANS to the list of man pages generated and then adding the
# dependency:
#
# $(man3_MANS): doxygen-doc
#
# This will cause make to run doxygen and generate all the documentation.
#
# The following variable is intended for use in Makefile.am:
#
# DX_CLEANFILES = everything to clean.
#
# This is usually added to MOSTLYCLEANFILES.
## --------------------------------- ##
## Format-independent Doxygen rules. ##
## --------------------------------- ##
if DX_COND_doc
## ------------------------------- ##
## Rules specific for HTML output. ##
## ------------------------------- ##
if DX_COND_html
DX_CLEAN_HTML = @DX_DOCDIR@/html
endif DX_COND_html
## ------------------------------ ##
## Rules specific for CHM output. ##
## ------------------------------ ##
if DX_COND_chm
DX_CLEAN_CHM = @DX_DOCDIR@/chm
if DX_COND_chi
DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi
endif DX_COND_chi
endif DX_COND_chm
## ------------------------------ ##
## Rules specific for MAN output. ##
## ------------------------------ ##
if DX_COND_man
DX_CLEAN_MAN = @DX_DOCDIR@/man
endif DX_COND_man
## ------------------------------ ##
## Rules specific for RTF output. ##
## ------------------------------ ##
if DX_COND_rtf
DX_CLEAN_RTF = @DX_DOCDIR@/rtf
endif DX_COND_rtf
## ------------------------------ ##
## Rules specific for XML output. ##
## ------------------------------ ##
if DX_COND_xml
DX_CLEAN_XML = @DX_DOCDIR@/xml
endif DX_COND_xml
## ----------------------------- ##
## Rules specific for PS output. ##
## ----------------------------- ##
if DX_COND_ps
DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps
DX_PS_GOAL = doxygen-ps
doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps
@DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag
cd @DX_DOCDIR@/latex; \
rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
$(DX_LATEX) refman.tex; \
$(MAKEINDEX_PATH) refman.idx; \
$(DX_LATEX) refman.tex; \
countdown=5; \
while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
refman.log > /dev/null 2>&1 \
&& test $$countdown -gt 0; do \
$(DX_LATEX) refman.tex; \
countdown=`expr $$countdown - 1`; \
done; \
$(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi
endif DX_COND_ps
## ------------------------------ ##
## Rules specific for PDF output. ##
## ------------------------------ ##
if DX_COND_pdf
DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf
DX_PDF_GOAL = doxygen-pdf
doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf
@DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag
cd @DX_DOCDIR@/latex; \
rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
$(DX_PDFLATEX) refman.tex; \
$(DX_MAKEINDEX) refman.idx; \
$(DX_PDFLATEX) refman.tex; \
countdown=5; \
while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
refman.log > /dev/null 2>&1 \
&& test $$countdown -gt 0; do \
$(DX_PDFLATEX) refman.tex; \
countdown=`expr $$countdown - 1`; \
done; \
mv refman.pdf ../@PACKAGE@.pdf
endif DX_COND_pdf
## ------------------------------------------------- ##
## Rules specific for LaTeX (shared for PS and PDF). ##
## ------------------------------------------------- ##
if DX_COND_latex
DX_CLEAN_LATEX = @DX_DOCDIR@/latex
endif DX_COND_latex
.PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)
.INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag
doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
@DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS)
rm -rf @DX_DOCDIR@
$(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)
DX_CLEANFILES = \
@DX_DOCDIR@/@PACKAGE@.tag \
-r \
$(DX_CLEAN_HTML) \
$(DX_CLEAN_CHM) \
$(DX_CLEAN_CHI) \
$(DX_CLEAN_MAN) \
$(DX_CLEAN_RTF) \
$(DX_CLEAN_XML) \
$(DX_CLEAN_PS) \
$(DX_CLEAN_PDF) \
$(DX_CLEAN_LATEX)
endif DX_COND_doc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
/**
* 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 CONFIG_H_
#define CONFIG_H_
/* Define to 1 if you have the <arpa/inet.h> header file. */
#cmakedefine HAVE_ARPA_INET_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#cmakedefine HAVE_FCNTL_H 1
/* Define to 1 if you have the file `generated/zookeeper.jute.c'. */
#cmakedefine HAVE_GENERATED_ZOOKEEPER_JUTE_C 1
/* Define to 1 if you have the file `generated/zookeeper.jute.h'. */
#cmakedefine HAVE_GENERATED_ZOOKEEPER_JUTE_H 1
/* Define to 1 if you have the `getcwd' function. */
#cmakedefine HAVE_GETCWD 1
/* Define to 1 if you have the `gethostbyname' function. */
#cmakedefine HAVE_GETHOSTBYNAME 1
/* Define to 1 if you have the `gethostname' function. */
#cmakedefine HAVE_GETHOSTNAME 1
/* Define to 1 if you have the `getlogin' function. */
#cmakedefine HAVE_GETLOGIN 1
/* Define to 1 if you have the `getpwuid_r' function. */
#cmakedefine HAVE_GETPWUID_R 1
/* Define to 1 if you have the `gettimeofday' function. */
#cmakedefine HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the `getuid' function. */
#cmakedefine HAVE_GETUID 1
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H 1
/* Define to 1 if you have the `rt' library (-lrt). */
#cmakedefine HAVE_LIBRT 1
/* Define to 1 if you have the `memmove' function. */
#cmakedefine HAVE_MEMMOVE 1
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#cmakedefine HAVE_MEMSET 1
/* Define to 1 if you have the <netdb.h> header file. */
#cmakedefine HAVE_NETDB_H 1
/* Define to 1 if you have the <netinet/in.h> header file. */
#cmakedefine HAVE_NETINET_IN_H 1
/* Define to 1 if you have the `poll' function. */
#cmakedefine HAVE_POLL 1
/* Define to 1 if you have the `socket' function. */
#cmakedefine HAVE_SOCKET 1
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#cmakedefine HAVE_STRCHR 1
/* Define to 1 if you have the `strdup' function. */
#cmakedefine HAVE_STRDUP 1
/* Define to 1 if you have the `strerror' function. */
#cmakedefine HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H 1
/* Define to 1 if you have the `strtol' function. */
#cmakedefine HAVE_STRTOL 1
/* Define to 1 if you have the <sys/socket.h> header file. */
#cmakedefine HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/utsname.h> header file. */
#cmakedefine HAVE_SYS_UTSNAME_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1
/* Define to 1 if IPv6 support is available. */
#cmakedefine ZOO_IPV6_ENABLED 1
/* Define to 1 if SOCK_CLOEXEC is available and wanted */
#cmakedefine SOCK_CLOEXEC_ENABLED 1
/* poll() second argument type */
#define POLL_NFDS_TYPE nfds_t
/* Name of package */
#define PACKAGE "${PROJECT_NAME}"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "${email}"
/* Define to the full name of this package. */
#define PACKAGE_NAME "${description}"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "${description} ${PROJECT_VERSION}"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "${PROJECT_NAME}"
/* Define to the version of this package. */
#define PACKAGE_VERSION "${PROJECT_VERSION}"
/* Version number of package */
#define VERSION "${PROJECT_VERSION}"
#endif

View File

@ -0,0 +1,245 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT([zookeeper C client],3.6.3,[user@zookeeper.apache.org],[zookeeper])
AC_CONFIG_SRCDIR([src/zookeeper.c])
# Save initial CFLAGS and CXXFLAGS values before AC_PROG_CC and AC_PROG_CXX
init_cflags="$CFLAGS"
init_cxxflags="$CXXFLAGS"
# initialize Doxygen support
DX_HTML_FEATURE(ON)
DX_CHM_FEATURE(OFF)
DX_CHI_FEATURE(OFF)
DX_MAN_FEATURE(OFF)
DX_RTF_FEATURE(OFF)
DX_XML_FEATURE(OFF)
DX_PDF_FEATURE(OFF)
DX_PS_FEATURE(OFF)
DX_INIT_DOXYGEN([zookeeper],[c-doc.Doxyfile],[docs])
# initialize automake
AM_INIT_AUTOMAKE([-Wall foreign])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_ARG_WITH(cppunit,
[ --without-cppunit do not use CPPUNIT])
if test "$with_cppunit" = "no" ; then
CPPUNIT_PATH="No_CPPUNIT"
CPPUNIT_INCLUDE=
CPPUNIT_LIBS=
else
CHECK_CPPUNIT(1.10.2)
fi
dnl OpenSSL
AC_ARG_WITH(openssl,
[AC_HELP_STRING([--with-openssl[=DIR]], [build with openssl (autodetect openssl library by default) )])],
[], [with_openssl=yes])
AC_MSG_NOTICE([configuring SSL using --with-openssl=$with_openssl])
saved_CPPFLAGS="$CPPFLAGS"
saved_LDFLAGS="$LDFLAGS"
if test "x$with_openssl" != "xno" && test "x$with_openssl" != "xyes" ; then
CPPFLAGS="$CPPFLAGS -I$with_openssl/include"
LDFLAGS="$LDFLAGS -L$with_openssl/lib"
fi
have_openssl=no
AC_CHECK_HEADER(openssl/ssl.h, [ AC_CHECK_LIB(ssl, SSL_CTX_new, [have_openssl=yes]) ])
if test "x$with_openssl" != "xno" && test "x$with_openssl" != "xyes" && test "x$have_openssl" != "xyes"; then
CPPFLAGS="$saved_CPPFLAGS"
LDFLAGS="$saved_LDFLAGS"
fi
if test "x$with_openssl" != xno && test "x$have_openssl" = xno; then
AC_MSG_WARN([cannot build SSL support -- openssl not found])
with_openssl=no
fi
if test "x$with_openssl" != xno; then
AC_MSG_NOTICE([building with SSL support])
else
AC_MSG_NOTICE([building without SSL support])
fi
AM_CONDITIONAL([WANT_OPENSSL],[test "x$with_openssl" != xno])
if test "$CALLER" = "ANT" ; then
CPPUNIT_CFLAGS="$CPPUNIT_CFLAGS -DZKSERVER_CMD=\"\\\"${base_dir}/zookeeper-client/zookeeper-client-c/tests/zkServer.sh\\\"\""
else
CPPUNIT_CFLAGS="$CPPUNIT_CFLAGS -DZKSERVER_CMD=\"\\\"./tests/zkServer.sh\\\"\""
AC_CHECK_FILES([$srcdir/generated/zookeeper.jute.c $srcdir/generated/zookeeper.jute.h],[],
[AC_MSG_ERROR([jute files are missing! Please run "ant compile_jute" while in the zookeeper top level directory.])
])
fi
AC_SUBST(CPPUNIT_CFLAGS)
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_LN_S
# AC_DISABLE_SHARED
AC_PROG_LIBTOOL
#enable -D_GNU_SOURCE since the return code value of getaddrinfo
#ifdefed with __USE_GNU
#features.h header undef's __USE_GNU and defines it only if _GNU_SOURCE is defined
#hence this define for gcc
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],[enable debug build [default=no]])],
[],[enable_debug=no])
if test "x$enable_debug" = xyes; then
if test "x$init_cflags" = x; then
CFLAGS=""
fi
CFLAGS="$CFLAGS -g -O0 -D_GNU_SOURCE"
else
if test "x$init_cflags" = x; then
CFLAGS="-g -O2 -D_GNU_SOURCE"
fi
fi
if test "x$enable_debug" = xyes; then
if test "x$init_cxxflags" = x; then
CXXFLAGS=""
fi
CXXFLAGS="$CXXFLAGS -g -O0"
else
if test "x$init_cxxflags" = x; then
CXXFLAGS="-g -O2"
fi
fi
# Check whether to enable gcov (coverage test)
AC_ARG_ENABLE(gcov, [AS_HELP_STRING([--enable-gcov],[enable coverage test])])
AC_MSG_CHECKING([whether to enable gcov])
AS_IF([test "x${enable_gcov}" = "xyes"],AC_MSG_RESULT([yes]),AC_MSG_RESULT([no]))
AM_CONDITIONAL([ENABLEGCOV],[test "x${enable_gcov}" = "xyes"])
CXXFLAGS="$CXXFLAGS -std=c++11"
AC_ARG_WITH([syncapi],
[AS_HELP_STRING([--with-syncapi],[build with support for SyncAPI [default=yes]])],
[],[with_syncapi=yes])
# Checks for libraries.
AC_CHECK_LIB([pthread], [pthread_mutex_lock],[have_pthread=yes],[have_pthread=no])
if test "x$with_syncapi" != xno && test "x$have_pthread" = xno; then
AC_MSG_WARN([cannot build SyncAPI -- pthread not found])
with_syncapi=no
fi
if test "x$with_syncapi" != xno; then
AC_MSG_NOTICE([building with SyncAPI support])
else
AC_MSG_NOTICE([building without SyncAPI support])
fi
AM_CONDITIONAL([WANT_SYNCAPI],[test "x$with_syncapi" != xno])
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h sys/utsname.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_HEADER_TIME
AC_CHECK_TYPE([nfds_t],
[AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[poll() second argument type])],
[AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[poll() second argument type])],
[#include <poll.h>])
AC_MSG_CHECKING([whether to enable ipv6])
AC_TRY_RUN([ /* is AF_INET6 available? */
#include <sys/types.h>
#include <sys/socket.h>
main()
{
if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
exit(1);
else
exit(0);
}
], AC_MSG_RESULT(yes)
ipv6=yes,
AC_MSG_RESULT(no)
ipv6=no,
AC_MSG_RESULT(no)
ipv6=no)
if test x"$ipv6" = xyes; then
USEIPV6="-DZOO_IPV6_ENABLED"
AC_SUBST(USEIPV6)
fi
# use SOCK_CLOEXEC if available and wanted
AC_ARG_WITH([sock_cloexec],
[AS_HELP_STRING([--with-sock-cloexec],[build with SOCK_CLOEXEC flag set on the connections])],
[],[with_sock_cloexec=no])
AC_MSG_CHECKING([whether SOCK_CLOEXEC is available])
AC_TRY_RUN([ /* is SOCK_CLOEXEC available ? */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
main()
{
#ifdef SOCK_CLOEXEC
exit(0);
#else
exit(1);
#endif
}
], AC_MSG_RESULT(yes)
has_sock_cloexec=yes,
AC_MSG_RESULT(no)
has_sock_cloexec=no,
AC_MSG_RESULT(no)
has_sock_cloexec=no)
if test "x$with_sock_cloexec" != xno && test "x$has_sock_cloexec" = xno; then
AC_MSG_WARN([cannot use SOCK_CLOEXEC -- SOCK_CLOEXEC undefined on this platform])
with_sock_cloexec=no
fi
if test "x$with_sock_cloexec" != xno; then
AC_MSG_NOTICE([building with SOCK_CLOEXEC])
else
AC_MSG_NOTICE([building without SOCK_CLOEXEC])
fi
AS_IF([test x"$with_sock_cloexec" != xno], [AC_DEFINE([SOCK_CLOEXEC_ENABLED], [1], [Define to 1, if SOCK_CLOEXEC is defined and wanted])])
AM_CONDITIONAL([SOCK_CLOEXEC_ENABLED],[test "x$with_sock_cloexec" != xno])
# Determine which libraries we need to use clock_gettime
saved_LIBS="$LIBS"
LIBS=""
AC_CHECK_LIB(rt, clock_gettime)
CLOCK_GETTIME_LIBS=$LIBS
AC_SUBST(CLOCK_GETTIME_LIBS)
LIBS="$saved_LIBS"
# Checks for library functions.
AC_CHECK_FUNCS([getcwd gethostbyname gethostname getlogin getpwuid_r gettimeofday getuid memmove memset poll socket strchr strdup strerror strtol])
AC_CONFIG_FILES([Makefile])
AC_CANONICAL_HOST
AM_CONDITIONAL([SOLARIS],[
case "$host_os" in
*solaris*)
true
;;
*)
false
;;
esac ])
AC_OUTPUT

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,595 @@
/**
* 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 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 SetWatches2 {
int64_t relativeZxid;
struct String_vector dataWatches;
struct String_vector existWatches;
struct String_vector childWatches;
struct String_vector persistentWatches;
struct String_vector persistentRecursiveWatches;
};
int serialize_SetWatches2(struct oarchive *out, const char *tag, struct SetWatches2 *v);
int deserialize_SetWatches2(struct iarchive *in, const char *tag, struct SetWatches2*v);
void deallocate_SetWatches2(struct SetWatches2*);
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 ReconfigRequest {
char * joiningServers;
char * leavingServers;
char * newMembers;
int64_t curConfigId;
};
int serialize_ReconfigRequest(struct oarchive *out, const char *tag, struct ReconfigRequest *v);
int deserialize_ReconfigRequest(struct iarchive *in, const char *tag, struct ReconfigRequest*v);
void deallocate_ReconfigRequest(struct ReconfigRequest*);
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 CreateTTLRequest {
char * path;
struct buffer data;
struct ACL_vector acl;
int32_t flags;
int64_t ttl;
};
int serialize_CreateTTLRequest(struct oarchive *out, const char *tag, struct CreateTTLRequest *v);
int deserialize_CreateTTLRequest(struct iarchive *in, const char *tag, struct CreateTTLRequest*v);
void deallocate_CreateTTLRequest(struct CreateTTLRequest*);
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 GetAllChildrenNumberRequest {
char * path;
};
int serialize_GetAllChildrenNumberRequest(struct oarchive *out, const char *tag, struct GetAllChildrenNumberRequest *v);
int deserialize_GetAllChildrenNumberRequest(struct iarchive *in, const char *tag, struct GetAllChildrenNumberRequest*v);
void deallocate_GetAllChildrenNumberRequest(struct GetAllChildrenNumberRequest*);
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 AddWatchRequest {
char * path;
int32_t mode;
};
int serialize_AddWatchRequest(struct oarchive *out, const char *tag, struct AddWatchRequest *v);
int deserialize_AddWatchRequest(struct iarchive *in, const char *tag, struct AddWatchRequest*v);
void deallocate_AddWatchRequest(struct AddWatchRequest*);
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 Create2Response {
char * path;
struct Stat stat;
};
int serialize_Create2Response(struct oarchive *out, const char *tag, struct Create2Response *v);
int deserialize_Create2Response(struct iarchive *in, const char *tag, struct Create2Response*v);
void deallocate_Create2Response(struct Create2Response*);
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 GetAllChildrenNumberResponse {
int32_t totalNumber;
};
int serialize_GetAllChildrenNumberResponse(struct oarchive *out, const char *tag, struct GetAllChildrenNumberResponse *v);
int deserialize_GetAllChildrenNumberResponse(struct iarchive *in, const char *tag, struct GetAllChildrenNumberResponse*v);
void deallocate_GetAllChildrenNumberResponse(struct GetAllChildrenNumberResponse*);
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 CheckWatchesRequest {
char * path;
int32_t type;
};
int serialize_CheckWatchesRequest(struct oarchive *out, const char *tag, struct CheckWatchesRequest *v);
int deserialize_CheckWatchesRequest(struct iarchive *in, const char *tag, struct CheckWatchesRequest*v);
void deallocate_CheckWatchesRequest(struct CheckWatchesRequest*);
struct RemoveWatchesRequest {
char * path;
int32_t type;
};
int serialize_RemoveWatchesRequest(struct oarchive *out, const char *tag, struct RemoveWatchesRequest *v);
int deserialize_RemoveWatchesRequest(struct iarchive *in, const char *tag, struct RemoveWatchesRequest*v);
void deallocate_RemoveWatchesRequest(struct RemoveWatchesRequest*);
struct GetEphemeralsRequest {
char * prefixPath;
};
int serialize_GetEphemeralsRequest(struct oarchive *out, const char *tag, struct GetEphemeralsRequest *v);
int deserialize_GetEphemeralsRequest(struct iarchive *in, const char *tag, struct GetEphemeralsRequest*v);
void deallocate_GetEphemeralsRequest(struct GetEphemeralsRequest*);
struct GetEphemeralsResponse {
struct String_vector ephemerals;
};
int serialize_GetEphemeralsResponse(struct oarchive *out, const char *tag, struct GetEphemeralsResponse *v);
int deserialize_GetEphemeralsResponse(struct iarchive *in, const char *tag, struct GetEphemeralsResponse*v);
void deallocate_GetEphemeralsResponse(struct GetEphemeralsResponse*);
struct LearnerInfo {
int64_t serverid;
int32_t protocolVersion;
int64_t configVersion;
};
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 QuorumAuthPacket {
int64_t magic;
int32_t status;
struct buffer token;
};
int serialize_QuorumAuthPacket(struct oarchive *out, const char *tag, struct QuorumAuthPacket *v);
int deserialize_QuorumAuthPacket(struct iarchive *in, const char *tag, struct QuorumAuthPacket*v);
void deallocate_QuorumAuthPacket(struct QuorumAuthPacket*);
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 TxnDigest {
int32_t version;
int64_t treeDigest;
};
int serialize_TxnDigest(struct oarchive *out, const char *tag, struct TxnDigest *v);
int deserialize_TxnDigest(struct iarchive *in, const char *tag, struct TxnDigest*v);
void deallocate_TxnDigest(struct TxnDigest*);
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 CreateTTLTxn {
char * path;
struct buffer data;
struct ACL_vector acl;
int32_t parentCVersion;
int64_t ttl;
};
int serialize_CreateTTLTxn(struct oarchive *out, const char *tag, struct CreateTTLTxn *v);
int deserialize_CreateTTLTxn(struct iarchive *in, const char *tag, struct CreateTTLTxn*v);
void deallocate_CreateTTLTxn(struct CreateTTLTxn*);
struct CreateContainerTxn {
char * path;
struct buffer data;
struct ACL_vector acl;
int32_t parentCVersion;
};
int serialize_CreateContainerTxn(struct oarchive *out, const char *tag, struct CreateContainerTxn *v);
int deserialize_CreateContainerTxn(struct iarchive *in, const char *tag, struct CreateContainerTxn*v);
void deallocate_CreateContainerTxn(struct CreateContainerTxn*);
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 CloseSessionTxn {
struct String_vector paths2Delete;
};
int serialize_CloseSessionTxn(struct oarchive *out, const char *tag, struct CloseSessionTxn *v);
int deserialize_CloseSessionTxn(struct iarchive *in, const char *tag, struct CloseSessionTxn*v);
void deallocate_CloseSessionTxn(struct CloseSessionTxn*);
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,54 @@
/**
* 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_CREATE2_OP 15
#define ZOO_RECONFIG_OP 16
#define ZOO_CHECK_WATCHES 17
#define ZOO_REMOVE_WATCHES 18
#define ZOO_CREATE_CONTAINER_OP 19
#define ZOO_DELETE_CONTAINER_OP 20
#define ZOO_CREATE_TTL_OP 21
#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,80 @@
/**
* 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>
#include <stdint.h> /* for int64_t */
#ifdef WIN32
#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

View File

@ -0,0 +1,674 @@
/**
* 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.
*/
/**
* DISCLAIMER
* This file is part of the mingw-w64 runtime package.
*
* The mingw-w64 runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef __GETOPT_H__
#pragma warning(disable:4996);
#define __GETOPT_H__
/* All the headers include this file. */
#include <crtdefs.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
#ifdef REPLACE_GETOPT
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
#undef optreset /* see getopt.h */
#define optreset __mingw_optreset
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#endif
//extern int optind; /* index of first non-option in argv */
//extern int optopt; /* single option character, as parsed */
//extern int opterr; /* flag to enable built-in diagnostics... */
// /* (user may set to zero, to suppress) */
//
//extern char *optarg; /* pointer to argument of current option */
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#ifndef __CYGWIN__
#define __progname __argv[0]
#else
extern char __declspec(dllimport) *__progname;
#endif
#ifdef __CYGWIN__
static char EMSG[] = "";
#else
#define EMSG ""
#endif
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
static void
_vwarnx(const char *fmt,va_list ap)
{
(void)fprintf(stderr,"%s: ",__progname);
if (fmt != NULL)
(void)vfprintf(stderr,fmt,ap);
(void)fprintf(stderr,"\n");
}
static void
warnx(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
_vwarnx(fmt,ap);
va_end(ap);
}
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif /* REPLACE_GETOPT */
//extern int getopt(int nargc, char * const *nargv, const char *options);
#ifdef _BSD_SOURCE
/*
* BSD adds the non-standard `optreset' feature, for reinitialisation
* of `getopt' parsing. We support this feature, for applications which
* proclaim their BSD heritage, before including this header; however,
* to maintain portability, developers are advised to avoid it.
*/
# define optreset __mingw_optreset
extern int optreset;
#endif
#ifdef __cplusplus
}
#endif
/*
* POSIX requires the `getopt' API to be specified in `unistd.h';
* thus, `unistd.h' includes this header. However, we do not want
* to expose the `getopt_long' or `getopt_long_only' APIs, when
* included in this manner. Thus, close the standard __GETOPT_H__
* declarations block, and open an additional __GETOPT_LONG_H__
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
* to declare the extended API.
*/
#endif /* !defined(__GETOPT_H__) */
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
#define __GETOPT_LONG_H__
#ifdef __cplusplus
extern "C" {
#endif
struct option /* specification for a long form option... */
{
const char *name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */
int val; /* its associated status value */
};
enum /* permitted values for its `has_arg' field... */
{
no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */
};
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
char *current_argv, *has_equal;
size_t current_argv_len;
int i, ambiguous, match;
#define IDENTICAL_INTERPRETATION(_x, _y) \
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
long_options[(_x)].flag == long_options[(_y)].flag && \
long_options[(_x)].val == long_options[(_y)].val)
current_argv = place;
match = -1;
ambiguous = 0;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
ambiguous = 0;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else if (!IDENTICAL_INTERPRETATION(i, match))
ambiguous = 1;
}
if (ambiguous) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
#undef IDENTICAL_INTERPRETATION
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
* optreset != 0 for GNU compatibility.
*/
if (posixly_correct == -1 || optreset != 0)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = (char*)strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
//extern int getopt_long(int nargc, char * const *nargv, const char *options,
// const struct option *long_options, int *idx);
//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
// const struct option *long_options, int *idx);
/*
* Previous MinGW implementation had...
*/
#ifndef HAVE_DECL_GETOPT
/*
* ...for the long form API only; keep this for compatibility.
*/
# define HAVE_DECL_GETOPT 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */

View File

@ -0,0 +1,15 @@
#ifndef WINCONFIG_H_
#define WINCONFIG_H_
/* 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
#define inline __inline
#endif
#define __attribute__(x)
#define __func__ __FUNCTION__
#define ACL ZKACL /* Conflict with windows API */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
/**
* 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 LOGCALLBACK(_zh) zoo_get_log_callback(_zh)
#define LOGSTREAM NULL
#define LOG_ERROR(_cb, ...) if(logLevel>=ZOO_LOG_LEVEL_ERROR) \
log_message(_cb, ZOO_LOG_LEVEL_ERROR, __LINE__, __func__, __VA_ARGS__)
#define LOG_WARN(_cb, ...) if(logLevel>=ZOO_LOG_LEVEL_WARN) \
log_message(_cb, ZOO_LOG_LEVEL_WARN, __LINE__, __func__, __VA_ARGS__)
#define LOG_INFO(_cb, ...) if(logLevel>=ZOO_LOG_LEVEL_INFO) \
log_message(_cb, ZOO_LOG_LEVEL_INFO, __LINE__, __func__, __VA_ARGS__)
#define LOG_DEBUG(_cb, ...) if(logLevel==ZOO_LOG_LEVEL_DEBUG) \
log_message(_cb, ZOO_LOG_LEVEL_DEBUG, __LINE__, __func__, __VA_ARGS__)
ZOOAPI void log_message(log_callback_fn callback, ZooLogLevel curLevel,
int line, const char* funcName, const char* format, ...);
FILE* zoo_get_log_stream();
#ifdef __cplusplus
}
#endif
#endif /*ZK_LOG_H_*/

View File

@ -0,0 +1,31 @@
/**
* 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_VERSION "3.6.0"
#ifdef __cplusplus
}
#endif
#endif /* ZOOKEEPER_VERSION_H_ */

View File

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
/**
* 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.
*/
-->
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper-client</artifactId>
<version>3.6.3</version>
<relativePath>..</relativePath>
</parent>
<artifactId>zookeeper-client-c</artifactId>
<packaging>jar</packaging>
<name>Apache ZooKeeper - Client - C</name>
<description>ZooKeeper c client</description>
<profiles>
<profile>
<id>c-test-coverage</id>
<properties>
<c-test-coverage-arg>--enable-gcov</c-test-coverage-arg>
</properties>
</profile>
<profile>
<id>no-c-test-coverage</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<c-test-coverage-arg> </c-test-coverage-arg>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>autoreconf</id>
<phase>process-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<workingDirectory>${project.basedir}</workingDirectory>
<executable>autoreconf</executable>
<environmentVariables>
<ACLOCAL>aclocal -I /usr/share/aclocal</ACLOCAL>
</environmentVariables>
<arguments>
<argument>-if</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>configure</id>
<phase>process-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<workingDirectory>${project.build.directory}/c</workingDirectory>
<executable>${project.basedir}/configure</executable>
<environmentVariables>
<base_dir>${project.basedir}/../..</base_dir>
<CALLER>ANT</CALLER>
</environmentVariables>
<arguments>
<argument>--with-openssl=${c-client-openssl}</argument>
<argument>--prefix=${project.build.directory}/c</argument>
<argument>${c-test-coverage-arg}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<mkdir dir="target/c" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>build-c-client</id>
<phase>compile</phase>
<configuration>
<tasks>
<exec dir="${basedir}/target/c" executable="make" failonerror="true">
<env key="LD_LIBRARY_PATH" value="${env.LD_LIBRARY_PATH};/usr/lib" />
<env key="PATH" path="${env.PATH};${basedir};" />
<env key="CALLER" value="ANT" />
<env key="CLOVER_HOME" value="${basedir}/../../zookeeper-server/target" />
<env key="base_dir" value="${basedir}/../.." />
<arg line="clean install" />
</exec>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>test-cppunit</id>
<phase>test</phase>
<configuration>
<!-- do not run cpp tests if tests are globally skipped -->
<skip>${skipTests}</skip>
<tasks>
<exec dir="${basedir}/target/c" executable="make" failonerror="true">
<env key="LD_LIBRARY_PATH" value="${env.LD_LIBRARY_PATH};/usr/lib" />
<env key="PATH" path="${env.PATH};${basedir};" />
<env key="CALLER" value="ANT" />
<env key="CLOVER_HOME" value="${basedir}/../../zookeeper-server/target" />
<env key="base_dir" value="${basedir}/../.." />
<arg line="check" />
</exec>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>replace-cclient-files-during-release</id>
<phase>none</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<replaceregexp file="include/zookeeper_version.h" match="project.*" replace="project(zookeeper VERSION ${project.version})" byline="true" />
<replace file="include/zookeeper_version.h" value="">
<replaceToken>-SNAPSHOT</replaceToken>
</replace>
<replaceregexp file="CMakeLists.txt" match="project.*" replace="project(zookeeper VERSION ${project.version})" byline="true" />
<replace file="CMakeLists.txt" value="">
<replaceToken>-SNAPSHOT</replaceToken>
</replace>
<replaceregexp file="configure.ac" match="AC_INIT.*" replace="AC_INIT([zookeeper C client],${project.version},[user@zookeeper.apache.org],[zookeeper])" byline="true" />
<replace file="configure.ac" value="">
<replaceToken>-SNAPSHOT</replaceToken>
</replace>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,271 @@
/**
* 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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#ifdef WIN32
#define random rand /* replace POSIX random with Windows rand */
#include <winsock2.h> /* must always be included before ws2tcpip.h */
#include <ws2tcpip.h> /* for sockaddr_storage */
#include "winport.h"
#endif
#include "addrvec.h"
#define ADDRVEC_DEFAULT_GROW_AMOUNT 16
void addrvec_init(addrvec_t *avec)
{
assert(avec);
avec->next = 0;
avec->count = 0;
avec->capacity = 0;
avec->data = NULL;
}
void addrvec_free(addrvec_t *avec)
{
if (avec == NULL)
{
return;
}
avec->next = 0;
avec->count = 0;
avec->capacity = 0;
if (avec->data) {
free(avec->data);
avec->data = NULL;
}
}
int addrvec_alloc(addrvec_t *avec)
{
addrvec_init(avec);
return addrvec_grow_default(avec);
}
int addrvec_alloc_capacity(addrvec_t* avec, uint32_t capacity)
{
addrvec_init(avec);
return addrvec_grow(avec, capacity);
}
int addrvec_grow(addrvec_t *avec, uint32_t grow_amount)
{
unsigned int old_capacity = 0;
struct sockaddr_storage *old_data = NULL;
assert(avec);
if (grow_amount == 0)
{
return 0;
}
// Save off old data and capacity in case there is a realloc failure
old_capacity = avec->capacity;
old_data = avec->data;
avec->capacity += grow_amount;
avec->data = realloc(avec->data, sizeof(*avec->data) * avec->capacity);
if (avec->data == NULL)
{
avec->capacity = old_capacity;
avec->data = old_data;
errno = ENOMEM;
return 1;
}
return 0;
}
int addrvec_grow_default(addrvec_t *avec)
{
return addrvec_grow(avec, ADDRVEC_DEFAULT_GROW_AMOUNT);
}
static int addrvec_grow_if_full(addrvec_t *avec)
{
assert(avec);
if (avec->count == avec->capacity)
{
int rc = addrvec_grow_default(avec);
if (rc != 0)
{
return rc;
}
}
return 0;
}
int addrvec_contains(const addrvec_t *avec, const struct sockaddr_storage *addr)
{
uint32_t i = 0;
if (!avec || !addr)
{
return 0;
}
for (i = 0; i < avec->count; i++)
{
if (avec->data[i].ss_family != addr->ss_family)
continue;
switch (addr->ss_family) {
case AF_INET:
if (memcmp(&((struct sockaddr_in*)&avec->data[i])->sin_addr,
&((struct sockaddr_in*)addr)->sin_addr,
sizeof(struct in_addr)) == 0)
return 1;
break;
#ifdef AF_INET6
case AF_INET6:
if (memcmp(&((struct sockaddr_in6*)&avec->data[i])->sin6_addr,
&((struct sockaddr_in6*)addr)->sin6_addr,
sizeof(struct in6_addr)) == 0)
return 1;
break;
#endif
default:
break;
}
}
return 0;
}
int addrvec_append(addrvec_t *avec, const struct sockaddr_storage *addr)
{
int rc = 0;
assert(avec);
assert(addr);
rc = addrvec_grow_if_full(avec);
if (rc != 0)
{
return rc;
}
// Copy addrinfo into address list
memcpy(avec->data + avec->count, addr, sizeof(*addr));
++avec->count;
return 0;
}
int addrvec_append_addrinfo(addrvec_t *avec, const struct addrinfo *addrinfo)
{
int rc = 0;
assert(avec);
assert(addrinfo);
rc = addrvec_grow_if_full(avec);
if (rc != 0)
{
return rc;
}
// Copy addrinfo into address list
memcpy(avec->data + avec->count, addrinfo->ai_addr, addrinfo->ai_addrlen);
++avec->count;
return 0;
}
void addrvec_shuffle(addrvec_t *avec)
{
int i = 0;
for (i = avec->count - 1; i > 0; --i) {
long int j = random()%(i+1);
if (i != j) {
struct sockaddr_storage t = avec->data[i];
avec->data[i] = avec->data[j];
avec->data[j] = t;
}
}
}
int addrvec_hasnext(const addrvec_t *avec)
{
return avec->count > 0 && (avec->next < avec->count);
}
int addrvec_atend(const addrvec_t *avec)
{
return avec->count > 0 && avec->next >= avec->count;
}
void addrvec_next(addrvec_t *avec, struct sockaddr_storage *next)
{
int index;
// If we're at the end of the list, then reset index to start
if (addrvec_atend(avec)) {
avec->next = 0;
}
if (!addrvec_hasnext(avec)) {
if (next) {
memset(next, 0, sizeof(*next));
}
return;
}
index = avec->next++;
if (next) {
*next = avec->data[index];
}
}
void addrvec_peek(addrvec_t *avec, struct sockaddr_storage *next)
{
int index = avec->next;
if (avec->count == 0) {
memset(next, 0, sizeof(*next));
return;
}
if (addrvec_atend(avec)) {
index = 0;
}
*next = avec->data[index];
}
int addrvec_eq(const addrvec_t *a1, const addrvec_t *a2)
{
uint32_t i = 0;
if (a1->count != a2->count)
{
return 0;
}
for (i = 0; i < a1->count; ++i)
{
if (!addrvec_contains(a2, &a1->data[i]))
return 0;
}
return 1;
}

View File

@ -0,0 +1,138 @@
/**
* 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 ADDRVEC_H_
#define ADDRVEC_H_
#ifndef WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#else
#include <WinSock2.h>
#include <stdint.h>
#endif
/**
* This structure represents a list of addresses. It stores the count of the
* number of elements that have been inserted via calls to addrvec_append and
* addrvec_append_addrinfo. It also has a capacity field for the number of
* addresses it has the ability to hold without needing to be enlarged.
*/
typedef struct _addrvec {
unsigned int next; // next index to use
unsigned int count; // number of addresses in this list
unsigned int capacity; // number of address this list can hold
struct sockaddr_storage *data; // list of addresses
} addrvec_t;
/**
* Initialize an addrvec by clearing out all its state.
*/
void addrvec_init(addrvec_t *avec);
/**
* Free any memory used internally by an addrvec
*/
void addrvec_free(addrvec_t *avec);
/**
* Allocate an addrvec with a default capacity (16)
*/
int addrvec_alloc(addrvec_t *avec);
/**
* Allocates an addrvec with a specified capacity
*/
int addrvec_alloc_capacity(addrvec_t *avec, uint32_t capacity);
/**
* Grow an addrvec by the specified amount. This will increase the capacity
* of the vector and not the contents.
*/
int addrvec_grow(addrvec_t *avec, uint32_t grow_amount);
/**
* Similar to addrvec_grow but uses a default growth amount of 16.
*/
int addrvec_grow_default(addrvec_t *avec);
/**
* Check if an addrvec contains the specificed sockaddr_storage value.
* \returns 1 if it contains the value and 0 otherwise.
*/
int addrvec_contains(const addrvec_t *avec, const struct sockaddr_storage *addr);
/**
* Append the given sockaddr_storage pointer into the addrvec. The contents of
* the given 'addr' are copied into the addrvec via memcpy.
*/
int addrvec_append(addrvec_t *avec, const struct sockaddr_storage *addr);
/**
* Append the given addrinfo pointer into the addrvec. The contents of the given
* 'addrinfo' are copied into the addrvec via memcpy.
*/
int addrvec_append_addrinfo(addrvec_t *avec, const struct addrinfo *addrinfo);
/**
* Shuffle the addrvec so that it's internal list of addresses are randomized.
* Uses random() and assumes it has been properly seeded.
*/
void addrvec_shuffle(addrvec_t *avec);
/**
* Determine if the addrvec has a next element (e.g. it's safe to call addrvec_next)
*
* \returns 1 if it has a next element and 0 otherwise
*/
int addrvec_hasnext(const addrvec_t *avec);
/**
* Determine if the addrvec is at the end or not. Specifically, this means a
* subsequent call to addrvec_next will loop around to the start again.
*/
int addrvec_atend(const addrvec_t *avec);
/**
* Get the next entry from the addrvec and update the associated index.
*
* If next is NULL, the index will still be updated.
*
* If the current index points at (or after) the last element in the vector then
* it will loop back around and start at the beginning of the list.
*/
void addrvec_next(addrvec_t *avec, struct sockaddr_storage *next);
/**
* Retrieves the next entry from the addrvec but doesn't update the index.
*/
void addrvec_peek(addrvec_t *avec, struct sockaddr_storage *next);
/**
* Compare two addrvecs for equality.
*
* \returns 1 if the contents of the two lists are identical and and 0 otherwise.
*/
int addrvec_eq(const addrvec_t *a1, const addrvec_t *a2);
#endif // ADDRVEC_H

File diff suppressed because it is too large Load Diff

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, hashvalue);
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,280 @@
/**
* 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 <zookeeper.h>
#include "zookeeper_log.h"
#include <errno.h>
#ifdef THREADED
#include <pthread.h>
#endif
#include <string.h>
#include <stdlib.h>
static zhandle_t *zh;
// *****************************************************************************
//
static pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t counterCond=PTHREAD_COND_INITIALIZER;
static pthread_mutex_t counterLock=PTHREAD_MUTEX_INITIALIZER;
static int counter;
void ensureConnected(){
pthread_mutex_lock(&lock);
while (zoo_state(zh)!=ZOO_CONNECTED_STATE) {
pthread_cond_wait(&cond,&lock);
}
pthread_mutex_unlock(&lock);
}
void incCounter(int delta){
pthread_mutex_lock(&counterLock);
counter+=delta;
pthread_cond_broadcast(&counterCond);
pthread_mutex_unlock(&counterLock);
}
void setCounter(int cnt){
pthread_mutex_lock(&counterLock);
counter=cnt;
pthread_cond_broadcast(&counterCond);
pthread_mutex_unlock(&counterLock);
}
void waitCounter(){
pthread_mutex_lock(&counterLock);
while (counter>0) {
pthread_cond_wait(&counterCond,&counterLock);
}
pthread_mutex_unlock(&counterLock);
}
void listener(zhandle_t *zzh, int type, int state, const char *path,void* ctx) {
if (type == ZOO_SESSION_EVENT) {
if (state == ZOO_CONNECTED_STATE || state == ZOO_READONLY_STATE) {
pthread_mutex_lock(&lock);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
}
setCounter(0);
}
}
void create_completion(int rc, const char *name, const void *data) {
incCounter(-1);
if(rc!=ZOK){
LOG_ERROR(LOGSTREAM, "Failed to create a node rc=%d",rc);
}
}
int doCreateNodes(const char* root, int count){
char nodeName[1024];
int i;
for(i=0; i<count;i++){
int rc = 0;
snprintf(nodeName, sizeof(nodeName),"%s/%d",root,i);
incCounter(1);
rc=zoo_acreate(zh, nodeName, "first", 5, &ZOO_OPEN_ACL_UNSAFE, 0,
create_completion, 0);
if(i%1000==0){
LOG_INFO(LOGSTREAM, "Created %s", nodeName);
}
if(rc!=ZOK) return rc;
}
return ZOK;
}
int createRoot(const char* root){
char realpath[1024];
return zoo_create(zh,root,"root",4,&ZOO_OPEN_ACL_UNSAFE,0,realpath,sizeof(realpath)-1);
}
void write_completion(int rc, const struct Stat *stat, const void *data) {
incCounter(-1);
if(rc!=ZOK){
LOG_ERROR(LOGSTREAM, "Failed to write a node rc=%d",rc);
}
}
int doWrites(const char* root, int count){
char nodeName[1024];
int i;
counter=0;
for(i=0; i<count;i++){
int rc = 0;
snprintf(nodeName, sizeof(nodeName),"%s/%d",root,i);
incCounter(1);
rc=zoo_aset(zh, nodeName, "second", 6,-1,write_completion, 0);
if(rc!=ZOK) return rc;
}
return ZOK;
}
void read_completion(int rc, const char *value, int value_len,
const struct Stat *stat, const void *data) {
incCounter(-1);
if(rc!=ZOK){
LOG_ERROR(LOGSTREAM, "Failed to read a node rc=%d",rc);
return;
}
if(memcmp(value,"second",6)!=0){
char buf[value_len+1];
memcpy(buf,value,value_len);buf[value_len]=0;
LOG_ERROR(LOGSTREAM, "Invalid read, expected [second], received [%s]\n",buf);
exit(1);
}
}
int doReads(const char* root, int count){
char nodeName[1024];
int i;
counter=0;
for(i=0; i<count;i++){
int rc = 0;
snprintf(nodeName, sizeof(nodeName),"%s/%d",root,i);
incCounter(1);
rc=zoo_aget(zh, nodeName,0,read_completion, 0);
if(rc!=ZOK) return rc;
}
return ZOK;
}
void delete_completion(int rc, const void *data) {
incCounter(-1);
}
int doDeletes(const char* root, int count){
char nodeName[1024];
int i;
counter=0;
for(i=0; i<count;i++){
int rc = 0;
snprintf(nodeName, sizeof(nodeName),"%s/%d",root,i);
incCounter(1);
rc=zoo_adelete(zh, nodeName,-1,delete_completion, 0);
if(rc!=ZOK) return rc;
}
return ZOK;
}
static int free_String_vector(struct String_vector *v) {
if (v->data) {
int32_t i;
for(i=0;i<v->count; i++) {
free(v->data[i]);
}
free(v->data);
v->data = 0;
}
return 0;
}
static int deletedCounter;
int recursiveDelete(const char* root){
struct String_vector children;
int i;
int rc=zoo_get_children(zh,root,0,&children);
if(rc!=ZNONODE){
if(rc!=ZOK){
LOG_ERROR(LOGSTREAM, "Failed to get children of %s, rc=%d",root,rc);
return rc;
}
for(i=0;i<children.count; i++){
int rc = 0;
char nodeName[2048];
snprintf(nodeName, sizeof(nodeName),"%s/%s",root,children.data[i]);
rc=recursiveDelete(nodeName);
if(rc!=ZOK){
free_String_vector(&children);
return rc;
}
}
free_String_vector(&children);
}
if(deletedCounter%1000==0)
LOG_INFO(LOGSTREAM, "Deleting %s",root);
rc=zoo_delete(zh,root,-1);
if(rc!=ZOK){
LOG_ERROR(LOGSTREAM, "Failed to delete znode %s, rc=%d",root,rc);
}else
deletedCounter++;
return rc;
}
void usage(char *argv[]){
fprintf(stderr, "USAGE:\t%s zookeeper_host_list path #children\nor", argv[0]);
fprintf(stderr, "\t%s zookeeper_host_list path clean\n", argv[0]);
exit(0);
}
int main(int argc, char **argv) {
int nodeCount;
int cleaning=0;
if (argc < 4) {
usage(argv);
}
if(strcmp("clean",argv[3])==0){
cleaning=1;
}
zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);
zoo_deterministic_conn_order(1); // enable deterministic order
zh = zookeeper_init(argv[1], listener, 10000, 0, 0, 0);
if (!zh)
return errno;
LOG_INFO(LOGSTREAM, "Checking server connection...");
ensureConnected();
if(cleaning==1){
int rc = 0;
deletedCounter=0;
rc=recursiveDelete(argv[2]);
if(rc==ZOK){
LOG_INFO(LOGSTREAM, "Successfully deleted a subtree starting at %s (%d nodes)",
argv[2],deletedCounter);
exit(0);
}
exit(1);
}
nodeCount=atoi(argv[3]);
createRoot(argv[2]);
while(1) {
ensureConnected();
LOG_INFO(LOGSTREAM, "Creating children for path %s",argv[2]);
doCreateNodes(argv[2],nodeCount);
waitCounter();
LOG_INFO(LOGSTREAM, "Starting the write cycle for path %s",argv[2]);
doWrites(argv[2],nodeCount);
waitCounter();
LOG_INFO(LOGSTREAM, "Starting the read cycle for path %s",argv[2]);
doReads(argv[2],nodeCount);
waitCounter();
LOG_INFO(LOGSTREAM, "Starting the delete cycle for path %s",argv[2]);
doDeletes(argv[2],nodeCount);
waitCounter();
}
zookeeper_close(zh);
return 0;
}

View File

@ -0,0 +1,571 @@
/**
* 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
#if !defined(DLL_EXPORT) && !defined(USE_STATIC_LIB)
# 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(zhandle_t* zh, SOCKET sock, char* message)
{
LOG_ERROR(LOGCALLBACK(zh), "%s. %d",message, WSAGetLastError());
closesocket (sock);
return -1;
}
//--create socket pair for interupting selects.
int create_socket_pair(zhandle_t* zh, 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(LOGCALLBACK(zh), "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(zh, lst,"Error trying to set socket option.");
}
if (bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr)) == SOCKET_ERROR){
return handle_error(zh, lst,"Error trying to bind socket.");
}
if (listen(lst,1) == SOCKET_ERROR){
return handle_error(zh, 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(zh, lst, "Error while connecting to socket.");
}
if ((fds[1]=accept(lst,0,0)) == INVALID_SOCKET){
closesocket(fds[0]);
return handle_error(zh, 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(LOGCALLBACK(zh), "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(LOGCALLBACK(zh), "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(zh, adaptor_threads->self_pipe) == -1){
LOG_ERROR(LOGCALLBACK(zh), "Can't make a socket.");
#else
if(pipe(adaptor_threads->self_pipe)==-1) {
LOG_ERROR(LOGCALLBACK(zh), "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);
pthread_mutex_init(&adaptor_threads->reconfig_lock,0);
pthread_mutex_init(&adaptor_threads->watchers_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(LOGCALLBACK(zh), "started IO thread");
fds[0].fd=adaptor_threads->self_pipe[0];
fds[0].events=POLLIN;
while(!zh->close_requested) {
zh->io_count++;
struct timeval tv;
int fd;
int interest;
int timeout;
int maxfd=1;
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;
struct adaptor_threads *adaptor_threads = zh->adaptor_priv;
api_prolog(zh);
notify_thread_ready(zh);
LOG_DEBUG(LOGCALLBACK(zh), "started IO thread");
while(!zh->close_requested) {
struct timeval tv;
SOCKET fd;
int interest;
int rc;
zookeeper_interest(zh, &fd, &interest, &tv);
// FD_ZERO is cheap on Win32, it just sets count of elements to zero.
// It needs to be done to ensure no stale entries.
FD_ZERO(&rfds);
FD_ZERO(&wfds);
if (fd != -1) {
if (interest&ZOOKEEPER_READ) {
FD_SET(fd, &rfds);
}
if (interest&ZOOKEEPER_WRITE) {
FD_SET(fd, &wfds);
}
}
// Always interested in self_pipe.
FD_SET(adaptor_threads->self_pipe[0], &rfds);
rc = select(/* unused */0, &rfds, &wfds, NULL, &tv);
if (rc > 0) {
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)){}
}
}
else if (rc < 0) {
LOG_ERROR(LOGCALLBACK(zh), ("select() failed %d [%d].", rc, WSAGetLastError()));
// Clear interest events for zookeeper_process if select() fails.
interest = 0;
}
#endif
// dispatch zookeeper events
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(LOGCALLBACK(zh), "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(LOGCALLBACK(zh), "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(LOGCALLBACK(zh), "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
return __sync_fetch_and_add(operand, incr);
#else
return InterlockedExchangeAdd(operand, incr);
#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 lock_reconfig(struct _zhandle *zh)
{
struct adaptor_threads *adaptor = zh->adaptor_priv;
if (adaptor) {
return pthread_mutex_lock(&adaptor->reconfig_lock);
} else {
return 0;
}
}
int unlock_reconfig(struct _zhandle *zh)
{
struct adaptor_threads *adaptor = zh->adaptor_priv;
if (adaptor) {
return pthread_mutex_unlock(&adaptor->reconfig_lock);
} else {
return 0;
}
}
int lock_watchers(struct _zhandle *zh)
{
struct adaptor_threads *adaptor = zh->adaptor_priv;
if (adaptor) {
return pthread_mutex_lock(&adaptor->watchers_lock);
} else {
return 0;
}
}
int unlock_watchers(struct _zhandle *zh)
{
struct adaptor_threads *adaptor = zh->adaptor_priv;
if (adaptor) {
return pthread_mutex_unlock(&adaptor->watchers_lock);
} else {
return 0;
}
}
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,372 @@
/**
* 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>
#else
#include <winsock2.h> /* for _htonl and _ntohl */
#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 = {
ia_start_record,
ia_end_record,
ia_start_vector,
ia_end_vector,
ia_deserialize_bool,
ia_deserialize_int,
ia_deserialize_long ,
ia_deserialize_buffer,
ia_deserialize_string};
static struct oarchive oa_default = {
oa_start_record,
oa_end_record,
oa_start_vector,
oa_end_vector,
oa_serialize_bool,
oa_serialize_int,
oa_serialize_long ,
oa_serialize_buffer,
oa_serialize_string};
struct iarchive *create_buffer_iarchive(char *buffer, int len)
{
struct iarchive *ia;
struct buff_struct *buff;
ia = malloc(sizeof(*ia));
if (!ia) return 0;
buff = malloc(sizeof(struct buff_struct));
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;
struct buff_struct *buff;
oa = malloc(sizeof(*oa));
if (!oa) return 0;
buff = malloc(sizeof(struct buff_struct));
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,115 @@
/**
* 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.
*/
#if !defined(DLL_EXPORT) && !defined(USE_STATIC_LIB)
# 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;
}
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 lock_reconfig(struct _zhandle *zh)
{
return 0;
}
int unlock_reconfig(struct _zhandle *zh)
{
return 0;
}
int lock_watchers(struct _zhandle *zh)
{
return 0;
}
int unlock_watchers(struct _zhandle *zh)
{
return 0;
}
int enter_critical(zhandle_t* zh)
{
return 0;
}
int leave_critical(zhandle_t* zh)
{
return 0;
}

View File

@ -0,0 +1,307 @@
/**
* 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.
*/
#ifdef WIN32
#include "winport.h"
#include <stdlib.h>
#include <stdint.h> /* for int64_t */
#include <winsock2.h> /* must always be included before ws2tcpip.h */
#include <ws2tcpip.h> /* for SOCKET */
int pthread_mutex_lock(pthread_mutex_t* _mutex ){
int rc = WaitForSingleObject( *_mutex, // handle to mutex
INFINITE); // no time-out interval
return ((rc == WAIT_OBJECT_0) ? 0: rc);
}
int pthread_mutex_unlock( pthread_mutex_t* _mutex ){
int rc = ReleaseMutex(*_mutex);
return ((rc != 0)? 0: GetLastError());
}
int pthread_mutex_init(pthread_mutex_t* _mutex, void* ignoredAttr){
//use CreateMutex as we are using the HANDLES in pthread_cond
*_mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
return ((*_mutex == NULL) ? GetLastError() : 0);
}
int pthread_mutex_destroy(pthread_mutex_t* _mutex)
{
int rc = CloseHandle(*_mutex);
return ((rc != 0)? 0: GetLastError());
}
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, unsigned (__stdcall* start_routine)(void* a), void *arg)
{
int _intThreadId;
(*thread).thread_handle = (HANDLE)_beginthreadex( NULL, 0, start_routine , arg, 0, (unsigned int*)&_intThreadId );
(*thread).thread_id = _intThreadId;
return (((*thread).thread_handle == 0 ) ? errno : 0 );
}
int pthread_equal(pthread_t t1, pthread_t t2){
//Is there a better way to do this? GetThreadId(handle) is only supported Windows 2003 n above.
return ((t1.thread_id == t2.thread_id) ? 1:0);
}
pthread_t pthread_self(){
pthread_t thread_self;
thread_self.thread_handle = GetCurrentThread();
thread_self.thread_id = GetCurrentThreadId();
return thread_self;
}
int pthread_join(pthread_t _thread, void** ignore)
{
int rc = WaitForSingleObject( _thread.thread_handle, INFINITE );
return ((rc == WAIT_OBJECT_0) ? 0: rc);
}
int pthread_detach(pthread_t _thread)
{
int rc = CloseHandle(_thread.thread_handle) ;
return (rc != 0) ? 0: GetLastError();
}
void pthread_mutexattr_init(pthread_mutexattr_t* ignore){}
void pthread_mutexattr_settype(pthread_mutexattr_t* ingore_attr, int ignore){}
void pthread_mutexattr_destroy(pthread_mutexattr_t* ignore_attr){}
int
pthread_cond_init (pthread_cond_t *cv,
const pthread_condattr_t * ignore)
{
cv->waiters_count_ = 0;
cv->was_broadcast_ = 0;
cv->sema_ = CreateSemaphore (NULL, // no security
0, // initially 0
0x7fffffff, // max count
NULL); // unnamed
if (cv->sema_ == NULL )
return GetLastError();
InitializeCriticalSection (&cv->waiters_count_lock_);
cv->waiters_done_ = CreateEvent (NULL, // no security
FALSE, // auto-reset
FALSE, // non-signaled initially
NULL); // unnamed
return (cv->waiters_done_ == NULL) ? GetLastError() : 0;
}
int pthread_cond_destroy(pthread_cond_t *cond)
{
CloseHandle( cond->sema_);
DeleteCriticalSection(&cond->waiters_count_lock_);
return (CloseHandle( cond->waiters_done_ ) == 0)? GetLastError(): 0 ;
}
int
pthread_cond_signal (pthread_cond_t *cv)
{
int have_waiters;
EnterCriticalSection (& (cv->waiters_count_lock_));
have_waiters = cv->waiters_count_ > 0;
LeaveCriticalSection (&cv->waiters_count_lock_);
// If there aren't any waiters, then this is a no-op.
if (have_waiters){
return (ReleaseSemaphore (cv->sema_, 1, 0) == 0 ) ? GetLastError() : 0 ;
}else
return 0;
}
int
pthread_cond_broadcast (pthread_cond_t *cv)
{
// This is needed to ensure that <waiters_count_> and <was_broadcast_> are
// consistent relative to each other.
int have_waiters = 0;
EnterCriticalSection (&cv->waiters_count_lock_);
if (cv->waiters_count_ > 0) {
// We are broadcasting, even if there is just one waiter...
// Record that we are broadcasting, which helps optimize
// <pthread_cond_wait> for the non-broadcast case.
cv->was_broadcast_ = 1;
have_waiters = 1;
}
if (have_waiters) {
// Wake up all the waiters atomically.
ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);
LeaveCriticalSection (&cv->waiters_count_lock_);
// Wait for all the awakened threads to acquire the counting
// semaphore.
WaitForSingleObject (cv->waiters_done_, INFINITE);
// This assignment is okay, even without the <waiters_count_lock_> held
// because no other waiter threads can wake up to access it.
cv->was_broadcast_ = 0;
}
else
LeaveCriticalSection (&cv->waiters_count_lock_);
}
int
pthread_cond_wait (pthread_cond_t *cv,
pthread_mutex_t *external_mutex)
{
int last_waiter;
// Avoid race conditions.
EnterCriticalSection (&cv->waiters_count_lock_);
cv->waiters_count_++;
LeaveCriticalSection (&cv->waiters_count_lock_);
// This call atomically releases the mutex and waits on the
// semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
// are called by another thread.
SignalObjectAndWait (*external_mutex, cv->sema_, INFINITE, FALSE);
// Reacquire lock to avoid race conditions.
EnterCriticalSection (&cv->waiters_count_lock_);
// We're no longer waiting...
cv->waiters_count_--;
// Check to see if we're the last waiter after <pthread_cond_broadcast>.
last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0;
LeaveCriticalSection (&cv->waiters_count_lock_);
// If we're the last waiter thread during this particular broadcast
// then let all the other threads proceed.
if (last_waiter)
// This call atomically signals the <waiters_done_> event and waits until
// it can acquire the <external_mutex>. This is required to ensure fairness.
SignalObjectAndWait (cv->waiters_done_, *external_mutex, INFINITE, FALSE);
else
// Always regain the external mutex since that's the guarantee we
// give to our callers.
WaitForSingleObject (*external_mutex, INFINITE);
}
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *) )
{
int result = 0;
pthread_key_t* newkey;
if ((newkey = (pthread_key_t*) calloc (1, sizeof (pthread_key_t))) == NULL)
{
result = ENOMEM;
}
else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES)
{
result = EAGAIN;
free (newkey);
newkey = NULL;
}
else if (destructor != NULL)
{
//--we have to store the function pointer for destructor, so that we can call it
//--to free up the user allocated storage--
newkey->destructor = destructor;
}
key = newkey;
return (result);
}
int pthread_key_delete(pthread_key_t key)
{
int rc = 0;
LPVOID lpvData = TlsGetValue(key.key);
rc = TlsFree (key.key);
rc = (rc != 0 ) ? 0 : GetLastError();
if (key.destructor != NULL && lpvData != 0){
key.destructor(lpvData); //we take control of calling destructor, instead of calling it on thread exit.
}
free (&key);
return (rc);
}
void *pthread_getspecific(pthread_key_t key)
{
LPVOID lpvData = TlsGetValue(key.key);
if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS))
return NULL;
else
return lpvData;
}
int pthread_setspecific(pthread_key_t key, const void *value)
{
int rc = TlsSetValue (key.key, value);
return ((rc != 0 ) ? 0 : GetLastError());
}
int gettimeofday(struct timeval *tp, void *tzp) {
int64_t now = 0;
if (tzp != 0) { errno = EINVAL; return -1; }
GetSystemTimeAsFileTime( (LPFILETIME)&now );
tp->tv_sec = (long)(now / 10000000 - 11644473600LL);
tp->tv_usec = (now / 10) % 1000000;
return 0;
}
int close(SOCKET fd) {
return closesocket(fd);
}
int Win32WSAStartup()
{
WORD wVersionRq;
WSADATA wsaData;
int err;
wVersionRq = MAKEWORD(2,0);
err = WSAStartup(wVersionRq, &wsaData);
if (err != 0)
return 1;
// confirm the version information
if ((LOBYTE(wsaData.wVersion) != 2) ||
(HIBYTE(wsaData.wVersion) != 0))
{
Win32WSACleanup();
return 1;
}
return 0;
}
void Win32WSACleanup()
{
WSACleanup();
}
double drand48(void)
{
return (double)(rand()) / RAND_MAX;
}
#endif //WIN32

View File

@ -0,0 +1,139 @@
/**
* 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.
*/
/**
* This header file is to port pthread lib , sockets and other utility methods on windows.
* Specifically the threads function, mutexes, keys, and socket initialization.
*/
#ifndef WINPORT_H_
#define WINPORT_H_
#ifdef WIN32
#include "winconfig.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h> /* must always be included before ws2tcpip.h */
#include <ws2tcpip.h> /* for struct sock_addr used in zookeeper.h */
/* POSIX names are deprecated, use ISO conformant names instead. */
#define strdup _strdup
#define getcwd _getcwd
#define getpid _getpid
/* Windows "secure" versions of POSIX reentrant functions */
#define strtok_r strtok_s
#define localtime_r(a,b) localtime_s(b,a)
/* After this version of MSVC, snprintf became a defined function,
and so cannot be redefined, nor can #ifndef be used to guard it. */
#if ((defined(_MSC_VER) && _MSC_VER < 1900) || !defined(_MSC_VER))
#define snprintf _snprintf
#endif
#include <errno.h>
#include <process.h>
#include <stdint.h> /* for int64_t */
#include <stdlib.h>
#include <malloc.h>
typedef int ssize_t;
typedef HANDLE pthread_mutex_t;
struct pthread_t_
{
HANDLE thread_handle;
DWORD thread_id;
};
typedef struct pthread_t_ pthread_t;
typedef int pthread_mutexattr_t;
typedef int pthread_condattr_t;
typedef int pthread_attr_t;
#define PTHREAD_MUTEX_RECURSIVE 0
int pthread_mutex_lock(pthread_mutex_t* _mutex );
int pthread_mutex_unlock( pthread_mutex_t* _mutex );
int pthread_mutex_init(pthread_mutex_t* _mutex, void* ignoredAttr);
int pthread_mutex_destroy(pthread_mutex_t* _mutex);
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, unsigned (__stdcall* start_routine)(void* a), void *arg);
int pthread_equal(pthread_t t1, pthread_t t2);
pthread_t pthread_self();
int pthread_join(pthread_t _thread, void** ignore);
int pthread_detach(pthread_t _thread);
void pthread_mutexattr_init(pthread_mutexattr_t* ignore);
void pthread_mutexattr_settype(pthread_mutexattr_t* ingore_attr, int ignore);
void pthread_mutexattr_destroy(pthread_mutexattr_t* ignore_attr);
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
typedef struct
{
int waiters_count_;
// Number of waiting threads.
CRITICAL_SECTION waiters_count_lock_;
// Serialize access to <waiters_count_>.
HANDLE sema_;
// Semaphore used to queue up threads waiting for the condition to
// become signaled.
HANDLE waiters_done_;
// An auto-reset event used by the broadcast/signal thread to wait
// for all the waiting thread(s) to wake up and be released from the
// semaphore.
size_t was_broadcast_;
// Keeps track of whether we were broadcasting or signaling. This
// allows us to optimize the code if we're just signaling.
}pthread_cond_t;
int pthread_cond_init (pthread_cond_t *cv,const pthread_condattr_t * ignore);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_signal (pthread_cond_t *cv);
int pthread_cond_broadcast (pthread_cond_t *cv);
int pthread_cond_wait (pthread_cond_t *cv, pthread_mutex_t *external_mutex);
struct pthread_key_t_
{
DWORD key;
void (*destructor) (void *);
};
typedef struct pthread_key_t_ pthread_key_t;
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *) );
int pthread_key_delete(pthread_key_t key);
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
int gettimeofday(struct timeval *tp, void *tzp);
int close(SOCKET fd);
int Win32WSAStartup();
void Win32WSACleanup();
double drand48(void);
#endif //WIN32
#endif //WINPORT_H_

View File

@ -0,0 +1,327 @@
/**
* 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"
#include "addrvec.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 READONLY_STATE_DEF 5
#define SSL_CONNECTING_STATE_DEF 7
#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 45
/* connect request */
struct connect_req {
int32_t protocolVersion;
int64_t lastZxidSeen;
int32_t timeOut;
int64_t sessionId;
int32_t passwd_len;
char passwd[16];
char readOnly;
};
/* 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];
char readOnly;
};
#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
pthread_mutex_t reconfig_lock; // lock for reconfiguring cluster's ensemble
pthread_mutex_t watchers_lock; // lock for watcher operations
#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 {
zsock_t *fd;
// Hostlist and list of addresses
char *hostname; // hostname contains list of zookeeper servers to connect to
struct sockaddr_storage addr_cur; // address of server we're currently connecting/connected to
struct sockaddr_storage addr_rw_server; // address of last known read/write server found.
addrvec_t addrs; // current list of addresses we're connected to
addrvec_t addrs_old; // old list of addresses that we are no longer connected to
addrvec_t addrs_new; // new list of addresses to connect to if we're reconfiguring
int reconfig; // Are we in the process of reconfiguring cluster's ensemble
double pOld, pNew; // Probability for selecting between 'addrs_old' and 'addrs_new'
int delay;
int disable_reconnection_attempt; // When set, client will not try reconnect to a different server in
// server list. This makes a sticky server for client, and is useful
// for testing if a sticky server is required, or if client wants to
// explicitly shuffle server by calling zoo_cycle_next_server.
// The default value is 0.
watcher_fn watcher; // the registered watcher
// Message timings
struct timeval last_recv; // time last message was received
struct timeval last_send; // time last message was sent
struct timeval last_ping; // time last PING was sent
struct timeval next_deadline; // time of the next deadline
int recv_timeout; // max receive timeout for messages from server
// Buffers
buffer_list_t *input_buffer; // current buffer being read in
buffer_head_t to_process; // buffers that have been read and ready to be processed
buffer_head_t to_send; // packets queued to send
completion_head_t sent_requests; // outstanding requests
completion_head_t completions_to_process; // completions that are ready to run
int outstanding_sync; // number of outstanding synchronous requests
/* read-only mode specific fields */
struct timeval last_ping_rw; /* The last time we checked server for being r/w */
int ping_rw_timeout; /* The time that can go by before checking next server */
// State info
volatile int state; // Current zookeeper state
void *context; // client-side provided context
clientid_t client_id; // client-id
long long last_zxid; // last zookeeper ID
auth_list_head_t auth_h; // authentication data list
log_callback_fn log_callback; // Callback for logging (falls back to logging to stderr)
int io_count; // counts the number of iterations of do_io
// Primer storage
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[41]; // the true size of primer_storage
/* 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;
// Watchers
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;
/** Indicates if this client is allowed to go to r/o mode */
char allow_read_only;
/** Indicates if we connected to a majority server before */
char seen_rw_server_before;
};
int adaptor_init(zhandle_t *zh);
void adaptor_finish(zhandle_t *zh);
void adaptor_destroy(zhandle_t *zh);
#if THREADED
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);
#endif
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);
// ensemble reconfigure access guards
int lock_reconfig(struct _zhandle *zh);
int unlock_reconfig(struct _zhandle *zh);
// watchers hashtable lock
int lock_watchers(struct _zhandle *zh);
int unlock_watchers(struct _zhandle *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,476 @@
/**
* 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));
}
}
}
/* If watcher is NULL, we return TRUE since we consider it a match */
static int containsWatcher(zk_hashtable *watchers, const char *path,
watcher_fn watcher, void *watcherCtx)
{
watcher_object_list_t *wl;
watcher_object_t e;
if (!watcher)
return 1;
wl = hashtable_search(watchers->ht, (void *)path);
if (!wl)
return 0;
e.watcher = watcher;
e.context = watcherCtx;
return search_watcher(&wl, &e) ? 1 : 0;
}
/**
* remove any watcher_object that has a matching (watcher, watcherCtx)
*/
static void removeWatcherFromList(watcher_object_list_t *wl, watcher_fn watcher,
void *watcherCtx)
{
watcher_object_t *e = NULL;
if (!wl || (wl && !wl->head))
return;
e = wl->head;
while (e){
if (e->next &&
e->next->watcher == watcher &&
e->next->context == watcherCtx) {
watcher_object_t *this = e->next;
e->next = e->next->next;
free(this);
break;
}
e = e->next;
}
if (wl->head &&
wl->head->watcher == watcher && wl->head->context == watcherCtx) {
watcher_object_t *this = wl->head;
wl->head = wl->head->next;
free(this);
}
}
static void removeWatcher(zk_hashtable *watchers, const char *path,
watcher_fn watcher, void *watcherCtx)
{
watcher_object_list_t *wl = hashtable_search(watchers->ht, (void *)path);
if (!wl)
return;
if (!watcher) {
wl = (watcher_object_list_t *) hashtable_remove(watchers->ht,
(void *)path);
destroy_watcher_object_list(wl);
return;
}
removeWatcherFromList(wl, watcher, watcherCtx);
if (!wl->head) {
wl = (watcher_object_list_t *) hashtable_remove(watchers->ht,
(void *)path);
destroy_watcher_object_list(wl);
}
}
void deactivateWatcher(zhandle_t *zh, watcher_deregistration_t *dereg, int rc)
{
if (rc != ZOK || !dereg)
return;
removeWatchers(zh, dereg->path, dereg->type, dereg->watcher,
dereg->context);
}
void removeWatchers(zhandle_t *zh, const char* path, ZooWatcherType type,
watcher_fn watcher, void *watcherCtx)
{
switch (type) {
case ZWATCHTYPE_CHILD:
removeWatcher(zh->active_child_watchers, path, watcher, watcherCtx);
break;
case ZWATCHTYPE_DATA:
removeWatcher(zh->active_node_watchers, path, watcher, watcherCtx);
removeWatcher(zh->active_exist_watchers, path, watcher, watcherCtx);
break;
case ZWATCHTYPE_ANY:
removeWatcher(zh->active_child_watchers, path, watcher, watcherCtx);
removeWatcher(zh->active_node_watchers, path, watcher, watcherCtx);
removeWatcher(zh->active_exist_watchers, path, watcher, watcherCtx);
break;
}
}
int pathHasWatcher(zhandle_t *zh, const char *path, int wtype,
watcher_fn watcher, void *watcherCtx)
{
int watcher_found = 0;
switch (wtype) {
case ZWATCHTYPE_CHILD:
watcher_found = containsWatcher(zh->active_child_watchers,
path, watcher, watcherCtx);
break;
case ZWATCHTYPE_DATA:
watcher_found = containsWatcher(zh->active_node_watchers, path,
watcher, watcherCtx);
if (!watcher_found) {
watcher_found = containsWatcher(zh->active_exist_watchers, path,
watcher, watcherCtx);
}
break;
case ZWATCHTYPE_ANY:
watcher_found = containsWatcher(zh->active_child_watchers, path,
watcher, watcherCtx);
if (!watcher_found) {
watcher_found = containsWatcher(zh->active_node_watchers, path,
watcher, watcherCtx);
}
if (!watcher_found) {
watcher_found = containsWatcher(zh->active_exist_watchers, path,
watcher, watcherCtx);
}
break;
}
return watcher_found;
}

View File

@ -0,0 +1,86 @@
/**
* 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;
/**
* A watcher deregistration gets temporarily stored with the completion entry until
* the server response comes back at which moment we can remove the watchers from
* the active watchers map.
*/
typedef struct _watcher_deregistration {
watcher_fn watcher;
void* context;
ZooWatcherType type;
const char* path;
} watcher_deregistration_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);
void deactivateWatcher(zhandle_t *zh, watcher_deregistration_t *dereg, 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);
void removeWatchers(zhandle_t *zh, const char* path, ZooWatcherType type,
watcher_fn watcher, void *watcherCtx);
int pathHasWatcher(zhandle_t *zh, const char *path, int wtype,
watcher_fn watcher, void *watcherCtx);
#ifdef __cplusplus
}
#endif
#endif /*ZK_HASHTABLE_H_*/

View File

@ -0,0 +1,203 @@
/**
* 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.
*/
#if !defined(DLL_EXPORT) && !defined(USE_STATIC_LIB)
# define USE_STATIC_LIB
#endif
#include "zookeeper_log.h"
#ifndef WIN32
#include <unistd.h>
#else
typedef DWORD pid_t;
#include <process.h> /* for getpid */
#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* zoo_get_log_stream(){
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(log_callback_fn callback, ZooLogLevel curLevel,
int line, const char* funcName, const char* format, ...)
{
static const char* dbgLevelStr[]={"ZOO_INVALID","ZOO_ERROR","ZOO_WARN",
"ZOO_INFO","ZOO_DEBUG"};
static pid_t pid=0;
va_list va;
int ofs = 0;
#ifdef THREADED
unsigned long int tid = 0;
#endif
#ifdef WIN32
char timebuf [TIME_NOW_BUF_SIZE];
const char* time = time_now(timebuf);
#else
const char* time = time_now(get_time_buffer());
#endif
char* buf = get_format_log_buffer();
if(!buf)
{
fprintf(stderr, "log_message: Unable to allocate memory buffer");
return;
}
if(pid==0)
{
pid=getpid();
}
#ifndef THREADED
// pid_t is long on Solaris
ofs = snprintf(buf, FORMAT_LOG_BUF_SIZE,
"%s:%ld:%s@%s@%d: ", time, (long)pid,
dbgLevelStr[curLevel], funcName, line);
#else
#ifdef WIN32
tid = (unsigned long int)(pthread_self().thread_id);
#else
tid = (unsigned long int)(pthread_self());
#endif
ofs = snprintf(buf, FORMAT_LOG_BUF_SIZE-1,
"%s:%ld(0x%lx):%s@%s@%d: ", time, (long)pid, tid,
dbgLevelStr[curLevel], funcName, line);
#endif
// Now grab the actual message out of the variadic arg list
va_start(va, format);
vsnprintf(buf+ofs, FORMAT_LOG_BUF_SIZE-1-ofs, format, va);
va_end(va);
if (callback)
{
callback(buf);
} else {
fprintf(zoo_get_log_stream(), "%s\n", buf);
fflush(zoo_get_log_stream());
}
}
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

View File

@ -0,0 +1,127 @@
#!/usr/bin/env bash
# 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.
#
# This script cleans up old transaction logs and snapshots
#
#
# If this scripted is run out of /usr/bin or some other system bin directory
# it should be linked to and not copied. Things like java jar files are found
# relative to the canonical path of this script.
#
# determining the domain name in the certificates:
# - use the first commandline argument, if present
# - if not, then use the fully qualified domain name
# - if `hostname` command fails, fall back to zookeeper.apache.org
FQDN=`hostname -f`
FQDN=${1:-$FQDN}
FQDN=${FQDN:-"zookeeper.apache.org"}
# Generate the root key
openssl genrsa -out rootkey.pem 2048
#Generate the root Cert
openssl req -x509 -new -key rootkey.pem -out root.crt -config <(
cat <<-EOF
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[ dn ]
C = US
ST = California
L = San Francisco
O = ZooKeeper
emailAddress = dev@$FQDN
CN = $FQDN
EOF
)
#Generate Client Key
openssl genrsa -out clientkey.pem 2048
#Generate Client Cert
openssl req -new -key clientkey.pem -out client.csr -config <(
cat <<-EOF
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[ dn ]
C = US
ST = California
L = San Francisco
O = ZooKeeper
emailAddress = dev@$FQDN
CN = $FQDN
EOF
)
openssl x509 -req -in client.csr -CA root.crt -CAkey rootkey.pem -CAcreateserial -days 3650 -out client.crt
#Export in pkcs12 format
openssl pkcs12 -export -in client.crt -inkey clientkey.pem -out client.pkcs12 -password pass:password
# Import Keystore in JKS
keytool -importkeystore -srckeystore client.pkcs12 -destkeystore client.jks -srcstoretype pkcs12 -srcstorepass password -deststorepass password
############################################################
#Generate Server key
openssl genrsa -out serverkey.pem 2048
#Generate Server Cert
openssl req -new -key serverkey.pem -out server.csr -config <(
cat <<-EOF
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[ dn ]
C = US
ST = California
L = San Francisco
O = ZooKeeper
emailAddress = dev@$FQDN
CN = $FQDN
EOF
)
openssl x509 -req -in server.csr -CA root.crt -CAkey rootkey.pem -CAcreateserial -days 3650 -out server.crt
#Export in pkcs12 format
openssl pkcs12 -export -in server.crt -inkey serverkey.pem -out server.pkcs12 -password pass:password
# Import Keystore in JKS
keytool -importkeystore -srckeystore server.pkcs12 -destkeystore server.jks -srcstoretype pkcs12 -srcstorepass password -deststorepass password
keytool -importcert -keystore server.jks -file root.crt -storepass password -noprompt
keytool -importcert -alias ca -file root.crt -keystore clienttrust.jks -storepass password -noprompt
keytool -importcert -alias clientcert -file client.crt -keystore clienttrust.jks -storepass password -noprompt
keytool -importcert -alias ca -file root.crt -keystore servertrust.jks -storepass password -noprompt
keytool -importcert -alias servercert -file server.crt -keystore servertrust.jks -storepass password -noprompt

View File

@ -0,0 +1,195 @@
/**
* 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 _COLLECTION_UTIL_H_
#define _COLLECTION_UTIL_H_
/**
* \file
* CollectionBuilder and DictionaryBuilder classes and collection utility functions
*/
namespace Util
{
// *********************************************************
/** A shortcut to use for building collections.
* This class is a wrapper around standard STL collection containers such as vector.
* It allows one to conveniently build collections at the variable initialization time:
* \code
* #include "CollectionUtil.h"
* #include "Vector.h" // for ostream << operator overload for STL vector
* using Util;
*
* int main()
* {
* typedef vector<string> MyVector;
* MyVector myVector=CollectionBuilder<MyVector>()("str1")("str2")("str3");
* cout<<myVector;
* // the following output will be produced:
* // [str1,str2,str3]
* }
* \endcode
*/
template <class CONT>
class CollectionBuilder
{
public:
/// Type of the collection container.
typedef CONT CollectionType;
/// Container's value type.
typedef typename CollectionType::value_type value_type;
/// Container's constant iterator type.
typedef typename CollectionType::const_iterator const_iterator;
/// Container's size type.
typedef typename CollectionType::size_type size_type;
/** Operator function call overload to allow call chaining.
* \param value the value to be inserted into the container
*/
CollectionBuilder<CONT>& operator()(const value_type& value){
return push_back(value);
}
/** Same as regular STL push_back() but allows call chaining.
* \param value the value to be inserted into the container
*/
CollectionBuilder<CONT>& push_back(const value_type& value){
collection_.push_back(value);
return *this;
}
/// \name Standard STL container interface
/// @{
const_iterator begin() const{return collection_.begin();}
const_iterator end() const{return collection_.end();}
size_type size() const{return collection_.size();}
void clear() {collection_.clear();}
///@}
/// Explicit typecast operator.
operator const CollectionType&() const {return collection_;}
private:
/// \cond PRIVATE
CollectionType collection_;
/// \endcond
};
// *********************************************************
/** A shortcut to use for building dictionaries.
* This class is a wrapper around standard STL associative containers such as map.
* It allows one to conveniently build dictionaries at the variable initialization time:
* \code
* #include "CollectionUtil.h"
* #include "Map.h" // for ostream << operator overload for STL map
* using Util;
*
* int main()
* {
* typedef map<string,int> MyMap;
* MyMap myMap=DictionaryBuilder<MyMap>()("str1",1)("str2",2)("str3",3);
* cout<<myMap;
* // the following output will be produced:
* // [str1=1,str2=2,str3=3]
* }
* \endcode
*/
template <class CONT>
class DictionaryBuilder
{
public:
/// The type of the associative container
typedef CONT DictionaryType;
/// Container's element type (usually a pair<key_type,mapped_type>)
typedef typename DictionaryType::value_type value_type;
/// Container's key type
typedef typename DictionaryType::key_type key_type;
/// Container's value type
typedef typename DictionaryType::mapped_type mapped_type;
/// Container's constant iterator type
typedef typename DictionaryType::const_iterator const_iterator;
/// Container's writable iterator type
typedef typename DictionaryType::iterator iterator;
/// Container's size type
typedef typename DictionaryType::size_type size_type;
/** Operator function call overload to allow call chaining.
* \param key the value key to be inserted
* \param value the value to be inserted into the container
* \return a non-const reference to self
*/
DictionaryBuilder<CONT>& operator()(const key_type& key,const mapped_type& value){
dict_.insert(value_type(key,value));
return *this;
}
/** Lookup value by key.
* \param key the key associated with the value.
* \return a non-const iterator pointing to the element whose key matched the \a key parameter
*/
iterator find(const key_type& key){
return dict_.find(key);
}
/** Lookup value by key.
* \param key the key associated with the value.
* \return a const iterator pointing to the element whose key matched the \a key parameter
*/
const_iterator find(const key_type& key) const{
return dict_.find(key);
}
/// \name Standard STL container interface
/// @{
const_iterator begin() const{return dict_.begin();}
const_iterator end() const{return dict_.end();}
size_type size() const{return dict_.size();}
void clear() {dict_.clear();}
///@}
/// Explicit typecast operator.
operator const DictionaryType&() const {return dict_;}
private:
DictionaryType dict_;
};
// ***********************************************************
/** Deletes all dynamically allocated elements of a collection.
* C::value_type is expected to be a pointer to a dynamically allocated object, or it won't compile.
* The function will iterate over all container elements and call delete for each of them.
* \param c a collection (vector,set) whose elements are being deleted.
*/
template <class C>
void clearCollection(C& c){
for(typename C::const_iterator it=c.begin();it!=c.end();++it)
delete *it;
c.clear();
}
/** Deletes all dynamically allocated values of the assotiative container.
* The function expects the M::value_type to be a pair<..., ptr_to_type>, or it won't compile.
* It first deletes the objects pointed to by ptr_to_type
* and then clears (calls m.clear()) the container.
* \param m an associative container (map,hash_map) whose elements are being deleted.
*/
template <class M>
void clearMap(M& m){
for(typename M::const_iterator it=m.begin();it!=m.end();++it)
delete it->second;
m.clear();
}
} // namespace Util
#endif // _COLLECTION_UTIL_H_

View File

@ -0,0 +1,37 @@
/**
* 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 CPPASSERTHELPER_H_
#define CPPASSERTHELPER_H_
#include <cppunit/TestAssert.h>
// make it possible to specify location of the ASSERT call
#define CPPUNIT_ASSERT_EQUAL_LOC(expected,actual,file,line) \
( CPPUNIT_NS::assertEquals( (expected), \
(actual), \
CPPUNIT_NS::SourceLine(file,line), \
"" ) )
#define CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC(message,expected,actual,file,line) \
( CPPUNIT_NS::assertEquals( (expected), \
(actual), \
CPPUNIT_NS::SourceLine(file,line), \
(message) ) )
#endif /*CPPASSERTHELPER_H_*/

View File

@ -0,0 +1,352 @@
/**
* 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 <cstdlib>
#include <cstdarg>
#include <iostream>
#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK
#include <stdarg.h>
#include "Util.h"
#include "LibCMocks.h"
#undef USING_DUMA
using namespace std;
// *****************************************************************************
// gethostbyname
struct hostent* gethostbyname(const char *name) {
if(!Mock_gethostbyname::mock_)
return LIBC_SYMBOLS.gethostbyname(name);
return Mock_gethostbyname::mock_->call(name);
}
Mock_gethostbyname* Mock_gethostbyname::mock_=0;
Mock_gethostbyname::~Mock_gethostbyname(){
mock_=0;
for(unsigned int i=0;i<gethostbynameReturns.size();i++)
delete gethostbynameReturns[i];
}
Mock_gethostbyname::HostEntry& Mock_gethostbyname::addHostEntry(
const char* hostName, short addrtype) {
gethostbynameReturns.push_back(new HostEntry(hostName, addrtype));
return *gethostbynameReturns.back();
}
hostent* Mock_gethostbyname::call(const char* name) {
assert("Must add one or more mock hostent entries first"&&
(gethostbynameReturns.size()!=0));
return gethostbynameReturns[current++ % gethostbynameReturns.size()];
}
static char** appendString(char **list,const char* str,int len=0){
const int SIZE_INCREMENT=16;
if(list==0)
list=(char**)LIBC_SYMBOLS.calloc(SIZE_INCREMENT,sizeof(char*));
// find the first available slot
int count=0;
for(char** ptr=list; *ptr!=0; ptr++,count++);
if(((count+1)%SIZE_INCREMENT)==0){
list=(char**)LIBC_SYMBOLS.realloc(list,(count+1+SIZE_INCREMENT)*sizeof(char*));
memset(list+count+1,0,SIZE_INCREMENT*sizeof(char*));
}
if(len==0){
len=strlen(str)+1;
}
char* ptr=(char*)malloc(len);
memcpy(ptr,str,len);
list[count]=ptr;
return list;
}
static void freeList(char **list){
if(list==0) return;
for(char** ptr=list; *ptr!=0; ptr++)
LIBC_SYMBOLS.free((void*)*ptr);
LIBC_SYMBOLS.free((void*)list);
}
Mock_gethostbyname::HostEntry::HostEntry(const char* hostName, short addrtype) {
h_name=strdup(hostName);
h_addrtype=addrtype;
if(addrtype==AF_INET)
h_length=4;
else{
#ifdef AF_INET6
h_length=6; // TODO: not really sure, verify!
#else
assert("AF_INET6 not supported yet"&&false);
#endif
}
h_aliases=h_addr_list=0;
}
Mock_gethostbyname::HostEntry::~HostEntry(){
if(h_name) LIBC_SYMBOLS.free((void*)h_name);
freeList(h_aliases); h_aliases=0;
freeList(h_addr_list); h_addr_list=0;
}
Mock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAlias(
const char* alias) {
h_aliases=appendString(h_aliases,alias);
return *this;
}
Mock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAddress(
const char* addr4) {
h_addr_list=appendString(h_addr_list,addr4,4);
return *this;
}
// *****************************************************************************
// calloc
#ifndef USING_DUMA
DECLARE_WRAPPER(void*,calloc,(size_t p1, size_t p2)){
if(!Mock_calloc::mock_)
return CALL_REAL(calloc,(p1,p2));
return Mock_calloc::mock_->call(p1,p2);
}
#endif
void* Mock_calloc::call(size_t p1, size_t p2){
#ifndef USING_DUMA
if(counter++ ==callsBeforeFailure){
counter=0;
errno=errnoOnFailure;
return 0;
}
return CALL_REAL(calloc,(p1,p2));
#else
return 0;
#endif
}
Mock_calloc* Mock_calloc::mock_=0;
// *****************************************************************************
// realloc
#ifndef USING_DUMA
DECLARE_WRAPPER(void*,realloc,(void* p, size_t s)){
if(!Mock_realloc::mock_)
return LIBC_SYMBOLS.realloc(p,s);
return Mock_realloc::mock_->call(p,s);
}
#endif
Mock_realloc* Mock_realloc::mock_=0;
void* Mock_realloc::call(void* p, size_t s){
if(counter++ ==callsBeforeFailure){
counter=0;
errno=errnoOnFailure;
return 0;
}
return LIBC_SYMBOLS.realloc(p,s);
}
// *****************************************************************************
// random
RANDOM_RET_TYPE random(){
if(!Mock_random::mock_)
return LIBC_SYMBOLS.random();
return Mock_random::mock_->call();
}
void srandom(unsigned long seed){
if (!Mock_random::mock_)
LIBC_SYMBOLS.srandom(seed);
else
Mock_random::mock_->setSeed(seed);
}
Mock_random* Mock_random::mock_=0;
int Mock_random::call(){
assert("Must specify one or more random integers"&&(randomReturns.size()!=0));
return randomReturns[currentIdx++ % randomReturns.size()];
}
// *****************************************************************************
// free
#ifndef USING_DUMA
DECLARE_WRAPPER(void,free,(void* p)){
if(Mock_free_noop::mock_ && !Mock_free_noop::mock_->nested)
Mock_free_noop::mock_->call(p);
else
CALL_REAL(free,(p));
}
#endif
void Mock_free_noop::call(void* p){
// on cygwin libc++ is linked statically
// push_back() may call free(), hence the nesting guards
synchronized(mx);
nested++;
callCounter++;
requested.push_back(p);
nested--;
}
void Mock_free_noop::freeRequested(){
#ifndef USING_DUMA
synchronized(mx);
for(unsigned i=0; i<requested.size();i++)
CALL_REAL(free,(requested[i]));
#endif
}
int Mock_free_noop::getFreeCount(void* p){
int cnt=0;
synchronized(mx);
for(unsigned i=0;i<requested.size();i++)
if(requested[i]==p)cnt++;
return cnt;
}
bool Mock_free_noop::isFreed(void* p){
synchronized(mx);
for(unsigned i=0;i<requested.size();i++)
if(requested[i]==p)return true;
return false;
}
Mock_free_noop* Mock_free_noop::mock_=0;
// *****************************************************************************
// socket
int socket(int domain, int type, int protocol){
if (!Mock_socket::mock_)
return LIBC_SYMBOLS.socket(domain,type,protocol);
return Mock_socket::mock_->callSocket(domain,type,protocol);
}
int close(int fd){
if (!Mock_socket::mock_)
return LIBC_SYMBOLS.close(fd);
return Mock_socket::mock_->callClose(fd);
}
int getsockopt(int s,int level,int optname,void *optval,socklen_t *optlen){
if (!Mock_socket::mock_)
return LIBC_SYMBOLS.getsockopt(s,level,optname,optval,optlen);
return Mock_socket::mock_->callGet(s,level,optname,optval,optlen);
}
int setsockopt(int s,int level,int optname,const void *optval,socklen_t optlen){
if (!Mock_socket::mock_)
return LIBC_SYMBOLS.setsockopt(s,level,optname,optval,optlen);
return Mock_socket::mock_->callSet(s,level,optname,optval,optlen);
}
int connect(int s,const struct sockaddr *addr,socklen_t len){
#ifdef AF_UNIX
/* don't mock UNIX domain sockets */
if (!Mock_socket::mock_ || addr->sa_family == AF_UNIX)
#else
if (!Mock_socket::mock_)
#endif
return LIBC_SYMBOLS.connect(s,addr,len);
return Mock_socket::mock_->callConnect(s,addr,len);
}
ssize_t send(int s,const void *buf,size_t len,int flags){
if (!Mock_socket::mock_)
return LIBC_SYMBOLS.send(s,buf,len,flags);
return Mock_socket::mock_->callSend(s,buf,len,flags);
}
ssize_t recv(int s,void *buf,size_t len,int flags){
if (!Mock_socket::mock_)
return LIBC_SYMBOLS.recv(s,buf,len,flags);
return Mock_socket::mock_->callRecv(s,buf,len,flags);
}
Mock_socket* Mock_socket::mock_=0;
// *****************************************************************************
// fcntl
extern "C" int fcntl(int fd,int cmd,...){
va_list va;
va_start(va,cmd);
void* arg = va_arg(va, void *);
va_end (va);
if (!Mock_fcntl::mock_)
return LIBC_SYMBOLS.fcntl(fd,cmd,arg);
return Mock_fcntl::mock_->call(fd,cmd,arg);
}
Mock_fcntl* Mock_fcntl::mock_=0;
// *****************************************************************************
// select
int select(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *timeout){
if (!Mock_select::mock_)
return LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,timeout);
return Mock_select::mock_->call(nfds,rfds,wfds,efds,timeout);
}
Mock_select* Mock_select::mock_=0;
// *****************************************************************************
// poll
Mock_poll* Mock_poll::mock_=0;
int poll(struct pollfd *fds, POLL_NFDS_TYPE nfds, int timeout){
if (!Mock_poll::mock_)
return LIBC_SYMBOLS.poll(fds,nfds,timeout);
return Mock_poll::mock_->call(fds,nfds,timeout);
}
/*
* Recent gcc with -O2 and glibc FORTIFY feature may cause our poll
* mock to be ignored.
*/
#if __USE_FORTIFY_LEVEL > 0
int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
__SIZE_TYPE__ __fdslen) {
return poll(__fds, __nfds, __timeout);
}
#endif
// *****************************************************************************
// gettimeofday
int gettimeofday(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){
if (!Mock_gettimeofday::mock_)
return LIBC_SYMBOLS.gettimeofday(tp,tzp);
return Mock_gettimeofday::mock_->call(tp,tzp);
}
Mock_gettimeofday* Mock_gettimeofday::mock_=0;
// *****************************************************************************
#ifdef _POSIX_MONOTONIC_CLOCK
// clock_gettime
int clock_gettime(clockid_t id, struct timespec *tp) {
if (!Mock_gettimeofday::mock_)
return LIBC_SYMBOLS.clock_gettime(id,tp);
struct timeval tv = { 0 };
int res = Mock_gettimeofday::mock_->call(&tv, NULL);
tp->tv_sec = tv.tv_sec;
tp->tv_nsec = tv.tv_usec * 1000;
return res;
}
#endif

View File

@ -0,0 +1,408 @@
/**
* 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 LIBCMOCKS_H_
#define LIBCMOCKS_H_
#include <string>
#include <vector>
#include <deque>
#include <errno.h>
#include <string.h>
#include "MocksBase.h"
#include "LibCSymTable.h"
#include "ThreadingUtil.h"
// *****************************************************************************
// gethostbyname
class Mock_gethostbyname: public Mock
{
public:
struct HostEntry: public hostent {
HostEntry(const char* hostName,short addrtype);
~HostEntry();
HostEntry& addAlias(const char* alias);
HostEntry& addAddress(const char* addr4);
};
Mock_gethostbyname():current(0){mock_=this;}
virtual ~Mock_gethostbyname();
HostEntry& addHostEntry(const char* hostName,short addrtype=AF_INET);
virtual hostent* call(const char* name);
typedef std::vector<HostEntry*> HostEntryCollection;
HostEntryCollection gethostbynameReturns;
int current;
static Mock_gethostbyname* mock_;
};
class MockFailed_gethostbyname: public Mock_gethostbyname
{
public:
MockFailed_gethostbyname():h_errnoReturn(HOST_NOT_FOUND) {}
int h_errnoReturn;
virtual hostent* call(const char* name) {
h_errno=h_errnoReturn;
return 0;
}
};
// *****************************************************************************
// calloc
class Mock_calloc: public Mock
{
public:
Mock_calloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) {
mock_=this;
}
virtual ~Mock_calloc() {mock_=0;}
int errnoOnFailure;
int callsBeforeFailure;
int counter;
virtual void* call(size_t p1, size_t p2);
static Mock_calloc* mock_;
};
// *****************************************************************************
// realloc
class Mock_realloc: public Mock
{
public:
Mock_realloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) {
mock_=this;
}
virtual ~Mock_realloc() {mock_=0;}
int errnoOnFailure;
int callsBeforeFailure;
int counter;
virtual void* call(void* p, size_t s);
static Mock_realloc* mock_;
};
// *****************************************************************************
// random
class Mock_random: public Mock
{
public:
Mock_random():currentIdx(0) {mock_=this;}
virtual ~Mock_random() {mock_=0;}
int currentIdx;
std::vector<int> randomReturns;
virtual int call();
void setSeed(unsigned long){currentIdx=0;}
static Mock_random* mock_;
};
// *****************************************************************************
// no-op free; keeps track of all deallocation requests
class Mock_free_noop: public Mock
{
Mutex mx;
std::vector<void*> requested;
public:
Mock_free_noop():nested(0),callCounter(0){mock_=this;}
virtual ~Mock_free_noop(){
mock_=0;
freeRequested();
}
int nested;
int callCounter;
virtual void call(void* p);
void freeRequested();
void disable(){mock_=0;}
// returns number of times the pointer was freed
int getFreeCount(void*);
bool isFreed(void*);
static Mock_free_noop* mock_;
};
// *****************************************************************************
// socket and related system calls
class Mock_socket: public Mock
{
public:
static const int FD=63;
Mock_socket():socketReturns(FD),closeReturns(0),getsocketoptReturns(0),
optvalSO_ERROR(0),
setsockoptReturns(0),connectReturns(0),connectErrno(0),
sendErrno(0),recvErrno(0)
{
mock_=this;
}
virtual ~Mock_socket(){mock_=0;}
int socketReturns;
virtual int callSocket(int domain, int type, int protocol){
return socketReturns;
}
int closeReturns;
virtual int callClose(int fd){
return closeReturns;
}
int getsocketoptReturns;
int optvalSO_ERROR;
virtual int callGet(int s,int level,int optname,void *optval,socklen_t *len){
if(level==SOL_SOCKET && optname==SO_ERROR){
setSO_ERROR(optval,*len);
}
return getsocketoptReturns;
}
virtual void setSO_ERROR(void *optval,socklen_t len){
memcpy(optval,&optvalSO_ERROR,len);
}
int setsockoptReturns;
virtual int callSet(int s,int level,int optname,const void *optval,socklen_t len){
return setsockoptReturns;
}
int connectReturns;
int connectErrno;
virtual int callConnect(int s,const struct sockaddr *addr,socklen_t len){
errno=connectErrno;
return connectReturns;
}
virtual void notifyBufferSent(const std::string& buffer){}
int sendErrno;
std::string sendBuffer;
virtual ssize_t callSend(int s,const void *buf,size_t len,int flags){
if(sendErrno!=0){
errno=sendErrno;
return -1;
}
// first call to send() is always the length of the buffer to follow
bool sendingLength=sendBuffer.size()==0;
// overwrite the length bytes
sendBuffer.assign((const char*)buf,len);
if(!sendingLength){
notifyBufferSent(sendBuffer);
sendBuffer.erase();
}
return len;
}
int recvErrno;
std::string recvReturnBuffer;
virtual ssize_t callRecv(int s,void *buf,size_t len,int flags){
if(recvErrno!=0){
errno=recvErrno;
return -1;
}
int k=std::min(len,recvReturnBuffer.length());
if(k==0)
return 0;
memcpy(buf,recvReturnBuffer.data(),k);
recvReturnBuffer.erase(0,k);
return k;
}
virtual bool hasMoreRecv() const{
return recvReturnBuffer.size()!=0;
}
static Mock_socket* mock_;
};
// *****************************************************************************
// fcntl
class Mock_fcntl: public Mock
{
public:
Mock_fcntl():callReturns(0),trapFD(-1){mock_=this;}
~Mock_fcntl(){mock_=0;}
int callReturns;
int trapFD;
virtual int call(int fd, int cmd, void* arg){
if(trapFD==-1)
return LIBC_SYMBOLS.fcntl(fd,cmd,arg);
return callReturns;
}
static Mock_fcntl* mock_;
};
// *****************************************************************************
// select
class Mock_select: public Mock
{
public:
Mock_select(Mock_socket* s,int fd):sock(s),
callReturns(0),myFD(fd),timeout(50)
{
mock_=this;
}
~Mock_select(){mock_=0;}
Mock_socket* sock;
int callReturns;
int myFD;
int timeout; //in millis
virtual int call(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *tv){
bool isWritableRequested=(wfds && FD_ISSET(myFD,wfds));
if(rfds) FD_CLR(myFD,rfds);
if(wfds) FD_CLR(myFD,wfds);
// this timeout is only to prevent a tight loop
timeval myTimeout={0,0};
if(!isWritableRequested && !isFDReadable()){
myTimeout.tv_sec=timeout/1000;
myTimeout.tv_usec=(timeout%1000)*1000;
}
LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,&myTimeout);
// myFD is always writable
if(isWritableRequested) FD_SET(myFD,wfds);
// myFD is only readable if the socket has anything to read
if(isFDReadable() && rfds) FD_SET(myFD,rfds);
return callReturns;
}
virtual bool isFDReadable() const {
return sock->hasMoreRecv();
}
static Mock_select* mock_;
};
// *****************************************************************************
// poll
// the last element of the pollfd array is expected to be test FD
class Mock_poll: public Mock
{
public:
Mock_poll(Mock_socket* s,int fd):sock(s),
callReturns(1),myFD(fd),timeout(50)
{
mock_=this;
}
~Mock_poll(){mock_=0;}
Mock_socket* sock;
int callReturns;
int myFD;
int timeout; //in millis
virtual int call(struct pollfd *fds, POLL_NFDS_TYPE nfds, int to) {
pollfd* myPoll=0;
if(fds[nfds-1].fd==myFD)
myPoll=&fds[nfds-1];
bool isWritableRequested=false;
if(myPoll!=0){
isWritableRequested=myPoll->events&POLLOUT;
nfds--;
}
LIBC_SYMBOLS.poll(fds,nfds,(!isWritableRequested&&!isFDReadable())?timeout:0);
if(myPoll!=0){
// myFD is always writable if requested
myPoll->revents=isWritableRequested?POLLOUT:0;
// myFD is only readable if the socket has anything to read
myPoll->revents|=isFDReadable()?POLLIN:0;
}
return callReturns;
}
virtual bool isFDReadable() const {
return sock->hasMoreRecv();
}
static Mock_poll* mock_;
};
// *****************************************************************************
// gettimeofday
class Mock_gettimeofday: public Mock
{
public:
Mock_gettimeofday(){
LIBC_SYMBOLS.gettimeofday(&tv,0);
mock_=this;
}
Mock_gettimeofday(const Mock_gettimeofday& other):tv(other.tv){}
Mock_gettimeofday(int32_t sec,int32_t usec){
tv.tv_sec=sec;
tv.tv_usec=usec;
}
~Mock_gettimeofday(){mock_=0;}
timeval tv;
virtual int call(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){
*tp=tv;
return 0;
}
operator timeval() const{
return tv;
}
// advance secs
virtual void tick(int howmuch=1){tv.tv_sec+=howmuch;}
// advance milliseconds
// can move the clock forward as well as backward by providing a negative
// number
virtual void millitick(int howmuch=1){
int ms=tv.tv_usec/1000+howmuch;
tv.tv_sec+=ms/1000;
// going backward?
if(ms<0){
ms=1000-(-ms%1000); //wrap millis around
}
tv.tv_usec=(ms%1000)*1000;
}
virtual void tick(const timeval& howmuch){
// add milliseconds (discarding microsecond portion)
long ms=tv.tv_usec/1000+howmuch.tv_usec/1000;
tv.tv_sec+=howmuch.tv_sec+ms/1000;
tv.tv_usec=(ms%1000)*1000;
}
static Mock_gettimeofday* mock_;
};
// discard microseconds!
inline bool operator==(const timeval& lhs, const timeval& rhs){
return rhs.tv_sec==lhs.tv_sec && rhs.tv_usec/1000==lhs.tv_usec/1000;
}
// simplistic implementation: no normalization, assume lhs >= rhs,
// discarding microseconds
inline timeval operator-(const timeval& lhs, const timeval& rhs){
timeval res;
res.tv_sec=lhs.tv_sec-rhs.tv_sec;
res.tv_usec=(lhs.tv_usec/1000-rhs.tv_usec/1000)*1000;
if(res.tv_usec<0){
res.tv_sec--;
res.tv_usec=1000000+res.tv_usec%1000000; // wrap the millis around
}
return res;
}
inline int32_t toMilliseconds(const timeval& tv){
return tv.tv_sec*1000+tv.tv_usec/1000;
}
#endif /*LIBCMOCKS_H_*/

View File

@ -0,0 +1,87 @@
/**
* 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 "LibCSymTable.h"
#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK
#define LOAD_SYM(sym) \
sym=(sym##_sig)dlsym(handle,#sym); \
assert("Unable to load "#sym" from libc"&&sym)
LibCSymTable& LibCSymTable::instance(){
static LibCSymTable tbl;
return tbl;
}
//******************************************************************************
// preload original libc symbols
LibCSymTable::LibCSymTable()
{
void* handle=getHandle();
LOAD_SYM(gethostbyname);
LOAD_SYM(calloc);
LOAD_SYM(realloc);
LOAD_SYM(free);
LOAD_SYM(random);
LOAD_SYM(srandom);
LOAD_SYM(printf);
LOAD_SYM(socket);
LOAD_SYM(close);
LOAD_SYM(getsockopt);
LOAD_SYM(setsockopt);
LOAD_SYM(fcntl);
LOAD_SYM(connect);
LOAD_SYM(send);
LOAD_SYM(recv);
LOAD_SYM(select);
LOAD_SYM(poll);
LOAD_SYM(gettimeofday);
#ifdef _POSIX_MONOTONIC_CLOCK
LOAD_SYM(clock_gettime);
#endif
#ifdef THREADED
LOAD_SYM(pthread_create);
LOAD_SYM(pthread_detach);
LOAD_SYM(pthread_cond_broadcast);
LOAD_SYM(pthread_cond_destroy);
LOAD_SYM(pthread_cond_init);
LOAD_SYM(pthread_cond_signal);
LOAD_SYM(pthread_cond_timedwait);
LOAD_SYM(pthread_cond_wait);
LOAD_SYM(pthread_join);
LOAD_SYM(pthread_mutex_destroy);
LOAD_SYM(pthread_mutex_init);
LOAD_SYM(pthread_mutex_lock);
LOAD_SYM(pthread_mutex_trylock);
LOAD_SYM(pthread_mutex_unlock);
#endif
}
void* LibCSymTable::getHandle(){
static void* handle=0;
if(!handle){
#ifdef __CYGWIN__
handle=dlopen("cygwin1.dll",RTLD_LAZY);
assert("Unable to dlopen global sym table"&&handle);
#else
handle=RTLD_NEXT;
#endif
}
return handle;
}

View File

@ -0,0 +1,111 @@
/**
* 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 LIBCSYMTABLE_H_
#define LIBCSYMTABLE_H_
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stddef.h>
#include <dlfcn.h>
#include <cassert>
#include <poll.h>
#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK
#ifdef THREADED
#include <pthread.h>
#endif
#include "config.h"
// TODO: move all these macros to config.h (generated by autoconf)
#ifdef __CYGWIN__
#if (CYGWIN_VERSION_DLL_MAJOR < 1007)
#define RANDOM_RET_TYPE int
#else
#define RANDOM_RET_TYPE long int
#endif
#define GETTIMEOFDAY_ARG2_TYPE void*
#else
#define RANDOM_RET_TYPE long int
#define GETTIMEOFDAY_ARG2_TYPE struct timezone*
#endif
#define DECLARE_SYM(ret,sym,sig) \
typedef ret (*sym##_sig)sig; \
static sym##_sig preload_##sym () { \
static sym##_sig ptr=0;\
if(!ptr){ void* h=getHandle(); ptr=(sym##_sig)dlsym(h,#sym); } \
assert("Unable to load "#sym" from libc"&&ptr); \
return ptr; \
} \
sym##_sig sym
#define LIBC_SYMBOLS LibCSymTable::instance()
//******************************************************************************
// preload original libc symbols
struct LibCSymTable
{
DECLARE_SYM(hostent*,gethostbyname,(const char*));
DECLARE_SYM(void*,calloc,(size_t, size_t));
DECLARE_SYM(void*,realloc,(void*, size_t));
DECLARE_SYM(void,free,(void*));
DECLARE_SYM(RANDOM_RET_TYPE,random,(void));
DECLARE_SYM(void,srandom,(unsigned long));
DECLARE_SYM(int,printf,(const char*, ...));
DECLARE_SYM(int,socket,(int,int,int));
DECLARE_SYM(int,close,(int));
DECLARE_SYM(int,getsockopt,(int,int,int,void*,socklen_t*));
DECLARE_SYM(int,setsockopt,(int,int,int,const void*,socklen_t));
DECLARE_SYM(int,fcntl,(int,int,...));
DECLARE_SYM(int,connect,(int,const struct sockaddr*,socklen_t));
DECLARE_SYM(ssize_t,send,(int,const void*,size_t,int));
DECLARE_SYM(ssize_t,recv,(int,const void*,size_t,int));
DECLARE_SYM(int,select,(int,fd_set*,fd_set*,fd_set*,struct timeval*));
DECLARE_SYM(int,poll,(struct pollfd*,POLL_NFDS_TYPE,int));
DECLARE_SYM(int,gettimeofday,(struct timeval*,GETTIMEOFDAY_ARG2_TYPE));
#ifdef _POSIX_MONOTONIC_CLOCK
DECLARE_SYM(int,clock_gettime,(clockid_t clk_id, struct timespec*));
#endif
#ifdef THREADED
DECLARE_SYM(int,pthread_create,(pthread_t *, const pthread_attr_t *,
void *(*)(void *), void *));
DECLARE_SYM(int,pthread_detach,(pthread_t));
DECLARE_SYM(int,pthread_cond_broadcast,(pthread_cond_t *));
DECLARE_SYM(int,pthread_cond_destroy,(pthread_cond_t *));
DECLARE_SYM(int,pthread_cond_init,(pthread_cond_t *, const pthread_condattr_t *));
DECLARE_SYM(int,pthread_cond_signal,(pthread_cond_t *));
DECLARE_SYM(int,pthread_cond_timedwait,(pthread_cond_t *,
pthread_mutex_t *, const struct timespec *));
DECLARE_SYM(int,pthread_cond_wait,(pthread_cond_t *, pthread_mutex_t *));
DECLARE_SYM(int,pthread_join,(pthread_t, void **));
DECLARE_SYM(int,pthread_mutex_destroy,(pthread_mutex_t *));
DECLARE_SYM(int,pthread_mutex_init,(pthread_mutex_t *, const pthread_mutexattr_t *));
DECLARE_SYM(int,pthread_mutex_lock,(pthread_mutex_t *));
DECLARE_SYM(int,pthread_mutex_trylock,(pthread_mutex_t *));
DECLARE_SYM(int,pthread_mutex_unlock,(pthread_mutex_t *));
#endif
LibCSymTable();
static void* getHandle();
static LibCSymTable& instance();
};
#endif /*LIBCSYMTABLE_H_*/

View File

@ -0,0 +1,36 @@
/**
* 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 <cstdlib>
#include <new>
#include "MocksBase.h"
#include "LibCSymTable.h"
// *****************************************************************************
// Mock base
void* Mock::operator new(std::size_t s){
void* p=malloc(s);
if(!p)
throw std::bad_alloc();
return p;
}
void Mock::operator delete(void* p){
LIBC_SYMBOLS.free(p);
}

View File

@ -0,0 +1,36 @@
/**
* 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 MOCKSBASE_H_
#define MOCKSBASE_H_
#include <cstddef>
// *****************************************************************************
// Mock base
class Mock
{
public:
virtual ~Mock(){}
static void* operator new(std::size_t s);
static void operator delete(void* p);
};
#endif /*MOCKSBASE_H_*/

View File

@ -0,0 +1,106 @@
/**
* 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 "PthreadMocks.h"
MockPthreadsBase* MockPthreadsBase::mock_=0;
#undef USING_DUMA
#ifndef USING_DUMA
int pthread_cond_broadcast (pthread_cond_t *c){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_cond_broadcast(c);
return MockPthreadsBase::mock_->pthread_cond_broadcast(c);
}
int pthread_cond_destroy (pthread_cond_t *c){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_cond_destroy(c);
return MockPthreadsBase::mock_->pthread_cond_destroy(c);
}
int pthread_cond_init (pthread_cond_t *c, const pthread_condattr_t *a){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_cond_init(c,a);
return MockPthreadsBase::mock_->pthread_cond_init(c,a);
}
int pthread_cond_signal (pthread_cond_t *c){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_cond_signal(c);
return MockPthreadsBase::mock_->pthread_cond_signal(c);
}
int pthread_cond_timedwait (pthread_cond_t *c,
pthread_mutex_t *m, const struct timespec *t){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);
return MockPthreadsBase::mock_->pthread_cond_timedwait(c,m,t);
}
int pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *m){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_cond_wait(c,m);
return MockPthreadsBase::mock_->pthread_cond_wait(c,m);
}
int pthread_create (pthread_t *t, const pthread_attr_t *a,
void *(*f)(void *), void *d){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_create(t,a,f,d);
return MockPthreadsBase::mock_->pthread_create(t,a,f,d);
}
int pthread_detach(pthread_t t){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_detach(t);
return MockPthreadsBase::mock_->pthread_detach(t);
}
int pthread_join (pthread_t t, void **r){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_join(t,r);
return MockPthreadsBase::mock_->pthread_join(t,r);
}
int pthread_mutex_destroy (pthread_mutex_t *m){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_mutex_destroy(m);
return MockPthreadsBase::mock_->pthread_mutex_destroy(m);
}
int pthread_mutex_init (pthread_mutex_t *m, const pthread_mutexattr_t *a){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_mutex_init(m,a);
return MockPthreadsBase::mock_->pthread_mutex_init(m,a);
}
DECLARE_WRAPPER(int,pthread_mutex_lock,(pthread_mutex_t *m)){
if(!MockPthreadsBase::mock_)
return CALL_REAL(pthread_mutex_lock,(m));
return MockPthreadsBase::mock_->pthread_mutex_lock(m);
}
int pthread_mutex_trylock (pthread_mutex_t *m){
if(!MockPthreadsBase::mock_)
return LIBC_SYMBOLS.pthread_mutex_trylock(m);
return MockPthreadsBase::mock_->pthread_mutex_trylock(m);
}
DECLARE_WRAPPER(int,pthread_mutex_unlock,(pthread_mutex_t *m)){
if(!MockPthreadsBase::mock_)
return CALL_REAL(pthread_mutex_unlock,(m));
return MockPthreadsBase::mock_->pthread_mutex_unlock(m);
}
#endif
CheckedPthread::ThreadMap CheckedPthread::tmap_;
CheckedPthread::MutexMap CheckedPthread::mmap_;
CheckedPthread::CVMap CheckedPthread::cvmap_;
Mutex CheckedPthread::mx;

View File

@ -0,0 +1,449 @@
/**
* 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 PTHREADMOCKS_H_
#define PTHREADMOCKS_H_
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include "src/zk_adaptor.h"
#include "Util.h"
#include "MocksBase.h"
#include "LibCSymTable.h"
#include "ThreadingUtil.h"
// an ABC for pthreads
class MockPthreadsBase: public Mock
{
public:
MockPthreadsBase(){mock_=this;}
virtual ~MockPthreadsBase(){mock_=0;}
virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
void *(*f)(void *), void *d) =0;
virtual int pthread_join(pthread_t t, void ** r) =0;
virtual int pthread_detach(pthread_t t) =0;
virtual int pthread_cond_broadcast(pthread_cond_t *c) =0;
virtual int pthread_cond_destroy(pthread_cond_t *c) =0;
virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a) =0;
virtual int pthread_cond_signal(pthread_cond_t *c) =0;
virtual int pthread_cond_timedwait(pthread_cond_t *c,
pthread_mutex_t *m, const struct timespec *t) =0;
virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) =0;
virtual int pthread_mutex_destroy(pthread_mutex_t *m) =0;
virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a) =0;
virtual int pthread_mutex_lock(pthread_mutex_t *m) =0;
virtual int pthread_mutex_trylock(pthread_mutex_t *m) =0;
virtual int pthread_mutex_unlock(pthread_mutex_t *m) =0;
static MockPthreadsBase* mock_;
};
// all pthread functions simply return an error code
// and increment their invocation counter. No actual threads are spawned.
class MockPthreadsNull: public MockPthreadsBase
{
public:
MockPthreadsNull():
pthread_createReturns(0),pthread_createCounter(0),
pthread_joinReturns(0),pthread_joinCounter(0),pthread_joinResultReturn(0),
pthread_detachReturns(0),pthread_detachCounter(0),
pthread_cond_broadcastReturns(0),pthread_cond_broadcastCounter(0),
pthread_cond_destroyReturns(0),pthread_cond_destroyCounter(0),
pthread_cond_initReturns(0),pthread_cond_initCounter(0),
pthread_cond_signalReturns(0),pthread_cond_signalCounter(0),
pthread_cond_timedwaitReturns(0),pthread_cond_timedwaitCounter(0),
pthread_cond_waitReturns(0),pthread_cond_waitCounter(0),
pthread_mutex_destroyReturns(0),pthread_mutex_destroyCounter(0),
pthread_mutex_initReturns(0),pthread_mutex_initCounter(0),
pthread_mutex_lockReturns(0),pthread_mutex_lockCounter(0),
pthread_mutex_trylockReturns(0),pthread_mutex_trylockCounter(0),
pthread_mutex_unlockReturns(0),pthread_mutex_unlockCounter(0)
{
memset(threads,0,sizeof(threads));
}
short threads[512];
int pthread_createReturns;
int pthread_createCounter;
virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
void *(*f)(void *), void *d){
char* p=(char*)&threads[pthread_createCounter++];
p[0]='i'; // mark as created
*t=(pthread_t)p;
return pthread_createReturns;
}
int pthread_joinReturns;
int pthread_joinCounter;
void* pthread_joinResultReturn;
virtual int pthread_join(pthread_t t, void ** r){
pthread_joinCounter++;
if(r!=0)
*r=pthread_joinResultReturn;
char* p=(char*)t;
p[0]='x';p[1]+=1;
return pthread_joinReturns;
}
int pthread_detachReturns;
int pthread_detachCounter;
virtual int pthread_detach(pthread_t t){
pthread_detachCounter++;
char* p=(char*)t;
p[0]='x';p[1]+=1;
return pthread_detachReturns;
}
template<class T>
static bool isInitialized(const T& t){
return ((char*)t)[0]=='i';
}
template<class T>
static bool isDestroyed(const T& t){
return ((char*)t)[0]=='x';
}
template<class T>
static int getDestroyCounter(const T& t){
return ((char*)t)[1];
}
template<class T>
static int getInvalidAccessCounter(const T& t){
return ((char*)t)[2];
}
int pthread_cond_broadcastReturns;
int pthread_cond_broadcastCounter;
virtual int pthread_cond_broadcast(pthread_cond_t *c){
pthread_cond_broadcastCounter++;
if(isDestroyed(c))((char*)c)[2]++;
return pthread_cond_broadcastReturns;
}
int pthread_cond_destroyReturns;
int pthread_cond_destroyCounter;
virtual int pthread_cond_destroy(pthread_cond_t *c){
pthread_cond_destroyCounter++;
char* p=(char*)c;
p[0]='x';p[1]+=1;
return pthread_cond_destroyReturns;
}
int pthread_cond_initReturns;
int pthread_cond_initCounter;
virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
pthread_cond_initCounter++;
char* p=(char*)c;
p[0]='i'; // mark as created
p[1]=0; // destruction counter
p[2]=0; // access after destruction counter
return pthread_cond_initReturns;
}
int pthread_cond_signalReturns;
int pthread_cond_signalCounter;
virtual int pthread_cond_signal(pthread_cond_t *c){
pthread_cond_signalCounter++;
if(isDestroyed(c))((char*)c)[2]++;
return pthread_cond_signalReturns;
}
int pthread_cond_timedwaitReturns;
int pthread_cond_timedwaitCounter;
virtual int pthread_cond_timedwait(pthread_cond_t *c,
pthread_mutex_t *m, const struct timespec *t){
pthread_cond_timedwaitCounter++;
if(isDestroyed(c))((char*)c)[2]++;
return pthread_cond_timedwaitReturns;
}
int pthread_cond_waitReturns;
int pthread_cond_waitCounter;
virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
pthread_cond_waitCounter++;
if(isDestroyed(c))((char*)c)[2]++;
return pthread_cond_waitReturns;
}
int pthread_mutex_destroyReturns;
int pthread_mutex_destroyCounter;
virtual int pthread_mutex_destroy(pthread_mutex_t *m){
pthread_mutex_destroyCounter++;
char* p=(char*)m;
p[0]='x';p[1]+=1;
return pthread_mutex_destroyReturns;
}
int pthread_mutex_initReturns;
int pthread_mutex_initCounter;
virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
pthread_mutex_initCounter++;
char* p=(char*)m;
p[0]='i'; // mark as created
p[1]=0; // destruction counter
p[2]=0; // access after destruction counter
return pthread_mutex_initReturns;
}
int pthread_mutex_lockReturns;
int pthread_mutex_lockCounter;
virtual int pthread_mutex_lock(pthread_mutex_t *m){
pthread_mutex_lockCounter++;
if(isDestroyed(m))((char*)m)[2]++;
return pthread_mutex_lockReturns;
}
int pthread_mutex_trylockReturns;
int pthread_mutex_trylockCounter;
virtual int pthread_mutex_trylock(pthread_mutex_t *m){
pthread_mutex_trylockCounter++;
if(isDestroyed(m))((char*)m)[2]++;
return pthread_mutex_trylockReturns;
}
int pthread_mutex_unlockReturns;
int pthread_mutex_unlockCounter;
virtual int pthread_mutex_unlock(pthread_mutex_t *m){
pthread_mutex_unlockCounter++;
if(isDestroyed(m))((char*)m)[2]++;
return pthread_mutex_unlockReturns;
}
};
// simulates the way zookeeper threads make use of api_prolog/epilog and
//
class MockPthreadZKNull: public MockPthreadsNull
{
typedef std::map<pthread_t,zhandle_t*> Map;
Map map_;
public:
virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
void *(*f)(void *), void *d){
int ret=MockPthreadsNull::pthread_create(t,a,f,d);
zhandle_t* zh=(zhandle_t*)d;
adaptor_threads* ad=(adaptor_threads*)zh->adaptor_priv;
api_prolog(zh);
ad->threadsToWait--;
putValue(map_,*t,zh);
return ret;
}
virtual int pthread_join(pthread_t t, void ** r){
zhandle_t* zh=0;
if(getValue(map_,t,zh))
api_epilog(zh,0);
return MockPthreadsNull::pthread_join(t,r);
}
};
struct ThreadInfo{
typedef enum {RUNNING,TERMINATED} ThreadState;
ThreadInfo():
destructionCounter_(0),invalidAccessCounter_(0),state_(RUNNING)
{
}
ThreadInfo& incDestroyed() {
destructionCounter_++;
return *this;
}
ThreadInfo& incInvalidAccess(){
invalidAccessCounter_++;
return *this;
}
ThreadInfo& setTerminated(){
state_=TERMINATED;
return *this;
}
int destructionCounter_;
int invalidAccessCounter_;
ThreadState state_;
};
class CheckedPthread: public MockPthreadsBase
{
// first => destruction counter
// second => invalid access counter
//typedef std::pair<int,int> Entry;
typedef ThreadInfo Entry;
typedef std::map<pthread_t,Entry> ThreadMap;
static ThreadMap tmap_;
static ThreadMap& getMap(const TypeOp<pthread_t>::BareT&){return tmap_;}
typedef std::map<pthread_mutex_t*,Entry> MutexMap;
static MutexMap mmap_;
static MutexMap& getMap(const TypeOp<pthread_mutex_t>::BareT&){return mmap_;}
typedef std::map<pthread_cond_t*,Entry> CVMap;
static CVMap cvmap_;
static CVMap& getMap(const TypeOp<pthread_cond_t>::BareT&){return cvmap_;}
static Mutex mx;
template<class T>
static void markDestroyed(T& t){
typedef typename TypeOp<T>::BareT Type;
Entry e;
synchronized(mx);
if(getValue(getMap(Type()),t,e)){
putValue(getMap(Type()),t,Entry(e).incDestroyed());
}else{
putValue(getMap(Type()),t,Entry().incDestroyed());
}
}
template<class T>
static void markCreated(T& t){
typedef typename TypeOp<T>::BareT Type;
Entry e;
synchronized(mx);
if(!getValue(getMap(Type()),t,e))
putValue(getMap(Type()),t,Entry());
}
template<class T>
static void checkAccessed(T& t){
typedef typename TypeOp<T>::BareT Type;
Entry e;
synchronized(mx);
if(getValue(getMap(Type()),t,e) && e.destructionCounter_>0)
putValue(getMap(Type()),t,Entry(e).incInvalidAccess());
}
static void setTerminated(pthread_t t){
Entry e;
synchronized(mx);
if(getValue(tmap_,t,e))
putValue(tmap_,t,Entry(e).setTerminated());
}
public:
bool verbose;
CheckedPthread():verbose(false){
tmap_.clear();
mmap_.clear();
cvmap_.clear();
mx.release();
}
template <class T>
static bool isInitialized(const T& t){
typedef typename TypeOp<T>::BareT Type;
Entry e;
synchronized(mx);
return getValue(getMap(Type()),t,e) && e.destructionCounter_==0;
}
template <class T>
static bool isDestroyed(const T& t){
typedef typename TypeOp<T>::BareT Type;
Entry e;
synchronized(mx);
return getValue(getMap(Type()),t,e) && e.destructionCounter_>0;
}
static bool isTerminated(pthread_t t){
Entry e;
synchronized(mx);
return getValue(tmap_,t,e) && e.state_==ThreadInfo::TERMINATED;
}
template <class T>
static int getDestroyCounter(const T& t){
typedef typename TypeOp<T>::BareT Type;
Entry e;
synchronized(mx);
return getValue(getMap(Type()),t,e)?e.destructionCounter_:-1;
}
template<class T>
static int getInvalidAccessCounter(const T& t){
typedef typename TypeOp<T>::BareT Type;
Entry e;
synchronized(mx);
return getValue(getMap(Type()),t,e)?e.invalidAccessCounter_:-1;
}
struct ThreadContext{
typedef void *(*ThreadFunc)(void *);
ThreadContext(ThreadFunc func,void* param):func_(func),param_(param){}
ThreadFunc func_;
void* param_;
};
static void* threadFuncWrapper(void* v){
ThreadContext* ctx=(ThreadContext*)v;
pthread_t t=pthread_self();
markCreated(t);
void* res=ctx->func_(ctx->param_);
setTerminated(pthread_self());
delete ctx;
return res;
}
virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
void *(*f)(void *), void *d)
{
int ret=LIBC_SYMBOLS.pthread_create(t,a,threadFuncWrapper,
new ThreadContext(f,d));
if(verbose)
TEST_TRACE("thread created %p",*t);
return ret;
}
virtual int pthread_join(pthread_t t, void ** r){
if(verbose) TEST_TRACE("thread joined %p",t);
int ret=LIBC_SYMBOLS.pthread_join(t,r);
if(ret==0)
markDestroyed(t);
return ret;
}
virtual int pthread_detach(pthread_t t){
if(verbose) TEST_TRACE("thread detached %p",t);
int ret=LIBC_SYMBOLS.pthread_detach(t);
if(ret==0)
markDestroyed(t);
return ret;
}
virtual int pthread_cond_broadcast(pthread_cond_t *c){
checkAccessed(c);
return LIBC_SYMBOLS.pthread_cond_broadcast(c);
}
virtual int pthread_cond_destroy(pthread_cond_t *c){
markDestroyed(c);
return LIBC_SYMBOLS.pthread_cond_destroy(c);
}
virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
markCreated(c);
return LIBC_SYMBOLS.pthread_cond_init(c,a);
}
virtual int pthread_cond_signal(pthread_cond_t *c){
checkAccessed(c);
return LIBC_SYMBOLS.pthread_cond_signal(c);
}
virtual int pthread_cond_timedwait(pthread_cond_t *c,
pthread_mutex_t *m, const struct timespec *t){
checkAccessed(c);
return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);
}
virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
checkAccessed(c);
return LIBC_SYMBOLS.pthread_cond_wait(c,m);
}
virtual int pthread_mutex_destroy(pthread_mutex_t *m){
markDestroyed(m);
return LIBC_SYMBOLS.pthread_mutex_destroy(m);
}
virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
markCreated(m);
return LIBC_SYMBOLS.pthread_mutex_init(m,a);
}
virtual int pthread_mutex_lock(pthread_mutex_t *m){
checkAccessed(m);
return LIBC_SYMBOLS.pthread_mutex_lock(m);
}
virtual int pthread_mutex_trylock(pthread_mutex_t *m){
checkAccessed(m);
return LIBC_SYMBOLS.pthread_mutex_trylock(m);
}
virtual int pthread_mutex_unlock(pthread_mutex_t *m){
checkAccessed(m);
return LIBC_SYMBOLS.pthread_mutex_unlock(m);
}
};
#endif /*PTHREADMOCKS_H_*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
/**
* 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 <cppunit/extensions/HelperMacros.h>
#include "CppAssertHelper.h"
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include "Vector.h"
using namespace std;
#include <zookeeper.h>
#include "Util.h"
#include "WatchUtil.h"
class Zookeeper_clientretry : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE(Zookeeper_clientretry);
#ifdef THREADED
CPPUNIT_TEST(testRetry);
#endif
CPPUNIT_TEST_SUITE_END();
static void watcher(zhandle_t *, int type, int state, const char *path,void*v){
watchctx_t *ctx = (watchctx_t*)v;
if (state == ZOO_CONNECTED_STATE) {
ctx->connected = true;
} else {
ctx->connected = false;
}
if (type != ZOO_SESSION_EVENT) {
evt_t evt;
evt.path = path;
evt.type = type;
ctx->putEvent(evt);
}
}
static const char hostPorts[];
const char *getHostPorts() {
return hostPorts;
}
zhandle_t *createClient(watchctx_t *ctx) {
zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0,
ctx, 0);
ctx->zh = zk;
sleep(1);
return zk;
}
FILE *logfile;
public:
Zookeeper_clientretry() {
logfile = openlogfile("Zookeeper_clientretry");
}
~Zookeeper_clientretry() {
if (logfile) {
fflush(logfile);
fclose(logfile);
logfile = 0;
}
}
void setUp()
{
zoo_set_log_stream(logfile);
char cmd[1024];
sprintf(cmd, "%s stop %s", ZKSERVER_CMD, getHostPorts());
CPPUNIT_ASSERT(system(cmd) == 0);
/* we are testing that if max cnxns is exceeded the server does the right thing */
sprintf(cmd, "ZKMAXCNXNS=1 %s startClean %s", ZKSERVER_CMD, getHostPorts());
CPPUNIT_ASSERT(system(cmd) == 0);
struct sigaction act;
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
CPPUNIT_ASSERT(sigaction(SIGPIPE, &act, NULL) == 0);
}
void tearDown()
{
char cmd[1024];
sprintf(cmd, "%s stop %s", ZKSERVER_CMD, getHostPorts());
CPPUNIT_ASSERT(system(cmd) == 0);
/* restart the server in "normal" mode */
sprintf(cmd, "%s startClean %s", ZKSERVER_CMD, getHostPorts());
CPPUNIT_ASSERT(system(cmd) == 0);
struct sigaction act;
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
CPPUNIT_ASSERT(sigaction(SIGPIPE, &act, NULL) == 0);
}
bool waitForEvent(zhandle_t *zh, watchctx_t *ctx, int seconds) {
time_t expires = time(0) + seconds;
while(ctx->countEvents() == 0 && time(0) < expires) {
yield(zh, 1);
}
return ctx->countEvents() > 0;
}
static zhandle_t *async_zk;
void testRetry()
{
watchctx_t ctx1, ctx2;
zhandle_t *zk1 = createClient(&ctx1);
CPPUNIT_ASSERT_EQUAL(true, ctx1.waitForConnected(zk1));
zhandle_t *zk2 = createClient(&ctx2);
zookeeper_close(zk1);
CPPUNIT_ASSERT_EQUAL(true, ctx2.waitForConnected(zk2));
ctx1.zh = 0;
}
};
zhandle_t *Zookeeper_clientretry::async_zk;
const char Zookeeper_clientretry::hostPorts[] = "127.0.0.1:22181";
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_clientretry);

View File

@ -0,0 +1,173 @@
/**
* 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 <string>
#include <cppunit/TestRunner.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextTestProgressListener.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <signal.h>
#include <stdlib.h>
#include <stdexcept>
#include <unistd.h>
#include <sys/select.h>
#include <cppunit/Exception.h>
#include <cppunit/TestFailure.h>
#include <cppunit/XmlOutputter.h>
#include <cppunit/TestAssert.h>
#include <fstream>
#include <time.h>
#include "Util.h"
#include "zookeeper_log.h"
using namespace std;
CPPUNIT_NS_BEGIN
class EclipseOutputter: public CompilerOutputter
{
public:
EclipseOutputter(TestResultCollector *result,ostream &stream):
CompilerOutputter(result,stream,"%p:%l: "),stream_(stream)
{
}
virtual void printFailedTestName( TestFailure *failure ){}
virtual void printFailureMessage( TestFailure *failure )
{
stream_<<": ";
Message msg = failure->thrownException()->message();
stream_<< msg.shortDescription();
string text;
for(int i=0; i<msg.detailCount();i++){
text+=msg.detailAt(i);
if(i+1!=msg.detailCount())
text+=", ";
}
if(text.length()!=0)
stream_ <<" ["<<text<<"]";
stream_<<"\n";
}
ostream& stream_;
};
CPPUNIT_NS_END
class TimingListener : public CPPUNIT_NS::BriefTestProgressListener {
public:
void startTest( CPPUNIT_NS::Test *test )
{
gettimeofday(&_start_time, NULL);
CPPUNIT_NS::BriefTestProgressListener::startTest(test);
}
void endTest( CPPUNIT_NS::Test *test )
{
struct timeval end;
gettimeofday(&end, NULL);
long seconds = end.tv_sec - _start_time.tv_sec;
long useconds = end.tv_usec - _start_time.tv_usec;
long mtime = seconds * 1000 + useconds/1000.0;
CPPUNIT_NS::stdCOut() << " : elapsed " << mtime;
CPPUNIT_NS::BriefTestProgressListener::endTest(test);
}
private:
struct timeval _start_time;
};
class ZKServer {
public:
ZKServer() {
char cmd[1024];
sprintf(cmd, "%s startClean %s", ZKSERVER_CMD, "127.0.0.1:22181");
CPPUNIT_ASSERT(system(cmd) == 0);
struct sigaction act;
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
CPPUNIT_ASSERT(sigaction(SIGPIPE, &act, NULL) == 0);
}
virtual ~ZKServer(){
char cmd[1024];
sprintf(cmd, "%s stop %s", ZKSERVER_CMD, "127.0.0.1:22181");
CPPUNIT_ASSERT(system(cmd) == 0);
}
};
int main( int argc, char* argv[] ) {
// if command line contains "-ide" then this is the post build check
// => the output must be in the compiler error format.
//bool selfTest = (argc > 1) && (std::string("-ide") == argv[1]);
globalTestConfig.addConfigFromCmdLine(argc,argv);
ZKServer zkserver;
// Create the event manager and test controller
CPPUNIT_NS::TestResult controller;
// Add a listener that colllects test result
CPPUNIT_NS::TestResultCollector result;
controller.addListener( &result );
// A listener that print dots as tests run.
// CPPUNIT_NS::TextTestProgressListener progress;
// CPPUNIT_NS::BriefTestProgressListener progress;
// brief + elapsed time
TimingListener progress;
controller.addListener( &progress );
CPPUNIT_NS::TestRunner runner;
runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
try {
CPPUNIT_NS::stdCOut() << endl << "Running " << endl;
zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);
//zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);
runner.run( controller, globalTestConfig.getTestName());
// Print test in a compiler compatible format.
CPPUNIT_NS::EclipseOutputter outputter( &result,cout);
outputter.write();
// Uncomment this for XML output
#ifdef ENABLE_XML_OUTPUT
std::ofstream file( "tests.xml" );
CPPUNIT_NS::XmlOutputter xml( &result, file );
xml.setStyleSheet( "report.xsl" );
xml.write();
file.close();
#endif
} catch ( std::invalid_argument &e ) {
// Test path not resolved
cout<<"\nERROR: "<<e.what()<<endl;
return 0;
}
return result.wasSuccessful() ? 0 : 1;
}

View File

@ -0,0 +1,59 @@
/**
* 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 <cppunit/extensions/HelperMacros.h>
#include "CppAssertHelper.h"
#include <string.h>
#include <zookeeper.h>
class Zookeeper_logClientEnv : public CPPUNIT_NS::TestFixture {
CPPUNIT_TEST_SUITE(Zookeeper_logClientEnv);
CPPUNIT_TEST(testLogClientEnv);
CPPUNIT_TEST_SUITE_END();
static void log_no_clientenv(const char *message) {
CPPUNIT_ASSERT(::strstr(message, "Client environment") == NULL);
}
static void log_clientenv(const char *message) {
static int first;
if (!first) {
CPPUNIT_ASSERT(::strstr(message, "Client environment") != NULL);
first = 1;
}
}
public:
void testLogClientEnv() {
zhandle_t* zh;
zh = zookeeper_init2("localhost:22181", NULL, 0, NULL, NULL, 0, log_clientenv);
CPPUNIT_ASSERT(zh != 0);
zookeeper_close(zh);
zh = zookeeper_init2("localhost:22181", NULL, 0, NULL, NULL, ZOO_NO_LOG_CLIENTENV, log_no_clientenv);
CPPUNIT_ASSERT(zh != 0);
zookeeper_close(zh);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_logClientEnv);

View File

@ -0,0 +1,770 @@
/**
* 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 <cppunit/extensions/HelperMacros.h>
#include "CppAssertHelper.h"
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/select.h>
#include "CollectionUtil.h"
#include "ThreadingUtil.h"
using namespace Util;
#include "Vector.h"
using namespace std;
#include <cstring>
#include <list>
#include <zookeeper.h>
#include <errno.h>
#include <recordio.h>
#include "Util.h"
#ifdef THREADED
static void yield(zhandle_t *zh, int i)
{
sleep(i);
}
#else
static void yield(zhandle_t *zh, int seconds)
{
int fd;
int interest;
int events;
struct timeval tv;
time_t expires = time(0) + seconds;
time_t timeLeft = seconds;
fd_set rfds, wfds, efds;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
while(timeLeft >= 0) {
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);
}
} else {
fd = 0;
}
FD_SET(0, &rfds);
if (tv.tv_sec > timeLeft) {
tv.tv_sec = timeLeft;
}
select(fd+1, &rfds, &wfds, &efds, &tv);
timeLeft = expires - time(0);
events = 0;
if (FD_ISSET(fd, &rfds)) {
events |= ZOOKEEPER_READ;
}
if (FD_ISSET(fd, &wfds)) {
events |= ZOOKEEPER_WRITE;
}
zookeeper_process(zh, events);
}
}
#endif
typedef struct evt {
string path;
int type;
} evt_t;
typedef struct watchCtx {
private:
list<evt_t> events;
watchCtx(const watchCtx&);
watchCtx& operator=(const watchCtx&);
public:
bool connected;
zhandle_t *zh;
Mutex mutex;
watchCtx() {
connected = false;
zh = 0;
}
~watchCtx() {
if (zh) {
zookeeper_close(zh);
zh = 0;
}
}
evt_t getEvent() {
evt_t evt;
mutex.acquire();
CPPUNIT_ASSERT( events.size() > 0);
evt = events.front();
events.pop_front();
mutex.release();
return evt;
}
int countEvents() {
int count;
mutex.acquire();
count = events.size();
mutex.release();
return count;
}
void putEvent(evt_t evt) {
mutex.acquire();
events.push_back(evt);
mutex.release();
}
bool waitForConnected(zhandle_t *zh) {
time_t expires = time(0) + 10;
while(!connected && time(0) < expires) {
yield(zh, 1);
}
return connected;
}
bool waitForDisconnected(zhandle_t *zh) {
time_t expires = time(0) + 15;
while(connected && time(0) < expires) {
yield(zh, 1);
}
return !connected;
}
} watchctx_t;
#ifdef THREADED
class Zookeeper_multi : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE(Zookeeper_multi);
//FIXME: None of these tests pass in single-threaded mode. It seems to be a
//flaw in the test suite setup.
CPPUNIT_TEST(testCreate);
CPPUNIT_TEST(testCreateDelete);
CPPUNIT_TEST(testInvalidVersion);
CPPUNIT_TEST(testNestedCreate);
CPPUNIT_TEST(testSetData);
CPPUNIT_TEST(testUpdateConflict);
CPPUNIT_TEST(testDeleteUpdateConflict);
CPPUNIT_TEST(testAsyncMulti);
CPPUNIT_TEST(testMultiFail);
CPPUNIT_TEST(testCheck);
CPPUNIT_TEST(testWatch);
CPPUNIT_TEST(testSequentialNodeCreateInAsyncMulti);
CPPUNIT_TEST(testBigAsyncMulti);
CPPUNIT_TEST_SUITE_END();
static void watcher(zhandle_t *, int type, int state, const char *path,void*v){
watchctx_t *ctx = (watchctx_t*)v;
if (state == ZOO_CONNECTED_STATE) {
ctx->connected = true;
} else {
ctx->connected = false;
}
if (type != ZOO_SESSION_EVENT) {
evt_t evt;
evt.path = path;
evt.type = type;
ctx->putEvent(evt);
}
}
static const char hostPorts[];
const char *getHostPorts() {
return hostPorts;
}
zhandle_t *createClient(watchctx_t *ctx) {
return createClient(hostPorts, ctx);
}
zhandle_t *createClient(const char *hp, watchctx_t *ctx) {
zhandle_t *zk = zookeeper_init(hp, watcher, 10000, 0, ctx, 0);
ctx->zh = zk;
CPPUNIT_ASSERT_EQUAL(true, ctx->waitForConnected(zk));
return zk;
}
FILE *logfile;
public:
Zookeeper_multi() {
logfile = openlogfile("Zookeeper_multi");
}
~Zookeeper_multi() {
if (logfile) {
fflush(logfile);
fclose(logfile);
logfile = 0;
}
}
void setUp()
{
zoo_set_log_stream(logfile);
}
void tearDown()
{
}
static volatile int count;
static void multi_completion_fn(int rc, const void *data) {
CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
count++;
}
static void multi_completion_fn_no_assert(int rc, const void *data) {
count++;
}
static void multi_completion_fn_rc(int rc, const void *data) {
count++;
*((int*) data) = rc;
}
static void create_completion_fn_rc(int rc, const char* value, const void *data) {
count++;
*((int*) data) = rc;
}
static void waitForMultiCompletion(int seconds) {
time_t expires = time(0) + seconds;
while(count == 0 && time(0) < expires) {
sleep(1);
}
count--;
}
static void resetCounter() {
count = 0;
}
/**
* Test basic multi-op create functionality
*/
void testCreate() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char p1[sz];
char p2[sz];
char p3[sz];
p1[0] = p2[0] = p3[0] = '\0';
int nops = 3 ;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi1", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_create_op_init(&ops[1], "/multi1/a", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);
zoo_create_op_init(&ops[2], "/multi1/b", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p3, sz);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT(strcmp(p1, "/multi1") == 0);
CPPUNIT_ASSERT(strcmp(p2, "/multi1/a") == 0);
CPPUNIT_ASSERT(strcmp(p3, "/multi1/b") == 0);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[2].err);
}
/**
* Test create followed by delete
*/
void testCreateDelete() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char p1[sz];
p1[0] = '\0';
int nops = 2 ;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi2", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_delete_op_init(&ops[1], "/multi2", 0);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
// '/multi2' should have been deleted
rc = zoo_exists(zk, "/multi2", 0, NULL);
CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);
}
/**
* Test invalid versions
*/
void testInvalidVersion() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int nops = 4;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi3", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);
zoo_delete_op_init(&ops[1], "/multi3", 1);
zoo_create_op_init(&ops[2], "/multi3", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);
zoo_create_op_init(&ops[3], "/multi3/a", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, rc);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);
CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, results[1].err);
CPPUNIT_ASSERT_EQUAL((int)ZRUNTIMEINCONSISTENCY, results[2].err);
CPPUNIT_ASSERT_EQUAL((int)ZRUNTIMEINCONSISTENCY, results[3].err);
}
/**
* Test nested creates that rely on state in earlier op in multi
*/
void testNestedCreate() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char p1[sz];
p1[0] = '\0';
int nops = 6;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
/* Create */
zoo_create_op_init(&ops[0], "/multi4", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_create_op_init(&ops[1], "/multi4/a", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_create_op_init(&ops[2], "/multi4/a/1", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
/* Delete */
zoo_delete_op_init(&ops[3], "/multi4/a/1", 0);
zoo_delete_op_init(&ops[4], "/multi4/a", 0);
zoo_delete_op_init(&ops[5], "/multi4", 0);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
// Verify tree deleted
rc = zoo_exists(zk, "/multi4/a/1", 0, NULL);
CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);
rc = zoo_exists(zk, "/multi4/a", 0, NULL);
CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);
rc = zoo_exists(zk, "/multi4", 0, NULL);
CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);
}
/**
* Test setdata functionality
*/
void testSetData() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
struct Stat s1;
char buf[sz];
int blen = sz ;
char p1[sz], p2[sz];
int nops = 2;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi5", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_create_op_init(&ops[1], "/multi5/a", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
yield(zk, 5);
zoo_op_t setdata_ops[nops];
zoo_op_result_t setdata_results[nops];
zoo_set_op_init(&setdata_ops[0], "/multi5", "1", 1, 0, &s1);
zoo_set_op_init(&setdata_ops[1], "/multi5/a", "2", 1, 0, &s1);
rc = zoo_multi(zk, nops, setdata_ops, setdata_results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);
memset(buf, '\0', blen);
rc = zoo_get(zk, "/multi5", 0, buf, &blen, &s1);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT_EQUAL(1, blen);
CPPUNIT_ASSERT(strcmp("1", buf) == 0);
memset(buf, '\0', blen);
rc = zoo_get(zk, "/multi5/a", 0, buf, &blen, &s1);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT_EQUAL(1, blen);
CPPUNIT_ASSERT(strcmp("2", buf) == 0);
}
/**
* Test update conflicts
*/
void testUpdateConflict() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char buf[sz];
int blen = sz;
char p1[sz];
p1[0] = '\0';
struct Stat s1;
int nops = 3;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi6", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_set_op_init(&ops[1], "/multi6", "X", 1, 0, &s1);
zoo_set_op_init(&ops[2], "/multi6", "Y", 1, 0, &s1);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, rc);
//Updating version solves conflict -- order matters
ops[2].set_op.version = 1;
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
memset(buf, 0, sz);
rc = zoo_get(zk, "/multi6", 0, buf, &blen, &s1);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT_EQUAL(blen, 1);
CPPUNIT_ASSERT(strncmp(buf, "Y", 1) == 0);
}
/**
* Test delete-update conflicts
*/
void testDeleteUpdateConflict() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char buf[sz];
int blen;
char p1[sz];
p1[0] = '\0';
struct Stat stat;
int nops = 3;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi7", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_delete_op_init(&ops[1], "/multi7", 0);
zoo_set_op_init(&ops[2], "/multi7", "Y", 1, 0, &stat);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);
// '/multi' should never have been created as entire op should fail
rc = zoo_exists(zk, "/multi7", 0, NULL);
CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);
}
void testAsyncMulti() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char p1[sz], p2[sz], p3[sz];
p1[0] = '\0';
p2[0] = '\0';
p3[0] = '\0';
int nops = 3;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi8", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_create_op_init(&ops[1], "/multi8/a", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);
zoo_create_op_init(&ops[2], "/multi8/b", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p3, sz);
rc = zoo_amulti(zk, nops, ops, results, multi_completion_fn, 0);
waitForMultiCompletion(10);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT(strcmp(p1, "/multi8") == 0);
CPPUNIT_ASSERT(strcmp(p2, "/multi8/a") == 0);
CPPUNIT_ASSERT(strcmp(p3, "/multi8/b") == 0);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[2].err);
}
void testMultiFail() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char p1[sz], p2[sz], p3[sz];
p1[0] = '\0';
p2[0] = '\0';
p3[0] = '\0';
int nops = 3;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0], "/multi9", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
zoo_create_op_init(&ops[1], "/multi9", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p2, sz);
zoo_create_op_init(&ops[2], "/multi9/b", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p3, sz);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, rc);
}
/**
* Test basic multi-op check functionality
*/
void testCheck() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char p1[sz];
p1[0] = '\0';
struct Stat s1;
rc = zoo_create(zk, "/multi0", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
// Conditionally create /multi0/a' only if '/multi0' at version 0
int nops = 2;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_check_op_init(&ops[0], "/multi0", 0);
zoo_create_op_init(&ops[1], "/multi0/a", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1].err);
// '/multi0/a' should have been created as it passed version check
rc = zoo_exists(zk, "/multi0/a", 0, NULL);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
// Only create '/multi0/b' if '/multi0' at version 10 (which it's not)
zoo_op_t ops2[nops];
zoo_check_op_init(&ops2[0], "/multi0", 10);
zoo_create_op_init(&ops2[1], "/multi0/b", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, p1, sz);
rc = zoo_multi(zk, nops, ops2, results);
CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, rc);
CPPUNIT_ASSERT_EQUAL((int)ZBADVERSION, results[0].err);
CPPUNIT_ASSERT_EQUAL((int)ZRUNTIMEINCONSISTENCY, results[1].err);
// '/multi0/b' should NOT have been created
rc = zoo_exists(zk, "/multi0/b", 0, NULL);
CPPUNIT_ASSERT_EQUAL((int)ZNONODE, rc);
}
/**
* Do a multi op inside a watch callback context.
*/
static void doMultiInWatch(zhandle_t *zk, int type, int state, const char *path, void *ctx) {
int rc;
int sz = 512;
char p1[sz];
p1[0] = '\0';
struct Stat s1;
int nops = 1;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_set_op_init(&ops[0], "/multiwatch", "1", 1, -1, NULL);
rc = zoo_multi(zk, nops, ops, results);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0].err);
memset(p1, '\0', sz);
rc = zoo_get(zk, "/multiwatch", 0, p1, &sz, &s1);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
CPPUNIT_ASSERT_EQUAL(1, sz);
CPPUNIT_ASSERT(strcmp("1", p1) == 0);
count++;
}
/**
* Test multi-op called from a watch
*/
void testWatch() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int sz = 512;
char p1[sz];
p1[0] = '\0';
rc = zoo_create(zk, "/multiwatch", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
// create a watch on node '/multiwatch'
rc = zoo_wget(zk, "/multiwatch", doMultiInWatch, &ctx, p1, &sz, NULL);
// setdata on node '/multiwatch' this should trip the watch
rc = zoo_set(zk, "/multiwatch", NULL, -1, -1);
CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
// wait for multi completion in doMultiInWatch
waitForMultiCompletion(5);
}
/**
* ZOOKEEPER-1636: If request is too large, the server will cut the
* connection without sending response packet. The client will try to
* process completion on multi request and eventually cause SIGSEGV
*/
void testBigAsyncMulti() {
int rc;
int callback_rc = (int) ZOK;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
// The request should be more than 1MB which exceeds the default
// jute.maxbuffer and causes the server to drop client connection
const int iteration = 500;
const int type_count = 3;
const int nops = iteration * type_count;
char buff[1024];
zoo_op_result_t results[nops];
zoo_op_t ops[nops];
struct Stat* s[nops];
int index = 0;
// Test that we deliver error to 3 types of sub-request
for (int i = 0; i < iteration; ++i) {
zoo_set_op_init(&ops[index++], "/x", buff, sizeof(buff), -1, s[i]);
zoo_create_op_init(&ops[index++], "/x", buff, sizeof(buff),
&ZOO_OPEN_ACL_UNSAFE, ZOO_SEQUENCE, NULL, 0);
zoo_delete_op_init(&ops[index++], "/x", -1);
}
rc = zoo_amulti(zk, nops, ops, results, multi_completion_fn_rc,
+ &callback_rc);
CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
waitForMultiCompletion(10);
// With the bug, we will get SIGSEGV before reaching this point
CPPUNIT_ASSERT_EQUAL((int) ZCONNECTIONLOSS, callback_rc);
// Make sure that all sub-request completions get processed
for (int i = 0; i < nops; ++i) {
CPPUNIT_ASSERT_EQUAL((int) ZCONNECTIONLOSS, results[i].err);
}
// The handle should be able to recover itself.
ctx.waitForConnected(zk);
// Try to submit another async request to see if it get processed
// correctly
rc = zoo_acreate(zk, "/target", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0,
create_completion_fn_rc, &callback_rc);
CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
waitForMultiCompletion(10);
CPPUNIT_ASSERT_EQUAL((int) ZOK, callback_rc);
}
/**
* ZOOKEEPER-1624: PendingChanges of create sequential node request didn't
* get rollbacked correctly when multi-op failed. This caused
* create sequential node request in subsequent multi-op to failed because
* sequential node name generation is incorrect.
*
* The check is to make sure that each request in multi-op failed with
* the correct reason.
*/
void testSequentialNodeCreateInAsyncMulti() {
int rc;
watchctx_t ctx;
zhandle_t *zk = createClient(&ctx);
int iteration = 4;
int nops = 2;
zoo_op_result_t results[iteration][nops];
zoo_op_t ops[nops];
zoo_create_op_init(&ops[0], "/node-", "", 0, &ZOO_OPEN_ACL_UNSAFE, ZOO_SEQUENCE, NULL, 0);
zoo_create_op_init(&ops[1], "/dup", "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, NULL, 0);
for (int i = 0; i < iteration ; ++i) {
rc = zoo_amulti(zk, nops, ops, results[i], multi_completion_fn_no_assert, 0);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
}
waitForMultiCompletion(10);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0][0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[1][0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[2][0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[3][0].err);
CPPUNIT_ASSERT_EQUAL((int)ZOK, results[0][1].err);
CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, results[1][1].err);
CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, results[2][1].err);
CPPUNIT_ASSERT_EQUAL((int)ZNODEEXISTS, results[3][1].err);
resetCounter();
}
};
volatile int Zookeeper_multi::count;
const char Zookeeper_multi::hostPorts[] = "127.0.0.1:22181";
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_multi);
#endif

View File

@ -0,0 +1,976 @@
/**
* 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 <cppunit/extensions/HelperMacros.h>
#include "CppAssertHelper.h"
#include "ZKMocks.h"
#include <proto.h>
using namespace std;
class Zookeeper_operations : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE(Zookeeper_operations);
#ifndef THREADED
CPPUNIT_TEST(testPing);
CPPUNIT_TEST(testUnsolicitedPing);
CPPUNIT_TEST(testTimeoutCausedByWatches1);
CPPUNIT_TEST(testTimeoutCausedByWatches2);
CPPUNIT_TEST(testCloseWhileInProgressFromMain);
CPPUNIT_TEST(testCloseWhileInProgressFromCompletion);
CPPUNIT_TEST(testCloseWhileMultiInProgressFromMain);
CPPUNIT_TEST(testCloseWhileMultiInProgressFromCompletion);
#else
CPPUNIT_TEST(testAsyncWatcher1);
CPPUNIT_TEST(testAsyncGetOperation);
#endif
CPPUNIT_TEST(testOperationsAndDisconnectConcurrently1);
CPPUNIT_TEST(testOperationsAndDisconnectConcurrently2);
CPPUNIT_TEST(testConcurrentOperations1);
CPPUNIT_TEST_SUITE_END();
zhandle_t *zh;
FILE *logfile;
static void watcher(zhandle_t *, int, int, const char *,void*){}
public:
Zookeeper_operations() {
logfile = openlogfile("Zookeeper_operations");
}
~Zookeeper_operations() {
if (logfile) {
fflush(logfile);
fclose(logfile);
logfile = 0;
}
}
void setUp()
{
zoo_set_log_stream(logfile);
zoo_deterministic_conn_order(0);
zh=0;
}
void tearDown()
{
zookeeper_close(zh);
}
class AsyncGetOperationCompletion: public AsyncCompletion{
public:
AsyncGetOperationCompletion():called_(false),rc_(ZAPIERROR){}
virtual void dataCompl(int rc, const char *value, int len, const Stat *stat){
synchronized(mx_);
called_=true;
rc_=rc;
value_.erase();
if(rc!=ZOK) return;
value_.assign(value,len);
if(stat)
stat_=*stat;
}
bool operator()()const{
synchronized(mx_);
return called_;
}
mutable Mutex mx_;
bool called_;
int rc_;
string value_;
NodeStat stat_;
};
class AsyncVoidOperationCompletion: public AsyncCompletion{
public:
AsyncVoidOperationCompletion():called_(false),rc_(ZAPIERROR){}
virtual void voidCompl(int rc){
synchronized(mx_);
called_=true;
rc_=rc;
}
bool operator()()const{
synchronized(mx_);
return called_;
}
mutable Mutex mx_;
bool called_;
int rc_;
};
#ifndef THREADED
// send two get data requests; verify that the corresponding completions called
void testConcurrentOperations1()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
// must call zookeeper_close() while all the mocks are in scope
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// simulate connected state
forceConnected(zh);
int fd=0;
int interest=0;
timeval tv;
// first operation
AsyncGetOperationCompletion res1;
zkServer.addOperationResponse(new ZooGetResponse("1",1));
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// second operation
AsyncGetOperationCompletion res2;
zkServer.addOperationResponse(new ZooGetResponse("2",1));
rc=zoo_aget(zh,"/x/y/2",0,asyncCompletion,&res2);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// process the send queue
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
while((rc=zookeeper_process(zh,interest))==ZOK) {
millisleep(100);
//printf("%d\n", rc);
}
//printf("RC = %d", rc);
CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);
CPPUNIT_ASSERT_EQUAL((int)ZOK,res1.rc_);
CPPUNIT_ASSERT_EQUAL(string("1"),res1.value_);
CPPUNIT_ASSERT_EQUAL((int)ZOK,res2.rc_);
CPPUNIT_ASSERT_EQUAL(string("2"),res2.value_);
}
// send two getData requests and disconnect while the second request is
// outstanding;
// verify the completions are called
void testOperationsAndDisconnectConcurrently1()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
// must call zookeeper_close() while all the mocks are in scope
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// simulate connected state
forceConnected(zh);
int fd=0;
int interest=0;
timeval tv;
// first operation
AsyncGetOperationCompletion res1;
zkServer.addOperationResponse(new ZooGetResponse("1",1));
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// second operation
AsyncGetOperationCompletion res2;
zkServer.addOperationResponse(new ZooGetResponse("2",1));
rc=zoo_aget(zh,"/x/y/2",0,asyncCompletion,&res2);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// process the send queue
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// simulate a disconnect
zkServer.setConnectionLost();
rc=zookeeper_interest(zh,&fd,&interest,&tv);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZCONNECTIONLOSS,rc);
CPPUNIT_ASSERT_EQUAL((int)ZOK,res1.rc_);
CPPUNIT_ASSERT_EQUAL(string("1"),res1.value_);
CPPUNIT_ASSERT_EQUAL((int)ZCONNECTIONLOSS,res2.rc_);
CPPUNIT_ASSERT_EQUAL(string(""),res2.value_);
}
// send two getData requests and simulate timeout while the both request
// are pending;
// verify the completions are called
void testOperationsAndDisconnectConcurrently2()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
// must call zookeeper_close() while all the mocks are in scope
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// simulate connected state
forceConnected(zh);
int fd=0;
int interest=0;
timeval tv;
// first operation
AsyncGetOperationCompletion res1;
zkServer.addOperationResponse(new ZooGetResponse("1",1));
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// second operation
AsyncGetOperationCompletion res2;
zkServer.addOperationResponse(new ZooGetResponse("2",1));
rc=zoo_aget(zh,"/x/y/2",0,asyncCompletion,&res2);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// simulate timeout
timeMock.tick(+10); // advance system time by 10 secs
// the next call to zookeeper_interest should return ZOPERATIONTIMEOUT
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOPERATIONTIMEOUT,rc);
// make sure the completions have been called
CPPUNIT_ASSERT_EQUAL((int)ZOPERATIONTIMEOUT,res1.rc_);
CPPUNIT_ASSERT_EQUAL((int)ZOPERATIONTIMEOUT,res2.rc_);
}
class PingCountingServer: public ZookeeperServer{
public:
PingCountingServer():pingCount_(0){}
// called when a client request is received
virtual void onMessageReceived(const RequestHeader& rh, iarchive* ia){
if(rh.type==ZOO_PING_OP){
pingCount_++;
}
}
int pingCount_;
};
// establish a connection; idle for a while
// verify ping was sent at least once
void testPing()
{
const int TIMEOUT=9; // timeout in secs
Mock_gettimeofday timeMock;
PingCountingServer zkServer;
// must call zookeeper_close() while all the mocks are in scope
CloseFinally guard(&zh);
// receive timeout is in milliseconds
zh=zookeeper_init("localhost:1234",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// simulate connected state
forceConnected(zh);
int fd=0;
int interest=0;
timeval tv;
// Round 1.
int rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// simulate waiting for the select() call to timeout;
// advance the system clock accordingly
timeMock.tick(tv);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);
// verify no ping sent
CPPUNIT_ASSERT(zkServer.pingCount_==0);
// Round 2.
// the client should have the idle threshold exceeded, by now
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// assume the socket is writable, so no idling here; move on to
// zookeeper_process immediately
rc=zookeeper_process(zh,interest);
// ZNOTHING means the client hasn't received a ping response yet
CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);
// verify a ping is sent
CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);
// Round 3.
// we're going to receive a server PING response and make sure
// that the client has updated its last_recv timestamp
zkServer.addRecvResponse(new PingResponse);
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// pseudo-sleep for a short while (10 ms)
timeMock.millitick(10);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// only one ping so far?
CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);
CPPUNIT_ASSERT(timeMock==zh->last_recv);
// Round 4
// make sure that a ping is not sent if something is outstanding
AsyncGetOperationCompletion res1;
rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
timeMock.tick(tv);
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// pseudo-sleep for a short while (10 ms)
timeMock.millitick(10);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);
// only one ping so far?
CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);
}
// ZOOKEEPER-2253: Permit unsolicited pings
void testUnsolicitedPing()
{
const int TIMEOUT=9; // timeout in secs
Mock_gettimeofday timeMock;
PingCountingServer zkServer;
// must call zookeeper_close() while all the mocks are in scope
CloseFinally guard(&zh);
// receive timeout is in milliseconds
zh=zookeeper_init("localhost:1234",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// simulate connected state
forceConnected(zh);
int fd=0;
int interest=0;
timeval tv;
int rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// verify no ping sent
CPPUNIT_ASSERT(zkServer.pingCount_==0);
// we're going to receive a unsolicited PING response; ensure
// that the client has updated its last_recv timestamp
timeMock.tick(tv);
zkServer.addRecvResponse(new PingResponse);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
CPPUNIT_ASSERT(timeMock==zh->last_recv);
}
// simulate a watch arriving right before a ping is due
// assert the ping is sent nevertheless
void testTimeoutCausedByWatches1()
{
const int TIMEOUT=9; // timeout in secs
Mock_gettimeofday timeMock;
PingCountingServer zkServer;
// must call zookeeper_close() while all the mocks are in scope
CloseFinally guard(&zh);
// receive timeout is in milliseconds
zh=zookeeper_init("localhost:1234",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// simulate connected state
forceConnected(zh);
int fd=0;
int interest=0;
timeval tv;
// Round 1.
int rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// simulate waiting for the select() call to timeout;
// advance the system clock accordingly
timeMock.tick(tv);
timeMock.tick(-1); // set the clock to a millisecond before a ping is due
// trigger a watch now
zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,"/x/y/z"));
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// arrival of a watch sets the last_recv to the current time
CPPUNIT_ASSERT(timeMock==zh->last_recv);
// spend 1 millisecond by processing the watch
timeMock.tick(1);
// Round 2.
// a ping is due; zookeeper_interest() must send it now
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// no delay here -- as if the socket is immediately writable
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);
// verify a ping is sent
CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);
}
// similar to testTimeoutCausedByWatches1, but this time the watch is
// triggered while the client has an outstanding request
// assert the ping is sent on time
void testTimeoutCausedByWatches2()
{
const int TIMEOUT=9; // timeout in secs
Mock_gettimeofday now;
PingCountingServer zkServer;
// must call zookeeper_close() while all the mocks are in scope
CloseFinally guard(&zh);
// receive timeout is in milliseconds
zh=zookeeper_init("localhost:1234",watcher,TIMEOUT*1000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// simulate connected state
forceConnected(zh);
// queue up a request; keep it pending (as if the server is busy or has died)
AsyncGetOperationCompletion res1;
zkServer.addOperationResponse(new ZooGetResponse("2",1));
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
int fd=0;
int interest=0;
timeval tv;
// Round 1.
// send the queued up zoo_aget() request
Mock_gettimeofday beginningOfTimes(now); // remember when we started
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// no delay -- the socket is writable
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// Round 2.
// what's next?
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// no response from the server yet -- waiting in the select() call
now.tick(tv);
// a watch has arrived, thus preventing the connection from timing out
zkServer.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,"/x/y/z"));
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc); // read the watch message
CPPUNIT_ASSERT_EQUAL(0,zkServer.pingCount_); // not yet!
//Round 3.
// now is the time to send a ping; make sure it's actually sent
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
rc=zookeeper_process(zh,interest);
CPPUNIT_ASSERT_EQUAL((int)ZNOTHING,rc);
// verify a ping is sent
CPPUNIT_ASSERT_EQUAL(1,zkServer.pingCount_);
// make sure only 1/3 of the timeout has passed
CPPUNIT_ASSERT_EQUAL((int32_t)TIMEOUT/3*1000,toMilliseconds(now-beginningOfTimes));
}
// ZOOKEEPER-2894: Memory and completions leak on zookeeper_close
// while there is a request waiting for being processed
// call zookeeper_close() from the main event loop
// assert the completion callback is called
void testCloseWhileInProgressFromMain()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
forceConnected(zh);
zhandle_t* savezh=zh;
// issue a request
zkServer.addOperationResponse(new ZooGetResponse("1",1));
AsyncGetOperationCompletion res1;
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// but do not allow Zookeeper C Client to process the request
// and call zookeeper_close() from the main event loop immediately
Mock_free_noop freeMock;
rc=zookeeper_close(zh); zh=0;
freeMock.disable();
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// verify that memory for completions was freed (would be freed if no mock installed)
CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));
CPPUNIT_ASSERT(savezh->completions_to_process.head==0);
CPPUNIT_ASSERT(savezh->completions_to_process.last==0);
// verify that completion was called, and it was called with ZCLOSING status
CPPUNIT_ASSERT(res1.called_);
CPPUNIT_ASSERT_EQUAL((int)ZCLOSING,res1.rc_);
}
// ZOOKEEPER-2894: Memory and completions leak on zookeeper_close
// send some request #1
// then, while there is a request #2 waiting for being processed
// call zookeeper_close() from the completion callback of request #1
// assert the completion callback #2 is called
void testCloseWhileInProgressFromCompletion()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
forceConnected(zh);
zhandle_t* savezh=zh;
// will handle completion on request #1 and issue request #2 from it
class AsyncGetOperationCompletion1: public AsyncCompletion{
public:
AsyncGetOperationCompletion1(zhandle_t **zh, ZookeeperServer *zkServer,
AsyncGetOperationCompletion *res2)
:zh_(zh),zkServer_(zkServer),res2_(res2){}
virtual void dataCompl(int rc1, const char *value, int len, const Stat *stat){
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc1);
// from the completion #1 handler, issue request #2
zkServer_->addOperationResponse(new ZooGetResponse("2",1));
int rc2=zoo_aget(*zh_,"/x/y/2",0,asyncCompletion,res2_);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc2);
// but do not allow Zookeeper C Client to process the request #2
// and call zookeeper_close() from the completion callback of request #1
rc2=zookeeper_close(*zh_); *zh_=0;
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc2);
// do not disable freeMock here, let completion #2 handler
// return through ZooKeeper C Client internals to the main loop
// and fulfill the work
}
zhandle_t **zh_;
ZookeeperServer *zkServer_;
AsyncGetOperationCompletion *res2_;
};
// issue request #1
AsyncGetOperationCompletion res2;
AsyncGetOperationCompletion1 res1(&zh,&zkServer,&res2);
zkServer.addOperationResponse(new ZooGetResponse("1",1));
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// process the send queue
int fd; int interest; timeval tv;
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
CPPUNIT_ASSERT(zh!=0);
Mock_free_noop freeMock;
while(zh!=0 && (rc=zookeeper_process(zh,interest))==ZOK) {
millisleep(100);
}
freeMock.disable();
CPPUNIT_ASSERT(zh==0);
// verify that memory for completions was freed (would be freed if no mock installed)
CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));
CPPUNIT_ASSERT(savezh->completions_to_process.head==0);
CPPUNIT_ASSERT(savezh->completions_to_process.last==0);
// verify that completion #2 was called, and it was called with ZCLOSING status
CPPUNIT_ASSERT(res2.called_);
CPPUNIT_ASSERT_EQUAL((int)ZCLOSING,res2.rc_);
}
// ZOOKEEPER-2891: Invalid processing of zookeeper_close for mutli-request
// while there is a multi request waiting for being processed
// call zookeeper_close() from the main event loop
// assert the completion callback is called with status ZCLOSING
void testCloseWhileMultiInProgressFromMain()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
forceConnected(zh);
zhandle_t* savezh=zh;
// issue a multi request
int nops=2;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
zoo_create_op_init(&ops[0],"/a",0,-1,&ZOO_OPEN_ACL_UNSAFE,0,0,0);
zoo_create_op_init(&ops[1],"/a/b",0,-1,&ZOO_OPEN_ACL_UNSAFE,0,0,0);
// TODO: Provide ZooMultiResponse. However, it's not required in this test.
// zkServer.addOperationResponse(new ZooMultiResponse(...));
AsyncVoidOperationCompletion res1;
int rc=zoo_amulti(zh,nops,ops,results,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// but do not allow Zookeeper C Client to process the request
// and call zookeeper_close() from the main event loop immediately
Mock_free_noop freeMock;
rc=zookeeper_close(zh); zh=0;
freeMock.disable();
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// verify that memory for completions was freed (would be freed if no mock installed)
CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));
CPPUNIT_ASSERT(savezh->completions_to_process.head==0);
CPPUNIT_ASSERT(savezh->completions_to_process.last==0);
// verify that completion was called, and it was called with ZCLOSING status
CPPUNIT_ASSERT(res1.called_);
CPPUNIT_ASSERT_EQUAL((int)ZCLOSING,res1.rc_);
}
// ZOOKEEPER-2891: Invalid processing of zookeeper_close for mutli-request
// send some request #1 (not a multi request)
// then, while there is a multi request #2 waiting for being processed
// call zookeeper_close() from the completion callback of request #1
// assert the completion callback #2 is called with status ZCLOSING
void testCloseWhileMultiInProgressFromCompletion()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
forceConnected(zh);
zhandle_t* savezh=zh;
// these shall persist during the test
int nops=2;
zoo_op_t ops[nops];
zoo_op_result_t results[nops];
// will handle completion on request #1 and issue request #2 from it
class AsyncGetOperationCompletion1: public AsyncCompletion{
public:
AsyncGetOperationCompletion1(zhandle_t **zh, ZookeeperServer *zkServer,
AsyncVoidOperationCompletion *res2,
int nops, zoo_op_t* ops, zoo_op_result_t* results)
:zh_(zh),zkServer_(zkServer),res2_(res2),nops_(nops),ops_(ops),results_(results){}
virtual void dataCompl(int rc1, const char *value, int len, const Stat *stat){
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc1);
// from the completion #1 handler, issue multi request #2
assert(nops_>=2);
zoo_create_op_init(&ops_[0],"/a",0,-1,&ZOO_OPEN_ACL_UNSAFE,0,0,0);
zoo_create_op_init(&ops_[1],"/a/b",0,-1,&ZOO_OPEN_ACL_UNSAFE,0,0,0);
// TODO: Provide ZooMultiResponse. However, it's not required in this test.
// zkServer_->addOperationResponse(new ZooMultiResponse(...));
int rc2=zoo_amulti(*zh_,nops_,ops_,results_,asyncCompletion,res2_);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc2);
// but do not allow Zookeeper C Client to process the request #2
// and call zookeeper_close() from the completion callback of request #1
rc2=zookeeper_close(*zh_); *zh_=0;
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc2);
// do not disable freeMock here, let completion #2 handler
// return through ZooKeeper C Client internals to the main loop
// and fulfill the work
}
zhandle_t **zh_;
ZookeeperServer *zkServer_;
AsyncVoidOperationCompletion *res2_;
int nops_;
zoo_op_t* ops_;
zoo_op_result_t* results_;
};
// issue some request #1 (not a multi request)
AsyncVoidOperationCompletion res2;
AsyncGetOperationCompletion1 res1(&zh,&zkServer,&res2,nops,ops,results);
zkServer.addOperationResponse(new ZooGetResponse("1",1));
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
// process the send queue
int fd; int interest; timeval tv;
rc=zookeeper_interest(zh,&fd,&interest,&tv);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
CPPUNIT_ASSERT(zh!=0);
Mock_free_noop freeMock;
while(zh!=0 && (rc=zookeeper_process(zh,interest))==ZOK) {
millisleep(100);
}
freeMock.disable();
CPPUNIT_ASSERT(zh==0);
// verify that memory for completions was freed (would be freed if no mock installed)
CPPUNIT_ASSERT_EQUAL(1,freeMock.getFreeCount(savezh));
CPPUNIT_ASSERT(savezh->completions_to_process.head==0);
CPPUNIT_ASSERT(savezh->completions_to_process.last==0);
// verify that completion #2 was called, and it was called with ZCLOSING status
CPPUNIT_ASSERT(res2.called_);
CPPUNIT_ASSERT_EQUAL((int)ZCLOSING,res2.rc_);
}
#else
class TestGetDataJob: public TestJob{
public:
TestGetDataJob(ZookeeperServer* svr,zhandle_t* zh, int reps=500)
:svr_(svr),zh_(zh),rc_(ZAPIERROR),reps_(reps){}
virtual void run(){
int i;
for(i=0;i<reps_;i++){
char buf;
int size=sizeof(buf);
if (i % 10 == 0) {
// We need to pause every once in a while so we don't
// get too far ahead and finish before the disconnect
millisleep(1);
}
svr_->addOperationResponse(new ZooGetResponse("1",1));
rc_=zoo_get(zh_,"/x/y/z",0,&buf,&size,0);
if(rc_!=ZOK){
break;
}
}
}
ZookeeperServer* svr_;
zhandle_t* zh_;
int rc_;
int reps_;
};
class TestConcurrentOpJob: public TestGetDataJob{
public:
static const int REPS=500;
TestConcurrentOpJob(ZookeeperServer* svr,zhandle_t* zh):
TestGetDataJob(svr,zh,REPS){}
virtual TestJob* clone() const {
return new TestConcurrentOpJob(svr_,zh_);
}
virtual void validate(const char* file, int line) const{
CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC("ZOK != rc",(int)ZOK,rc_,file,line);
}
};
void testConcurrentOperations1()
{
for(int counter=0; counter<50; counter++){
// frozen time -- no timeouts and no pings
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
Mock_poll pollMock(&zkServer,ZookeeperServer::FD);
// must call zookeeper_close() while all the mocks are in the scope!
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// make sure the client has connected
CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);
TestJobManager jmgr(TestConcurrentOpJob(&zkServer,zh),10);
jmgr.startAllJobs();
jmgr.wait();
// validate test results
VALIDATE_JOBS(jmgr);
}
}
class ZKGetJob: public TestJob{
public:
static const int REPS=1000;
ZKGetJob(zhandle_t* zh)
:zh_(zh),rc_(ZAPIERROR){}
virtual TestJob* clone() const {
return new ZKGetJob(zh_);
}
virtual void run(){
int i;
for(i=0;i<REPS;i++){
char buf;
int size=sizeof(buf);
rc_=zoo_get(zh_,"/xyz",0,&buf,&size,0);
if(rc_!=ZOK){
break;
}
}
//TEST_TRACE("Finished %d iterations",i);
}
virtual void validate(const char* file, int line) const{
CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC("ZOK != rc",(int)ZOK,rc_,file,line);
}
zhandle_t* zh_;
int rc_;
};
// this test connects to a real ZK server and creates the /xyz node and sends
// lots of zoo_get requests.
// to run this test use the following command:
// zktest-mt Zookeeper_operations::testOperationsAndDisconnectConcurrently2 localhost:3181
// where the second parameter is the server host and port
void testOperationsAndDisconnectConcurrently2()
{
if(globalTestConfig.getTestName().find(__func__)==string::npos ||
globalTestConfig.getExtraOptCount()==0)
{
// only run this test when specifically asked so
return;
}
string host(*(globalTestConfig.getExtraOptBegin()));
zhandle_t* lzh=zookeeper_init(host.c_str(),watcher,10000,0,0,0);
CPPUNIT_ASSERT(lzh!=0);
// make sure the client has connected
CPPUNIT_ASSERT_MESSAGE("Unable to connect to the host",
ensureCondition(ClientConnected(zh),5000)<5000);
char realpath[1024];
int rc=zoo_create(lzh,"/xyz","1",1,&ZOO_OPEN_ACL_UNSAFE,0,realpath,sizeof(realpath)-1);
CPPUNIT_ASSERT(rc==ZOK || rc==ZNODEEXISTS);
zookeeper_close(lzh);
for(int counter=0; counter<200; counter++){
TEST_TRACE("Loop count %d",counter);
CloseFinally guard(&zh);
zh=zookeeper_init(host.c_str(),watcher,10000,0,0,0);
CPPUNIT_ASSERT(zh!=0);
// make sure the client has connected
CPPUNIT_ASSERT_MESSAGE("Unable to connect to the host",
ensureCondition(ClientConnected(zh),5000)<5000);
TestJobManager jmgr(ZKGetJob(zh),10);
jmgr.startJobsImmediately();
jmgr.wait();
VALIDATE_JOBS(jmgr);
TEST_TRACE("run %d finished",counter);
}
}
class TestConcurrentOpWithDisconnectJob: public TestGetDataJob{
public:
static const int REPS=1000;
TestConcurrentOpWithDisconnectJob(ZookeeperServer* svr,zhandle_t* zh):
TestGetDataJob(svr,zh,REPS){}
virtual TestJob* clone() const {
return new TestConcurrentOpWithDisconnectJob(svr_,zh_);
}
virtual void validate(const char* file, int line) const{
CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC("ZCONNECTIONLOSS != rc",(int)ZCONNECTIONLOSS,rc_,file,line);
}
};
// this test is not 100% accurate in a sense it may not detect all error cases.
// TODO: I can't think of a test that is 100% accurate and doesn't interfere
// with the code being tested (in terms of introducing additional
// implicit synchronization points)
void testOperationsAndDisconnectConcurrently1()
{
for(int counter=0; counter<50; counter++){
//TEST_TRACE("Loop count %d",counter);
// frozen time -- no timeouts and no pings
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
Mock_poll pollMock(&zkServer,ZookeeperServer::FD);
// must call zookeeper_close() while all the mocks are in the scope!
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// make sure the client has connected
CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);
TestJobManager jmgr(TestConcurrentOpWithDisconnectJob(&zkServer,zh),10);
jmgr.startJobsImmediately();
// let everything startup before we shutdown the server
millisleep(4);
// reconnect attempts will start failing immediately
zkServer.setServerDown(0);
// next recv call will return 0
zkServer.setConnectionLost();
jmgr.wait();
VALIDATE_JOBS(jmgr);
}
}
// call zoo_aget() in the multithreaded mode
void testAsyncGetOperation()
{
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
Mock_poll pollMock(&zkServer,ZookeeperServer::FD);
// must call zookeeper_close() while all the mocks are in the scope!
CloseFinally guard(&zh);
zh=zookeeper_init("localhost:2121",watcher,10000,TEST_CLIENT_ID,0,0);
CPPUNIT_ASSERT(zh!=0);
// make sure the client has connected
CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);
AsyncGetOperationCompletion res1;
zkServer.addOperationResponse(new ZooGetResponse("1",1));
int rc=zoo_aget(zh,"/x/y/1",0,asyncCompletion,&res1);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
CPPUNIT_ASSERT(ensureCondition(res1,1000)<1000);
CPPUNIT_ASSERT_EQUAL((int)ZOK,res1.rc_);
CPPUNIT_ASSERT_EQUAL(string("1"),res1.value_);
}
class ChangeNodeWatcher: public WatcherAction{
public:
ChangeNodeWatcher():changed_(false){}
virtual void onNodeValueChanged(zhandle_t*,const char* path){
synchronized(mx_);
changed_=true;
if(path!=0) path_=path;
}
// this predicate checks if CHANGE_EVENT event type was triggered, unlike
// the isWatcherTriggered() that returns true whenever a watcher is triggered
// regardless of the event type
SyncedBoolCondition isNodeChangedTriggered() const{
return SyncedBoolCondition(changed_,mx_);
}
bool changed_;
string path_;
};
class AsyncWatcherCompletion: public AsyncCompletion{
public:
AsyncWatcherCompletion(ZookeeperServer& zkServer):zkServer_(zkServer){}
virtual void statCompl(int rc, const Stat *stat){
// we received a server response, now enqueue a watcher event
// to trigger the watcher
zkServer_.addRecvResponse(new ZNodeEvent(ZOO_CHANGED_EVENT,"/x/y/z"));
}
ZookeeperServer& zkServer_;
};
// verify that async watcher is called for znode events (CREATED, DELETED etc.)
void testAsyncWatcher1(){
Mock_gettimeofday timeMock;
ZookeeperServer zkServer;
Mock_poll pollMock(&zkServer,ZookeeperServer::FD);
// must call zookeeper_close() while all the mocks are in the scope!
CloseFinally guard(&zh);
ChangeNodeWatcher action;
zh=zookeeper_init("localhost:2121",activeWatcher,10000,
TEST_CLIENT_ID,&action,0);
CPPUNIT_ASSERT(zh!=0);
// make sure the client has connected
CPPUNIT_ASSERT(ensureCondition(ClientConnected(zh),1000)<1000);
// set the watcher
AsyncWatcherCompletion completion(zkServer);
// prepare a response for the zoo_aexists() request
zkServer.addOperationResponse(new ZooStatResponse);
int rc=zoo_aexists(zh,"/x/y/z",1,asyncCompletion,&completion);
CPPUNIT_ASSERT_EQUAL((int)ZOK,rc);
CPPUNIT_ASSERT(ensureCondition(action.isNodeChangedTriggered(),1000)<1000);
CPPUNIT_ASSERT_EQUAL(string("/x/y/z"),action.path_);
}
#endif
};
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_operations);

View File

@ -0,0 +1,153 @@
/**
* 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 <cppunit/extensions/HelperMacros.h>
#include "CppAssertHelper.h"
#include <sys/socket.h>
#include <unistd.h>
#include <zookeeper.h>
#include "Util.h"
#include "WatchUtil.h"
#ifdef THREADED
class Zookeeper_readOnly : public CPPUNIT_NS::TestFixture {
CPPUNIT_TEST_SUITE(Zookeeper_readOnly);
CPPUNIT_TEST(testReadOnly);
#ifdef HAVE_OPENSSL_H
CPPUNIT_TEST(testReadOnlyWithSSL);
#endif
CPPUNIT_TEST_SUITE_END();
static void watcher(zhandle_t* zh, int type, int state,
const char* path, void* v) {
watchctx_t *ctx = (watchctx_t*)v;
if (state==ZOO_CONNECTED_STATE || state==ZOO_READONLY_STATE) {
ctx->connected = true;
} else {
ctx->connected = false;
}
if (type != ZOO_SESSION_EVENT) {
evt_t evt;
evt.path = path;
evt.type = type;
ctx->putEvent(evt);
}
}
FILE *logfile;
public:
Zookeeper_readOnly() {
logfile = openlogfile("Zookeeper_readOnly");
}
~Zookeeper_readOnly() {
if (logfile) {
fflush(logfile);
fclose(logfile);
logfile = 0;
}
}
void setUp() {
zoo_set_log_stream(logfile);
zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);
}
void startReadOnly() {
char cmd[1024];
sprintf(cmd, "%s startCleanReadOnly", ZKSERVER_CMD);
CPPUNIT_ASSERT(system(cmd) == 0);
}
void stopPeer() {
char cmd[1024];
sprintf(cmd, "%s stop", ZKSERVER_CMD);
CPPUNIT_ASSERT(system(cmd) == 0);
}
zhandle_t* connectReadOnly(const char *address, watchctx_t *watch) {
zhandle_t* zh = zookeeper_init(address, watcher, 10000, NULL, watch, ZOO_READONLY);
watch->zh = zh;
CPPUNIT_ASSERT(zh != 0);
sleep(1);
return zh;
}
void assertCanRead(zhandle_t* zh, const char *znode_path) {
int len = 1024;
char buf[len];
int res = zoo_get(zh, znode_path, 0, buf, &len, 0);
CPPUNIT_ASSERT_EQUAL((int)ZOK, res);
}
void assertCanNotWrite(zhandle_t* zh, const char *znode_path) {
char path[1024];
char buf[1024];
int res = zoo_create(zh, znode_path, buf, 10, &ZOO_OPEN_ACL_UNSAFE, 0, path, 512);
CPPUNIT_ASSERT_EQUAL((int)ZNOTREADONLY, res);
}
void testReadOnly()
{
startReadOnly();
watchctx_t watch;
zhandle_t* zh = connectReadOnly("localhost:22181", &watch);
assertCanRead(zh, "/");
assertCanNotWrite(zh, "/test");
stopPeer();
}
#ifdef HAVE_OPENSSL_H
zhandle_t* connectReadOnlySSL(const char *address, const char *certs, watchctx_t *watch) {
zhandle_t* zh = zookeeper_init_ssl(address, certs, watcher, 10000, NULL, watch, ZOO_READONLY);
watch->zh = zh;
CPPUNIT_ASSERT(zh != 0);
sleep(1);
return zh;
}
void testReadOnlyWithSSL() {
startReadOnly();
watchctx_t watch;
zhandle_t* zh = connectReadOnlySSL("localhost:22281",
"/tmp/certs/server.crt,/tmp/certs/client.crt,/tmp/certs/clientkey.pem,password",
&watch);
assertCanRead(zh, "/");
assertCanNotWrite(zh, "/testSSL");
stopPeer();
}
#endif
};
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_readOnly);
#endif

View File

@ -0,0 +1,697 @@
/**
* 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 <cppunit/extensions/HelperMacros.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <iostream>
#include <sstream>
#include <arpa/inet.h>
#include <exception>
#include <stdlib.h>
extern "C" {
#include <src/addrvec.h>
}
#include "Util.h"
#include "LibCMocks.h"
#include "ZKMocks.h"
using namespace std;
static const int portOffset = 2000;
class Client
{
private:
// Member variables
zhandle_t *zh;
unsigned int seed;
public:
/**
* Create a client with given connection host string and add to our internal
* vector of clients. These are disconnected and cleaned up in tearDown().
*/
Client(const string hosts, unsigned int seed) :
seed((seed * seed) + 0xAFAFAFAF)
{
reSeed();
zh = zookeeper_init(hosts.c_str(),0,1000,0,0,0);
CPPUNIT_ASSERT(zh);
// Set the flag to disable ZK from reconnecting to a different server.
// Our reconfig test case will do explicit server shuffling through
// zoo_cycle_next_server, and the reconnection attempts would interfere
// with the server states the tests cases assume.
zh->disable_reconnection_attempt = 1;
reSeed();
cycleNextServer();
}
void close()
{
zookeeper_close(zh);
zh = NULL;
}
bool isReconfig()
{
return zh->reconfig != 0;
}
/**
* re-seed this client with it's own previously generated seed so its
* random choices are unique and separate from the other clients
*/
void reSeed()
{
srandom(seed);
srand48(seed);
}
/**
* Get the server that this client is currently connected to.
*/
string getServer()
{
const char* addrstring = zoo_get_current_server(zh);
return string(addrstring);
}
/**
* Get the server this client is currently connected to with no port
* specification.
*/
string getServerNoPort()
{
string addrstring = getServer();
size_t found = addrstring.find_last_of(":");
CPPUNIT_ASSERT(found != string::npos);
// ipv6 address case (to remove leading and trailing bracket)
if (addrstring.find("[") != string::npos)
{
return addrstring.substr(1, found-2);
}
else
{
return addrstring.substr(0, found);
}
}
/**
* Get the port of the server this client is currently connected to.
*/
uint32_t getServerPort()
{
string addrstring = getServer();
size_t found = addrstring.find_last_of(":");
CPPUNIT_ASSERT(found != string::npos);
string portStr = addrstring.substr(found+1);
stringstream ss(portStr);
uint32_t port;
ss >> port;
CPPUNIT_ASSERT(port >= portOffset);
return port;
}
/**
* Cycle to the next available server on the next connect attempt. It also
* calls into getServer (above) to return the server connected to.
*/
string cycleNextServer()
{
zoo_cycle_next_server(zh);
return getServer();
}
void cycleUntilServer(const string requested)
{
// Call cycleNextServer until the one it's connected to is the one
// specified (disregarding port).
string first;
while(true)
{
string next = cycleNextServer();
if (first.empty())
{
first = next;
}
// Else we've looped around!
else if (first == next)
{
CPPUNIT_ASSERT(false);
}
// Strip port off
string server = getServerNoPort();
// If it matches the requested host we're now 'connected' to the right host
if (server == requested)
{
break;
}
}
}
/**
* Set servers for this client.
*/
void setServers(const string new_hosts)
{
int rc = zoo_set_servers(zh, new_hosts.c_str());
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
}
/**
* Set servers for this client and validate reconfig value matches expected.
*/
void setServersAndVerifyReconfig(const string new_hosts, bool is_reconfig)
{
setServers(new_hosts);
CPPUNIT_ASSERT_EQUAL(is_reconfig, isReconfig());
}
/**
* Sets the server list this client is connecting to AND if this requires
* the client to be reconfigured (as dictated by internal client policy)
* then it will trigger a call to cycleNextServer.
*/
void setServersAndCycleIfNeeded(const string new_hosts)
{
setServers(new_hosts);
if (isReconfig())
{
cycleNextServer();
}
}
};
class Zookeeper_reconfig : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE(Zookeeper_reconfig);
// Test cases
CPPUNIT_TEST(testcycleNextServer);
CPPUNIT_TEST(testMigrateOrNot);
CPPUNIT_TEST(testMigrationCycle);
CPPUNIT_TEST(testAddrVecContainsIPv4);
#ifdef AF_INET6
CPPUNIT_TEST(testAddrVecContainsIPv6);
#endif
// In threaded mode each 'create' is a thread -- it's not practical to create
// 10,000 threads to test load balancing. The load balancing code can easily
// be tested in single threaded mode as concurrency doesn't affect the algorithm.
#ifndef THREADED
CPPUNIT_TEST(testMigrateProbability);
CPPUNIT_TEST(testLoadBalancing);
#endif
CPPUNIT_TEST_SUITE_END();
FILE *logfile;
double slackPercent;
static const int numClients = 10000;
static const int portOffset = 2000;
vector<Client> clients;
vector<uint32_t> numClientsPerHost;
public:
Zookeeper_reconfig() :
slackPercent(10.0)
{
logfile = openlogfile("Zookeeper_reconfig");
}
~Zookeeper_reconfig()
{
if (logfile)
{
fflush(logfile);
fclose(logfile);
logfile = 0;
}
}
void setUp()
{
zoo_set_log_stream(logfile);
zoo_deterministic_conn_order(1);
numClientsPerHost.resize(numClients);
}
void tearDown()
{
for (unsigned int i = 0; i < clients.size(); i++)
{
clients.at(i).close();
}
}
/**
* Create a client with given connection host string and add to our internal
* vector of clients. These are disconnected and cleaned up in tearDown().
*/
Client& createClient(const string hosts)
{
Client client(hosts, clients.size());
clients.push_back(client);
return clients.back();
}
/**
* Same as createClient(hosts) only it takes a specific host that this client
* should simulate being connected to.
*/
Client& createClient(const string hosts, const string host)
{
// Ensure requested host is in the list
size_t found = hosts.find(host);
CPPUNIT_ASSERT(found != hosts.npos);
Client client(hosts, clients.size());
client.cycleUntilServer(host);
clients.push_back(client);
return clients.back();
}
/**
* Create a connection host list starting at 'start' and stopping at 'stop'
* where start >= stop. This creates a connection string with host:port pairs
* separated by commas. The given 'octet' is the starting octet that is used
* as the last octet in the host's IP. This is decremented on each iteration.
* Each port will be portOffset + octet.
*/
string createHostList(uint32_t start, uint32_t stop = 1, uint32_t octet = 0)
{
if (octet == 0)
{
octet = start;
}
stringstream ss;
for (uint32_t i = start; i >= stop; i--, octet--)
{
ss << "10.10.10." << octet << ":" << portOffset + octet;
if (i > stop)
{
ss << ", ";
}
}
return ss.str();
}
/**
* Gets the lower bound of the number of clients per server that we expect
* based on the probabilistic load balancing algorithm implemented by the
* client code.
*/
double lowerboundClientsPerServer(int numClients, int numServers)
{
return (1 - slackPercent/100.0) * numClients / numServers;
}
/**
* Gets the upper bound of the number of clients per server that we expect
* based on the probabilistic load balancing algorithm implemented by the
* client code.
*/
double upperboundClientsPerServer(int numClients, int numServers)
{
return (1 + slackPercent/100.0) * numClients / numServers;
}
/**
* Update all the clients to use a new list of servers. This will also cause
* the client to cycle to the next server as needed (e.g. due to a reconfig).
* It then updates the number of clients connected to the server based on
* this change.
*
* Afterwards it validates that all of the servers have the correct amount of
* clients based on the probabilistic load balancing algorithm.
*/
void updateAllClientsAndServers(int start, int stop = 1)
{
string newServers = createHostList(start, stop);
int numServers = start - stop + 1;
for (int i = 0; i < numClients; i++) {
Client &client = clients.at(i);
client.reSeed();
client.setServersAndCycleIfNeeded(newServers);
numClientsPerHost.at(client.getServerPort() - portOffset - 1)++;
}
int offset = stop - 1;
for (int index = offset; index < numServers; index++) {
if (numClientsPerHost.at(index) > upperboundClientsPerServer(numClients, numServers))
{
cout << "INDEX=" << index << " too many -- actual=" << numClientsPerHost.at(index)
<< " expected=" << upperboundClientsPerServer(numClients, numServers) << endl;
}
CPPUNIT_ASSERT(numClientsPerHost.at(index) <= upperboundClientsPerServer(numClients, numServers));
if (numClientsPerHost.at(index) < lowerboundClientsPerServer(numClients, numServers))
{
cout << "INDEX=" << index << " too few -- actual=" << numClientsPerHost.at(index)
<< " expected=" << lowerboundClientsPerServer(numClients, numServers) << endl;
}
CPPUNIT_ASSERT(numClientsPerHost.at(index) >= lowerboundClientsPerServer(numClients, numServers));
numClientsPerHost.at(index) = 0; // prepare for next test
}
}
/*-------------------------------------------------------------------------*
* TESTCASES
*------------------------------------------------------------------------*/
/**
* Very basic sunny day test to ensure basic functionality of zoo_set_servers
* and zoo_cycle_next_server.
*/
void testcycleNextServer()
{
const string initial_hosts = createHostList(10); // 2010..2001
const string new_hosts = createHostList(4); // 2004..2001
Client &client = createClient(initial_hosts);
client.setServersAndVerifyReconfig(new_hosts, true);
for (int i = 0; i < 10; i++)
{
string next = client.cycleNextServer();
}
}
/**
* Test the migration policy implicit within the probabilistic load balancing
* algorithm the Client implements. Tests all the corner cases whereby the
* list of servers is decreased, increased, and stays the same. Also combines
* various combinations of the currently connected server being in the new
* configuration and not.
*/
void testMigrateOrNot()
{
const string initial_hosts = createHostList(4); // 2004..2001
Client &client = createClient(initial_hosts, "10.10.10.3");
// Ensemble size decreasing, my server is in the new list
client.setServersAndVerifyReconfig(createHostList(3), false);
// Ensemble size decreasing, my server is NOT in the new list
client.setServersAndVerifyReconfig(createHostList(2), true);
// Ensemble size stayed the same, my server is NOT in the new list
client.setServersAndVerifyReconfig(createHostList(2), true);
// Ensemble size increased, my server is not in the new ensemble
client.setServers(createHostList(4));
client.cycleUntilServer("10.10.10.1");
client.setServersAndVerifyReconfig(createHostList(7,2), true);
}
/**
* This tests that as a client is in reconfig mode it will properly try to
* connect to all the new servers first. Then it will try to connect to all
* the 'old' servers that are staying in the new configuration. Finally it
* will fallback to the normal behavior of trying servers in round-robin.
*/
void testMigrationCycle()
{
int num_initial = 4;
const string initial_hosts = createHostList(num_initial); // {2004..2001}
int num_new = 10;
string new_hosts = createHostList(12, 3); // {2012..2003}
// servers from the old list that appear in the new list {2004..2003}
int num_staying = 2;
string oldStaying = createHostList(4, 3);
// servers in the new list that are not in the old list {2012..2005}
int num_coming = 8;
string newComing = createHostList(12, 5);
// Ensemble in increasing in size, my server is not in the new ensemble
// load on the old servers must be decreased, so must connect to one of
// new servers (pNew = 1)
Client &client = createClient(initial_hosts, "10.10.10.1");
client.setServersAndVerifyReconfig(new_hosts, true);
// Since we're in reconfig mode, next connect should be from new list
// We should try all the new servers *BEFORE* trying any old servers
string seen;
for (int i = 0; i < num_coming; i++) {
client.cycleNextServer();
// Assert next server is in the 'new' list
stringstream next;
next << client.getServerNoPort() << ":" << client.getServerPort();
size_t found = newComing.find(next.str());
CPPUNIT_ASSERT_MESSAGE(next.str() + " not in newComing list",
found != string::npos);
// Assert not in seen list then append
found = seen.find(next.str());
CPPUNIT_ASSERT_MESSAGE(next.str() + " in seen list",
found == string::npos);
seen += found + ", ";
}
// Now it should start connecting to the old servers
seen.clear();
for (int i = 0; i < num_staying; i++) {
client.cycleNextServer();
// Assert it's in the old list
stringstream next;
next << client.getServerNoPort() << ":" << client.getServerPort();
size_t found = oldStaying.find(next.str());
CPPUNIT_ASSERT(found != string::npos);
// Assert not in seen list then append
found = seen.find(next.str());
CPPUNIT_ASSERT(found == string::npos);
seen += found + ", ";
}
// NOW it goes back to normal as we've tried all the new and old
string first = client.cycleNextServer();
for (int i = 0; i < num_new - 1; i++) {
client.cycleNextServer();
}
CPPUNIT_ASSERT_EQUAL(first, client.cycleNextServer());
}
/**
* Test the migration probability to ensure that it conforms to our expected
* lower and upper bounds of the number of clients per server as we are
* reconfigured.
*
* In this case, the list of servers is increased and the client's server is
* in the new list. Whether to move or not depends on the difference of
* server sizes with probability 1 - |old|/|new| the client disconnects.
*
* In the test below 1-9/10 = 1/10 chance of disconnecting
*/
void testMigrateProbability()
{
const string initial_hosts = createHostList(9); // 10.10.10.9:2009...10.10.10.1:2001
string new_hosts = createHostList(10); // 10.10.10.10:2010...10.10.10.1:2001
uint32_t numDisconnects = 0;
for (int i = 0; i < numClients; i++) {
Client &client = createClient(initial_hosts, "10.10.10.3");
client.setServers(new_hosts);
if (client.isReconfig())
{
numDisconnects++;
}
}
// should be numClients/10 in expectation, we test that it's numClients/10 +- slackPercent
CPPUNIT_ASSERT(numDisconnects < upperboundClientsPerServer(numClients, 10));
}
/**
* Tests the probabilistic load balancing algorithm implemented by the Client
* code.
*
* Test strategy:
*
* (1) Start with 9 servers and 10,000 clients. Remove a server, update
* everything, and ensure that the clients are redistributed properly.
*
* (2) Remove two more nodes and repeat the same validations of proper client
* redistribution. Ensure no clients are connected to the two removed
* nodes.
*
* (3) Remove the first server in the list and simultaneously add the three
* previously removed servers. Ensure everything is redistributed and
* no clients are connected to the one missing node.
*
* (4) Add the one missing server back into the mix and validate.
*/
void testLoadBalancing()
{
zoo_deterministic_conn_order(0);
uint32_t numServers = 9;
const string initial_hosts = createHostList(numServers); // 10.10.10.9:2009...10.10.10.1:2001
// Create connections to servers
for (int i = 0; i < numClients; i++) {
Client &client = createClient(initial_hosts);
numClientsPerHost.at(client.getServerPort() - portOffset - 1)++;
}
for (uint32_t i = 0; i < numServers; i++) {
CPPUNIT_ASSERT(numClientsPerHost.at(i) <= upperboundClientsPerServer(numClients, numServers));
CPPUNIT_ASSERT(numClientsPerHost.at(i) >= lowerboundClientsPerServer(numClients, numServers));
numClientsPerHost.at(i) = 0; // prepare for next test
}
// remove last server
numServers = 8;
updateAllClientsAndServers(numServers);
CPPUNIT_ASSERT_EQUAL((uint32_t)0, numClientsPerHost.at(numServers));
// Remove two more nodes
numServers = 6;
updateAllClientsAndServers(numServers);
CPPUNIT_ASSERT_EQUAL((uint32_t)0, numClientsPerHost.at(numServers));
CPPUNIT_ASSERT_EQUAL((uint32_t)0, numClientsPerHost.at(numServers+1));
CPPUNIT_ASSERT_EQUAL((uint32_t)0, numClientsPerHost.at(numServers+2));
// remove host 0 (first one in list) and add back 6, 7, and 8
numServers = 8;
updateAllClientsAndServers(numServers, 1);
CPPUNIT_ASSERT_EQUAL((uint32_t)0, numClientsPerHost.at(0));
// add back host number 0
numServers = 9;
updateAllClientsAndServers(numServers);
}
/**
* This tests that client can detect server's ipv4 address change.
*
* (1) We generate some address and put in addr, which saddr point to
* (2) Add all addresses that differ by one bit from the source
* (3) Add same address, but set ipv6 protocol
* (4) Ensure, that our address is not equal to any of generated,
* and that it equals to itself
*/
void testAddrVecContainsIPv4() {
addrvec_t vec;
addrvec_init(&vec);
sockaddr_storage addr;
sockaddr_in* saddr = (sockaddr_in*)&addr;
saddr->sin_family = AF_INET;
saddr->sin_port = htons((u_short)1234);
saddr->sin_addr.s_addr = INADDR_ANY;
CPPUNIT_ASSERT(sizeof(saddr->sin_addr.s_addr) == 4);
for (int i = 0; i < 32; i++) {
saddr->sin_addr.s_addr ^= (1 << i);
addrvec_append(&vec, &addr);
saddr->sin_addr.s_addr ^= (1 << i);
}
saddr->sin_family = AF_INET6;
addrvec_append(&vec, &addr);
saddr->sin_family = AF_INET;
CPPUNIT_ASSERT(!addrvec_contains(&vec, &addr));
addrvec_append(&vec, &addr);
CPPUNIT_ASSERT(addrvec_contains(&vec, &addr));
addrvec_free(&vec);
}
/**
* This tests that client can detect server's ipv6 address change.
*
* Same logic as in previous testAddrVecContainsIPv4 method,
* but we keep in mind, that ipv6 is 128-bit long.
*/
#ifdef AF_INET6
void testAddrVecContainsIPv6() {
addrvec_t vec;
addrvec_init(&vec);
sockaddr_storage addr;
sockaddr_in6* saddr = (sockaddr_in6*)&addr;
saddr->sin6_family = AF_INET6;
saddr->sin6_port = htons((u_short)1234);
saddr->sin6_addr = in6addr_any;
CPPUNIT_ASSERT(sizeof(saddr->sin6_addr.s6_addr) == 16);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 8; j++) {
saddr->sin6_addr.s6_addr[i] ^= (1 << j);
addrvec_append(&vec, &addr);
saddr->sin6_addr.s6_addr[i] ^= (1 << j);
}
}
saddr->sin6_family = AF_INET;
addrvec_append(&vec, &addr);
saddr->sin6_family = AF_INET6;
CPPUNIT_ASSERT(!addrvec_contains(&vec, &addr));
addrvec_append(&vec, &addr);
CPPUNIT_ASSERT(addrvec_contains(&vec, &addr));
addrvec_free(&vec);
}
#endif
};
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_reconfig);

View File

@ -0,0 +1,420 @@
/**
* 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 <algorithm>
#include <sstream>
#include <vector>
#include <utility>
#include <cppunit/extensions/HelperMacros.h>
#include <unistd.h>
#include "zookeeper.h"
#include "Util.h"
#include "ZooKeeperQuorumServer.h"
#ifdef THREADED
class TestReconfigServer : public CPPUNIT_NS::TestFixture {
CPPUNIT_TEST_SUITE(TestReconfigServer);
CPPUNIT_TEST(testNonIncremental);
CPPUNIT_TEST(testRemoveConnectedFollower);
CPPUNIT_TEST(testRemoveFollower);
CPPUNIT_TEST(testReconfigFailureWithoutAuth);
CPPUNIT_TEST(testReconfigFailureWithoutServerSuperuserPasswordConfigured);
CPPUNIT_TEST_SUITE_END();
public:
TestReconfigServer();
virtual ~TestReconfigServer();
void setUp();
void tearDown();
void testNonIncremental();
void testRemoveConnectedFollower();
void testRemoveFollower();
void testReconfigFailureWithoutAuth();
void testReconfigFailureWithoutServerSuperuserPasswordConfigured();
private:
static const uint32_t NUM_SERVERS;
FILE* logfile_;
std::vector<ZooKeeperQuorumServer*> cluster_;
int32_t getLeader();
std::vector<int32_t> getFollowers();
void parseConfig(char* buf, int len, std::vector<std::string>& servers,
std::string& version);
bool waitForConnected(zhandle_t* zh, uint32_t timeout_sec);
zhandle_t* connectFollowers(std::vector<int32_t> &followers);
};
const uint32_t TestReconfigServer::NUM_SERVERS = 3;
TestReconfigServer::
TestReconfigServer() :
logfile_(openlogfile("TestReconfigServer")) {
zoo_set_log_stream(logfile_);
}
TestReconfigServer::
~TestReconfigServer() {
if (logfile_) {
fflush(logfile_);
fclose(logfile_);
logfile_ = NULL;
}
}
void TestReconfigServer::
setUp() {
ZooKeeperQuorumServer::tConfigPairs configs;
configs.push_back(std::make_pair("reconfigEnabled", "true"));
cluster_ = ZooKeeperQuorumServer::getCluster(NUM_SERVERS, configs,
"SERVER_JVMFLAGS=-Dzookeeper.DigestAuthenticationProvider.superDigest=super:D/InIHSb7yEEbrWz8b9l71RjZJU="/* password is test */);
}
void TestReconfigServer::
tearDown() {
for (int i = 0; i < cluster_.size(); i++) {
delete cluster_[i];
}
cluster_.clear();
}
int32_t TestReconfigServer::
getLeader() {
for (int32_t i = 0; i < cluster_.size(); i++) {
if (cluster_[i]->isLeader()) {
return i;
}
}
return -1;
}
std::vector<int32_t> TestReconfigServer::
getFollowers() {
std::vector<int32_t> followers;
for (int32_t i = 0; i < cluster_.size(); i++) {
if (cluster_[i]->isFollower()) {
followers.push_back(i);
}
}
return followers;
}
void TestReconfigServer::
parseConfig(char* buf, int len, std::vector<std::string>& servers,
std::string& version) {
std::string config(buf, len);
std::stringstream ss(config);
std::string line;
std::string serverPrefix("server.");
std::string versionPrefix("version=");
servers.clear();
while(std::getline(ss, line, '\n')) {
if (line.compare(0, serverPrefix.size(), serverPrefix) == 0) {
servers.push_back(line);
} else if (line.compare(0, versionPrefix.size(), versionPrefix) == 0) {
version = line.substr(versionPrefix.size());
}
}
}
bool TestReconfigServer::
waitForConnected(zhandle_t* zh, uint32_t timeout_sec) {
for (uint32_t i = 0; i < timeout_sec; i++) {
if (zoo_state(zh) == ZOO_CONNECTED_STATE) {
return true;
}
sleep(1);
}
return false;
}
/**
* 1. Connect to the leader.
* 2. Remove a follower using incremental reconfig.
* 3. Add the follower back using incremental reconfig.
*/
void TestReconfigServer::
testRemoveFollower() {
std::vector<std::string> servers;
std::string version;
struct Stat stat;
int len = 1024;
char buf[len];
// get config from leader.
int32_t leader = getLeader();
CPPUNIT_ASSERT(leader >= 0);
std::string host = cluster_[leader]->getHostPort();
zhandle_t* zk = zookeeper_init(host.c_str(), NULL, 10000, NULL, NULL, 0);
CPPUNIT_ASSERT_EQUAL(true, waitForConnected(zk, 10));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_getconfig(zk, 0, buf, &len, &stat));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_add_auth(zk, "digest", "super:test", 10, NULL,(void*)ZOK));
// check if all the servers are listed in the config.
parseConfig(buf, len, servers, version);
// initially should be 1<<32, which is 0x100000000. This is the zxid
// of the first NEWLEADER message, used as the initial version
CPPUNIT_ASSERT_EQUAL(std::string("100000000"), version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
// remove a follower.
std::vector<int32_t> followers = getFollowers();
len = 1024;
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS - 1,
(uint32_t)(followers.size()));
std::stringstream ss;
ss << followers[0];
int rc = zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len,
&stat);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
parseConfig(buf, len, servers, version);
CPPUNIT_ASSERT_EQUAL(std::string("100000002"), version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS - 1, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
if (i == followers[0]) {
continue;
}
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
// add the follower back.
len = 1024;
std::string serverString = cluster_[followers[0]]->getServerString();
rc = zoo_reconfig(zk, serverString.c_str(), NULL, NULL, -1, buf, &len,
&stat);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
parseConfig(buf, len, servers, version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
zookeeper_close(zk);
}
/**
* 1. Connect to the leader.
* 2. Remove a follower using non-incremental reconfig.
* 3. Add the follower back using non-incremental reconfig.
*/
void TestReconfigServer::
testNonIncremental() {
std::vector<std::string> servers;
std::string version;
struct Stat stat;
int len = 1024;
char buf[len];
// get config from leader.
int32_t leader = getLeader();
CPPUNIT_ASSERT(leader >= 0);
std::string host = cluster_[leader]->getHostPort();
zhandle_t* zk = zookeeper_init(host.c_str(), NULL, 10000, NULL, NULL, 0);
CPPUNIT_ASSERT_EQUAL(true, waitForConnected(zk, 10));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_getconfig(zk, 0, buf, &len, &stat));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_add_auth(zk, "digest", "super:test", 10, NULL,(void*)ZOK));
// check if all the servers are listed in the config.
parseConfig(buf, len, servers, version);
// initially should be 1<<32, which is 0x100000000. This is the zxid
// of the first NEWLEADER message, used as the initial version
CPPUNIT_ASSERT_EQUAL(std::string("100000000"), version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
// remove a follower.
std::vector<int32_t> followers = getFollowers();
len = 1024;
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS - 1,
(uint32_t)(followers.size()));
std::stringstream ss;
for (int i = 1; i < followers.size(); i++) {
ss << cluster_[followers[i]]->getServerString() << ",";
}
ss << cluster_[leader]->getServerString();
int rc = zoo_reconfig(zk, NULL, NULL, ss.str().c_str(), -1, buf, &len,
&stat);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
parseConfig(buf, len, servers, version);
CPPUNIT_ASSERT_EQUAL(std::string("100000002"), version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS - 1, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
if (i == followers[0]) {
continue;
}
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
// add the follower back.
len = 1024;
ss.str("");
for (int i = 0; i < cluster_.size(); i++) {
ss << cluster_[i]->getServerString() << ",";
}
rc = zoo_reconfig(zk, NULL, NULL, ss.str().c_str(), -1, buf, &len,
&stat);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
parseConfig(buf, len, servers, version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
zookeeper_close(zk);
}
zhandle_t* TestReconfigServer::
connectFollowers(std::vector<int32_t> &followers) {
std::stringstream ss;
int32_t leader = getLeader();
CPPUNIT_ASSERT(leader >= 0);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS - 1, (uint32_t)(followers.size()));
for (int i = 0; i < followers.size(); i++) {
ss << cluster_[followers[i]]->getHostPort() << ",";
}
ss << cluster_[leader]->getHostPort();
std::string hosts = ss.str().c_str();
zoo_deterministic_conn_order(true);
zhandle_t* zk = zookeeper_init(hosts.c_str(), NULL, 10000, NULL, NULL, 0);
CPPUNIT_ASSERT_EQUAL(true, waitForConnected(zk, 10));
std::string connectedHost(zoo_get_current_server(zk));
std::string portString = connectedHost.substr(connectedHost.find(":") + 1);
uint32_t port;
std::istringstream (portString) >> port;
CPPUNIT_ASSERT_EQUAL(cluster_[followers[0]]->getClientPort(), port);
return zk;
}
/**
* 1. Connect to a follower.
* 2. Remove the follower the client is connected to.
*/
void TestReconfigServer::
testRemoveConnectedFollower() {
std::vector<std::string> servers;
std::string version;
struct Stat stat;
int len = 1024;
char buf[len];
// connect to a follower.
std::stringstream ss;
std::vector<int32_t> followers = getFollowers();
zhandle_t* zk = connectFollowers(followers);
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_add_auth(zk, "digest", "super:test", 10, NULL,(void*)ZOK));
// remove the follower.
len = 1024;
ss.str("");
ss << followers[0];
zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len, &stat);
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_getconfig(zk, 0, buf, &len, &stat));
parseConfig(buf, len, servers, version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS - 1, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
if (i == followers[0]) {
continue;
}
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
zookeeper_close(zk);
}
/**
* ZOOKEEPER-2014: only admin or users who are explicitly granted permission can do reconfig.
*/
void TestReconfigServer::
testReconfigFailureWithoutAuth() {
std::vector<std::string> servers;
std::string version;
struct Stat stat;
int len = 1024;
char buf[len];
// connect to a follower.
std::stringstream ss;
std::vector<int32_t> followers = getFollowers();
zhandle_t* zk = connectFollowers(followers);
// remove the follower.
len = 1024;
ss.str("");
ss << followers[0];
// No auth, should fail.
CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len, &stat));
// Wrong auth, should fail.
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_add_auth(zk, "digest", "super:wrong", 11, NULL,(void*)ZOK));
CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len, &stat));
// Right auth, should pass.
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_add_auth(zk, "digest", "super:test", 10, NULL,(void*)ZOK));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len, &stat));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_getconfig(zk, 0, buf, &len, &stat));
parseConfig(buf, len, servers, version);
CPPUNIT_ASSERT_EQUAL(NUM_SERVERS - 1, (uint32_t)(servers.size()));
for (int i = 0; i < cluster_.size(); i++) {
if (i == followers[0]) {
continue;
}
CPPUNIT_ASSERT(std::find(servers.begin(), servers.end(),
cluster_[i]->getServerString()) != servers.end());
}
zookeeper_close(zk);
}
void TestReconfigServer::
testReconfigFailureWithoutServerSuperuserPasswordConfigured() {
std::vector<std::string> servers;
std::string version;
struct Stat stat;
int len = 1024;
char buf[len];
// Create a new quorum with the super user's password not configured.
tearDown();
ZooKeeperQuorumServer::tConfigPairs configs;
configs.push_back(std::make_pair("reconfigEnabled", "true"));
cluster_ = ZooKeeperQuorumServer::getCluster(NUM_SERVERS, configs, "");
// connect to a follower.
std::stringstream ss;
std::vector<int32_t> followers = getFollowers();
zhandle_t* zk = connectFollowers(followers);
// remove the follower.
len = 1024;
ss.str("");
ss << followers[0];
// All cases should fail as server ensemble was not configured with the super user's password.
CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len, &stat));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_add_auth(zk, "digest", "super:", 11, NULL,(void*)ZOK));
CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len, &stat));
CPPUNIT_ASSERT_EQUAL((int)ZOK, zoo_add_auth(zk, "digest", "super:test", 10, NULL,(void*)ZOK));
CPPUNIT_ASSERT_EQUAL((int)ZNOAUTH, zoo_reconfig(zk, NULL, ss.str().c_str(), NULL, -1, buf, &len, &stat));
zookeeper_close(zk);
}
CPPUNIT_TEST_SUITE_REGISTRATION(TestReconfigServer);
#endif

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