diff --git a/.classpath b/.classpath
index 9daadee954..009f6148a2 100644
--- a/.classpath
+++ b/.classpath
@@ -9,17 +9,20 @@
+
+
-
+
-
+
+
@@ -40,7 +43,7 @@
-
+
@@ -53,9 +56,13 @@
-
+
+
+
+
+
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
index 038d4674f0..b5553d65f5 100644
--- a/.settings/org.eclipse.jdt.ui.prefs
+++ b/.settings/org.eclipse.jdt.ui.prefs
@@ -1,4 +1,4 @@
-#Tue Jan 13 14:27:58 PST 2009
+#Sat Sep 22 05:05:45 PDT 2012
cleanup.add_default_serial_version_id=true
cleanup.add_generated_serial_version_id=false
cleanup.add_missing_annotations=true
diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF
index 86ad47e2ea..08a19d78e9 100644
--- a/META-INF/MANIFEST.MF
+++ b/META-INF/MANIFEST.MF
@@ -1,7 +1,8 @@
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 20.2-b06 (Sun Microsystems Inc.)
+Voldemort-Implementation-Version: 1.3.0
Implementation-Title: Voldemort
-Implementation-Version: 0.96
+Implementation-Version: 1.3.0
Implementation-Vendor: LinkedIn
diff --git a/bin/PREUPGRADE_FOR_1_1_X_README b/bin/PREUPGRADE_FOR_1_1_X_README
new file mode 100644
index 0000000000..2cde462b4e
--- /dev/null
+++ b/bin/PREUPGRADE_FOR_1_1_X_README
@@ -0,0 +1,110 @@
+This directory contains utility to convert BDB JE data between different versions of Voldemort.
+
+Need for Conversion
+-------------------
+Voldemort has been using "sorted duplicates" feature of BDB JE to handle
+conflicting writes to the same key. At the very minimum, the conversion gets
+rid of BDB sorted duplicates support and handles duplicates in the Voldemort
+storage layer itself. The decision was made after months of closely working
+with Oracle JE team, to understand the factors affecting performance.
+
+Data Formats
+------------
+This section describes the data formats themselves.
+
+1) Base Format (Base)
+---------------------
+This is the format used by Voldemort up until 1.1.x, relying on BDB JE for
+duplicate handling
+
+Disadvantages:
+-- The manner in which BDB JE handles duplicates is not suitable for an
+ application with small percent of 2-3 duplicates i.e Voldemort.
+-- Data bloat issue that prevented us from migrating to any higher 4.x version
+ to be able to control cache eviction
+-- Incompatible with how duplicates are handled in JE5.
+-- May incur additional locking costs for the "duplicates" subtree
+
+2) New duplicate format (NewDup)
+--------------------------------
+This format is supported from release 1.1.x, where Voldemort storage layer
+handles duplicates and BDB JE version is bumped up to JE 4.1.17
+
+Advantages:
+-- Ability to move data off disk. This is very GC friendly, relying on OS page
+ cache for the data and using the JVM heap only for index. This is achieved
+ by setting "bdb.cache.evictln" server parameter to "true"
+-- Ability to evict data brought into the cache during scans, minimize impact
+ on online traffic (Restore, Rebalance, Retention). This is achieved by
+ setting "bdb.minimize.scan.impact" to "true"
+-- Thinner storage layer. eg: BdbStorageEngine.put() does not incur the cost
+ of an additional delete()
+-- General speed up due to elimination of duplicates
+
+This format is the minimum requirement to be able to upgrade to 1.1.x & higher
+
+3) Partition Scan format (PidScan)
+----------------------------------
+This is a super set of 'NewDup' format, supported 1.1.x upwards. In addition to
+eliminating duplicates and upgrading to JE 4.1.17, it adds a 2 byte prefix
+representing the partition id to each key.
+
+Advantages:
+-- Speed up Restore and Rebalancing linearly to the number of partitions
+ actually fetched. (which means much shorter degraded mode performance)
+
+This is an optional format. You can turn it off, by setting
+bdb.prefix.keys.with.partitionid=false, if you don't like for some reason
+
+Note : We have not seen the extra 2 bytes cause any overhead to online
+performance
+
+IMPORTANT: IT IS REQUIRED TO CONVERT TO EITHER 'NewDup' or 'PidScan' TO RUN
+VOLDEMORT WITH BDB, STARTING RELEASE 1.1.x
+
+Running the Conversion Utility
+------------------------------
+The tool provides the ability to convert one database from a source environment
+to a destination environment. You need to run the tool for each of the databases
+or voldemort store you have. You can bring one Voldemort server at a time and
+perform the conversion and bring it up on the appropriate release
+
+Note: For users running with "bdb.one.env.per.store=false", it means you will
+have to run the tool with the same --src --dest options for each database
+contained.
+
+In addition to BDB environment locations, the tool needs the cluster.xml to generate
+the partition prefix.
+
+$./voldemort-convert-bdb.sh --src
+ --dest
+ --store
+ --cluster-xml
+ --from-format
+ --to-format
+ --je-log-size
+ --btree-nodemax
+
+We recommend you run the following to move to release 1.1.x & up.
+
+$./voldemort-convert-bdb.sh --src /path/to/src/env
+ --dest /path/to/dest/env
+ --store teststore
+ --cluster-xml /path/to/cluster/xml
+ --from-format Base
+ --to-format PidScan
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/generate_cluster_xml.py b/bin/generate_cluster_xml.py
index 1811fdd2fc..8160988580 100644
--- a/bin/generate_cluster_xml.py
+++ b/bin/generate_cluster_xml.py
@@ -10,6 +10,8 @@
# Setup and argument parser
parser = argparse.ArgumentParser(description='Build a voldemort cluster.xml.')
# Add supported arguments
+parser.add_argument('-f', '--file', type=str, dest='file',
+ help='the file of the list of hosts(one per line)')
parser.add_argument('-N', '--name', type=str, default='voldemort', dest='name',
help='the name you want to give the cluster')
parser.add_argument('-n', '--nodes', type=int, default=2, dest='nodes',
@@ -44,7 +46,11 @@
sys.exit(1)
# Store arguments
-nodes = args.nodes
+if args.file:
+ hostList = open(args.file).readlines()
+ nodes = len(hostList)
+else:
+ nodes = args.nodes
partitions = args.partitions
name = args.name
http_port = args.http_port
@@ -73,7 +79,10 @@
print " "
print " %d" % i
- print " host%d" % i
+ if args.file:
+ print " %s" % hostList[i].strip()
+ else:
+ print " host%d" % i
print " %d" % http_port
print " %d" % sock_port
print " %d" % admin_port
diff --git a/bin/run-class.bat b/bin/run-class.bat
new file mode 100644
index 0000000000..b0e3618df0
--- /dev/null
+++ b/bin/run-class.bat
@@ -0,0 +1,46 @@
+@echo off
+
+REM
+REM Copyright 2013 Carlos Tasada
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM 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.
+REM
+REM ** This Windows BAT file is not tested with each Voldemort release. **
+
+set argC=0
+for %%a in (%*) do set /a argC+=1
+if %argC% geq 1 goto :continue
+echo %0 java-class-name [options]
+goto :eof
+:continue
+
+SET BASE_DIR=%~dp0..
+SET CLASSPATH=.
+
+set VOLDEMORT_CONFIG_DIR=%1%/config
+
+for %%j in ("%BASE_DIR%\dist\*.jar") do (call :append_classpath "%%j")
+for %%j in ("%BASE_DIR%\lib\*.jar") do (call :append_classpath "%%j")
+set CLASSPATH=%CLASSPATH%;"%BASE_DIR%\dist\resources"
+goto :run
+
+:append_classpath
+set CLASSPATH=%CLASSPATH%;%1
+goto :eof
+
+:run
+if "%VOLD_OPTS%" == "" set "VOLD_OPTS=-Xmx2G -server -Dcom.sun.management.jmxremote"
+java -Dlog4j.configuration=%VOLDEMORT_CONFIG_DIR%\log4j.properties %VOLD_OPTS% -cp %CLASSPATH% %*
+
+endlocal
+:eof
\ No newline at end of file
diff --git a/bin/run-class.sh b/bin/run-class.sh
index f0d1fbe391..465637dd4a 100755
--- a/bin/run-class.sh
+++ b/bin/run-class.sh
@@ -1,7 +1,7 @@
#!/bin/bash
#
-# Copyright 2008-2009 LinkedIn, Inc
+# Copyright 2008-2013 LinkedIn, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -21,7 +21,10 @@ if [ $# -lt 1 ]; then
exit 1
fi
-base_dir=$(dirname $0)/..
+script_path=$(readlink -f "$0")
+script_dir=`dirname "$script_path"`
+
+base_dir=`dirname "$script_dir"`
for file in $base_dir/lib/*.jar;
do
@@ -43,5 +46,8 @@ if [ -z "$VOLD_OPTS" ]; then
VOLD_OPTS="-Xmx2G -server -Dcom.sun.management.jmxremote "
fi
+# add '-Dlog4j.debug ' to debug log4j issues.
+LOG4JPROPERTIES="-Dlog4j.configuration=file:///${base_dir}/src/java/log4j.properties"
+
export CLASSPATH
-java -Dlog4j.configuration=$base_dir/src/java/log4j.properties $VOLD_OPTS -cp $CLASSPATH $@
+java $LOG4JPROPERTIES $VOLD_OPTS -cp $CLASSPATH $@
diff --git a/bin/voldemort-admin-tool.bat b/bin/voldemort-admin-tool.bat
new file mode 100644
index 0000000000..9629277257
--- /dev/null
+++ b/bin/voldemort-admin-tool.bat
@@ -0,0 +1,22 @@
+@echo off
+
+REM
+REM Copyright 2013 Carlos Tasada
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM 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.
+REM
+REM ** This Windows BAT file is not tested with each Voldemort release. **
+
+SET BASE_DIR=%~dp0..
+
+call "%BASE_DIR%/bin/run-class.bat" voldemort.VoldemortAdminTool %*
\ No newline at end of file
diff --git a/bin/voldemort-convert-bdb.sh b/bin/voldemort-convert-bdb.sh
new file mode 100755
index 0000000000..52af1efd09
--- /dev/null
+++ b/bin/voldemort-convert-bdb.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# Copyright 2008-2012 LinkedIn, Inc
+#
+# 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.
+#
+
+base_dir=$(dirname $0)/..
+
+for file in $base_dir/dist/*.jar;
+do
+ CLASSPATH=$CLASSPATH:$file
+done
+
+for file in $base_dir/lib/*.jar;
+do
+ CLASSPATH=$CLASSPATH:$file
+done
+
+for file in $base_dir/contrib/*/lib/*.jar;
+do
+ CLASSPATH=$CLASSPATH:$file
+done
+
+CLASSPATH=$CLASSPATH:$base_dir/dist/resources
+
+JVM_OPTS="-server -Xms5g -Xmx5g -XX:NewSize=1024m -XX:MaxNewSize=1024m -XX:+AlwaysPreTouch -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=70 -XX:SurvivorRatio=2"
+
+java -Dlog4j.configuration=src/java/log4j.properties $JVM_OPTS -cp $CLASSPATH voldemort.store.bdb.dataconversion.BdbConvertData $@
diff --git a/bin/voldemort-performance-tool.bat b/bin/voldemort-performance-tool.bat
new file mode 100644
index 0000000000..bb401c1509
--- /dev/null
+++ b/bin/voldemort-performance-tool.bat
@@ -0,0 +1,22 @@
+@echo off
+
+REM
+REM Copyright 2013 Carlos Tasada
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM 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.
+REM
+REM ** This Windows BAT file is not tested with each Voldemort release. **
+
+SET BASE_DIR=%~dp0..
+
+call "%BASE_DIR%/bin/run-class.bat" voldemort.performance.benchmark.Benchmark %*
\ No newline at end of file
diff --git a/bin/voldemort-rebalance.bat b/bin/voldemort-rebalance.bat
new file mode 100644
index 0000000000..7c918de15c
--- /dev/null
+++ b/bin/voldemort-rebalance.bat
@@ -0,0 +1,22 @@
+@echo off
+
+REM
+REM Copyright 2013 Carlos Tasada
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM 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.
+REM
+REM ** This Windows BAT file is not tested with each Voldemort release. **
+
+SET BASE_DIR=%~dp0..
+
+call "%BASE_DIR%/bin/run-class.bat" voldemort.client.rebalance.RebalanceCLI %*
\ No newline at end of file
diff --git a/bin/voldemort-server.bat b/bin/voldemort-server.bat
new file mode 100644
index 0000000000..e4dd896057
--- /dev/null
+++ b/bin/voldemort-server.bat
@@ -0,0 +1,49 @@
+@echo off
+
+REM
+REM Copyright 2013 Carlos Tasada
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM 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.
+REM
+REM ** This Windows BAT file is not tested with each Voldemort release. **
+
+set argC=0
+for %%a in (%*) do set /a argC+=1
+if %argC% leq 2 goto :continue
+echo USAGE: bin/voldemort-server.bat [voldemort_home_dir] [voldemort_config_dir]
+goto :eof
+:continue
+
+setlocal
+
+SET BASE_DIR=%~dp0..
+SET CLASSPATH=.
+
+set VOLDEMORT_CONFIG_DIR=%1%/config
+rem call %VOLDEMORT_CONFIG_DIR%/voldemort-env.bat
+
+for %%j in ("%BASE_DIR%\dist\*.jar") do (call :append_classpath "%%j")
+for %%j in ("%BASE_DIR%\lib\*.jar") do (call :append_classpath "%%j")
+set CLASSPATH=%CLASSPATH%:"%BASE_DIR%\dist\resources"
+goto :run
+
+:append_classpath
+set CLASSPATH=%CLASSPATH%;%1
+goto :eof
+
+:run
+if "%VOLD_OPTS%" == "" set "VOLD_OPTS=-Xmx2G -server -Dcom.sun.management.jmxremote"
+java %VOLD_OPTS% -cp %CLASSPATH% voldemort.server.VoldemortServer %*
+
+endlocal
+:eof
\ No newline at end of file
diff --git a/bin/voldemort-shell.bat b/bin/voldemort-shell.bat
new file mode 100644
index 0000000000..3300cef41d
--- /dev/null
+++ b/bin/voldemort-shell.bat
@@ -0,0 +1,34 @@
+@echo off
+
+REM
+REM Copyright 2013 Carlos Tasada
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM 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.
+REM
+REM ** This Windows BAT file is not tested with each Voldemort release. **
+
+set argC=0
+for %%a in (%*) do set /a argC+=1
+if %argC% geq 2 goto :continue
+echo "USAGE: bin/voldemort-shell.bat store_name bootstrap_url [command_file] [--client-zone-id ]"
+goto :eof
+:continue
+
+setlocal
+SET BASE_DIR=%~dp0..
+
+call "%BASE_DIR%\bin\run-class.bat" jline.ConsoleRunner voldemort.VoldemortClientShell %*
+
+endlocal
+
+:eof
\ No newline at end of file
diff --git a/build.properties b/build.properties
index 2bc92bcf07..d851cb378b 100644
--- a/build.properties
+++ b/build.properties
@@ -42,4 +42,5 @@ tomcat.context=/voldemort
javac.version=1.5
## Release
-curr.release=1.0.0
+curr.release=1.3.1
+
diff --git a/build.xml b/build.xml
index daefcc5334..88158310c2 100644
--- a/build.xml
+++ b/build.xml
@@ -79,7 +79,9 @@
-
+
+
+
@@ -122,6 +124,12 @@
+
-
+
@@ -149,8 +158,9 @@
+
-
+
@@ -422,7 +432,7 @@
-
+
diff --git a/clients/python/voldemort/protocol/voldemort_admin_pb2.py b/clients/python/voldemort/protocol/voldemort_admin_pb2.py
index 008ac0cda0..08937e79ba 100644
--- a/clients/python/voldemort/protocol/voldemort_admin_pb2.py
+++ b/clients/python/voldemort/protocol/voldemort_admin_pb2.py
@@ -10,7 +10,7 @@
DESCRIPTOR = descriptor.FileDescriptor(
name='voldemort-admin.proto',
package='voldemort',
- serialized_pb='\n\x15voldemort-admin.proto\x12\tvoldemort\x1a\x16voldemort-client.proto\"!\n\x12GetMetadataRequest\x12\x0b\n\x03key\x18\x01 \x02(\x0c\"]\n\x13GetMetadataResponse\x12%\n\x07version\x18\x01 \x01(\x0b\x32\x14.voldemort.Versioned\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"M\n\x15UpdateMetadataRequest\x12\x0b\n\x03key\x18\x01 \x02(\x0c\x12\'\n\tversioned\x18\x02 \x02(\x0b\x32\x14.voldemort.Versioned\"9\n\x16UpdateMetadataResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"7\n\tFileEntry\x12\x11\n\tfile_name\x18\x01 \x02(\t\x12\x17\n\x0f\x66ile_size_bytes\x18\x02 \x02(\x03\"F\n\x0ePartitionEntry\x12\x0b\n\x03key\x18\x01 \x02(\x0c\x12\'\n\tversioned\x18\x02 \x02(\x0b\x32\x14.voldemort.Versioned\"\x8e\x01\n\x1dUpdatePartitionEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x32\n\x0fpartition_entry\x18\x02 \x02(\x0b\x32\x19.voldemort.PartitionEntry\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\"A\n\x1eUpdatePartitionEntriesResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"-\n\x0fVoldemortFilter\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\"\xaf\x01\n\x18UpdateSlopEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x0b\n\x03key\x18\x02 \x02(\x0c\x12\'\n\x07version\x18\x03 \x02(\x0b\x32\x16.voldemort.VectorClock\x12,\n\x0crequest_type\x18\x04 \x02(\x0e\x32\x16.voldemort.RequestType\x12\r\n\x05value\x18\x05 \x01(\x0c\x12\x11\n\ttransform\x18\x06 \x01(\x0c\"<\n\x19UpdateSlopEntriesResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"d\n\x1a\x46\x65tchPartitionFilesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x37\n\x14replica_to_partition\x18\x02 \x03(\x0b\x32\x19.voldemort.PartitionTuple\"\xd7\x01\n\x1c\x46\x65tchPartitionEntriesRequest\x12\x37\n\x14replica_to_partition\x18\x01 \x03(\x0b\x32\x19.voldemort.PartitionTuple\x12\r\n\x05store\x18\x02 \x02(\t\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\x12\x14\n\x0c\x66\x65tch_values\x18\x04 \x01(\x08\x12\x14\n\x0cskip_records\x18\x05 \x01(\x03\x12\x17\n\x0finitial_cluster\x18\x06 \x01(\t\"\x81\x01\n\x1d\x46\x65tchPartitionEntriesResponse\x12\x32\n\x0fpartition_entry\x18\x01 \x01(\x0b\x32\x19.voldemort.PartitionEntry\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x1f\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x10.voldemort.Error\"\xac\x01\n\x1d\x44\x65letePartitionEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x37\n\x14replica_to_partition\x18\x02 \x03(\x0b\x32\x19.voldemort.PartitionTuple\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\x12\x17\n\x0finitial_cluster\x18\x04 \x01(\t\"P\n\x1e\x44\x65letePartitionEntriesResponse\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"\xcf\x01\n\x1dInitiateFetchAndUpdateRequest\x12\x0f\n\x07node_id\x18\x01 \x02(\x05\x12\r\n\x05store\x18\x02 \x02(\t\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\x12\x37\n\x14replica_to_partition\x18\x04 \x03(\x0b\x32\x19.voldemort.PartitionTuple\x12\x17\n\x0finitial_cluster\x18\x05 \x01(\t\x12\x10\n\x08optimize\x18\x06 \x01(\x08\"1\n\x1b\x41syncOperationStatusRequest\x12\x12\n\nrequest_id\x18\x01 \x02(\x05\"/\n\x19\x41syncOperationStopRequest\x12\x12\n\nrequest_id\x18\x01 \x02(\x05\"=\n\x1a\x41syncOperationStopResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"2\n\x19\x41syncOperationListRequest\x12\x15\n\rshow_complete\x18\x02 \x02(\x08\"R\n\x1a\x41syncOperationListResponse\x12\x13\n\x0brequest_ids\x18\x01 \x03(\x05\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\":\n\x0ePartitionTuple\x12\x14\n\x0creplica_type\x18\x01 \x02(\x05\x12\x12\n\npartitions\x18\x02 \x03(\x05\"e\n\x16PerStorePartitionTuple\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x37\n\x14replica_to_partition\x18\x02 \x03(\x0b\x32\x19.voldemort.PartitionTuple\"\xf8\x01\n\x19RebalancePartitionInfoMap\x12\x12\n\nstealer_id\x18\x01 \x02(\x05\x12\x10\n\x08\x64onor_id\x18\x02 \x02(\x05\x12\x0f\n\x07\x61ttempt\x18\x03 \x02(\x05\x12\x43\n\x18replica_to_add_partition\x18\x04 \x03(\x0b\x32!.voldemort.PerStorePartitionTuple\x12\x46\n\x1breplica_to_delete_partition\x18\x05 \x03(\x0b\x32!.voldemort.PerStorePartitionTuple\x12\x17\n\x0finitial_cluster\x18\x06 \x02(\t\"f\n\x1cInitiateRebalanceNodeRequest\x12\x46\n\x18rebalance_partition_info\x18\x01 \x02(\x0b\x32$.voldemort.RebalancePartitionInfoMap\"m\n#InitiateRebalanceNodeOnDonorRequest\x12\x46\n\x18rebalance_partition_info\x18\x01 \x03(\x0b\x32$.voldemort.RebalancePartitionInfoMap\"\x8a\x01\n\x1c\x41syncOperationStatusResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\x05\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x10\n\x08\x63omplete\x18\x04 \x01(\x08\x12\x1f\n\x05\x65rror\x18\x05 \x01(\x0b\x32\x10.voldemort.Error\"\'\n\x16TruncateEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\":\n\x17TruncateEntriesResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"*\n\x0f\x41\x64\x64StoreRequest\x12\x17\n\x0fstoreDefinition\x18\x01 \x02(\t\"3\n\x10\x41\x64\x64StoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"\'\n\x12\x44\x65leteStoreRequest\x12\x11\n\tstoreName\x18\x01 \x02(\t\"6\n\x13\x44\x65leteStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"P\n\x11\x46\x65tchStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\x12\x14\n\x0cpush_version\x18\x03 \x01(\x03\"9\n\x10SwapStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\"P\n\x11SwapStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\x12\x1a\n\x12previous_store_dir\x18\x02 \x01(\t\"@\n\x14RollbackStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x14\n\x0cpush_version\x18\x02 \x02(\x03\"8\n\x15RollbackStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"&\n\x10RepairJobRequest\x12\x12\n\nstore_name\x18\x01 \x01(\t\"4\n\x11RepairJobResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"=\n\x14ROStoreVersionDirMap\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\"/\n\x19GetROMaxVersionDirRequest\x12\x12\n\nstore_name\x18\x01 \x03(\t\"y\n\x1aGetROMaxVersionDirResponse\x12:\n\x11ro_store_versions\x18\x01 \x03(\x0b\x32\x1f.voldemort.ROStoreVersionDirMap\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"3\n\x1dGetROCurrentVersionDirRequest\x12\x12\n\nstore_name\x18\x01 \x03(\t\"}\n\x1eGetROCurrentVersionDirResponse\x12:\n\x11ro_store_versions\x18\x01 \x03(\x0b\x32\x1f.voldemort.ROStoreVersionDirMap\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"/\n\x19GetROStorageFormatRequest\x12\x12\n\nstore_name\x18\x01 \x03(\t\"y\n\x1aGetROStorageFormatResponse\x12:\n\x11ro_store_versions\x18\x01 \x03(\x0b\x32\x1f.voldemort.ROStoreVersionDirMap\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"@\n\x17\x46\x61iledFetchStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\";\n\x18\x46\x61iledFetchStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"\xe6\x01\n\x1bRebalanceStateChangeRequest\x12K\n\x1drebalance_partition_info_list\x18\x01 \x03(\x0b\x32$.voldemort.RebalancePartitionInfoMap\x12\x16\n\x0e\x63luster_string\x18\x02 \x02(\t\x12\x0f\n\x07swap_ro\x18\x03 \x02(\x08\x12\x1f\n\x17\x63hange_cluster_metadata\x18\x04 \x02(\x08\x12\x1e\n\x16\x63hange_rebalance_state\x18\x05 \x02(\x08\x12\x10\n\x08rollback\x18\x06 \x02(\x08\"?\n\x1cRebalanceStateChangeResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"G\n DeleteStoreRebalanceStateRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x0f\n\x07node_id\x18\x02 \x02(\x05\"D\n!DeleteStoreRebalanceStateResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"h\n\x13NativeBackupRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x12\n\nbackup_dir\x18\x02 \x02(\t\x12\x14\n\x0cverify_files\x18\x03 \x02(\x08\x12\x13\n\x0bincremental\x18\x04 \x02(\x08\">\n\x14ReserveMemoryRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x12\n\nsize_in_mb\x18\x02 \x02(\x03\"8\n\x15ReserveMemoryResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"\xf0\x0e\n\x15VoldemortAdminRequest\x12)\n\x04type\x18\x01 \x02(\x0e\x32\x1b.voldemort.AdminRequestType\x12\x33\n\x0cget_metadata\x18\x02 \x01(\x0b\x32\x1d.voldemort.GetMetadataRequest\x12\x39\n\x0fupdate_metadata\x18\x03 \x01(\x0b\x32 .voldemort.UpdateMetadataRequest\x12J\n\x18update_partition_entries\x18\x04 \x01(\x0b\x32(.voldemort.UpdatePartitionEntriesRequest\x12H\n\x17\x66\x65tch_partition_entries\x18\x05 \x01(\x0b\x32\'.voldemort.FetchPartitionEntriesRequest\x12J\n\x18\x64\x65lete_partition_entries\x18\x06 \x01(\x0b\x32(.voldemort.DeletePartitionEntriesRequest\x12K\n\x19initiate_fetch_and_update\x18\x07 \x01(\x0b\x32(.voldemort.InitiateFetchAndUpdateRequest\x12\x46\n\x16\x61sync_operation_status\x18\x08 \x01(\x0b\x32&.voldemort.AsyncOperationStatusRequest\x12H\n\x17initiate_rebalance_node\x18\t \x01(\x0b\x32\'.voldemort.InitiateRebalanceNodeRequest\x12\x42\n\x14\x61sync_operation_stop\x18\n \x01(\x0b\x32$.voldemort.AsyncOperationStopRequest\x12\x42\n\x14\x61sync_operation_list\x18\x0b \x01(\x0b\x32$.voldemort.AsyncOperationListRequest\x12;\n\x10truncate_entries\x18\x0c \x01(\x0b\x32!.voldemort.TruncateEntriesRequest\x12-\n\tadd_store\x18\r \x01(\x0b\x32\x1a.voldemort.AddStoreRequest\x12\x33\n\x0c\x64\x65lete_store\x18\x0e \x01(\x0b\x32\x1d.voldemort.DeleteStoreRequest\x12\x31\n\x0b\x66\x65tch_store\x18\x0f \x01(\x0b\x32\x1c.voldemort.FetchStoreRequest\x12/\n\nswap_store\x18\x10 \x01(\x0b\x32\x1b.voldemort.SwapStoreRequest\x12\x37\n\x0erollback_store\x18\x11 \x01(\x0b\x32\x1f.voldemort.RollbackStoreRequest\x12\x44\n\x16get_ro_max_version_dir\x18\x12 \x01(\x0b\x32$.voldemort.GetROMaxVersionDirRequest\x12L\n\x1aget_ro_current_version_dir\x18\x13 \x01(\x0b\x32(.voldemort.GetROCurrentVersionDirRequest\x12\x44\n\x15\x66\x65tch_partition_files\x18\x14 \x01(\x0b\x32%.voldemort.FetchPartitionFilesRequest\x12@\n\x13update_slop_entries\x18\x16 \x01(\x0b\x32#.voldemort.UpdateSlopEntriesRequest\x12>\n\x12\x66\x61iled_fetch_store\x18\x18 \x01(\x0b\x32\".voldemort.FailedFetchStoreRequest\x12\x43\n\x15get_ro_storage_format\x18\x19 \x01(\x0b\x32$.voldemort.GetROStorageFormatRequest\x12\x46\n\x16rebalance_state_change\x18\x1a \x01(\x0b\x32&.voldemort.RebalanceStateChangeRequest\x12/\n\nrepair_job\x18\x1b \x01(\x0b\x32\x1b.voldemort.RepairJobRequest\x12X\n initiate_rebalance_node_on_donor\x18\x1c \x01(\x0b\x32..voldemort.InitiateRebalanceNodeOnDonorRequest\x12Q\n\x1c\x64\x65lete_store_rebalance_state\x18\x1d \x01(\x0b\x32+.voldemort.DeleteStoreRebalanceStateRequest\x12\x35\n\rnative_backup\x18\x1e \x01(\x0b\x32\x1e.voldemort.NativeBackupRequest\x12\x37\n\x0ereserve_memory\x18\x1f \x01(\x0b\x32\x1f.voldemort.ReserveMemoryRequest*\xc8\x05\n\x10\x41\x64minRequestType\x12\x10\n\x0cGET_METADATA\x10\x00\x12\x13\n\x0fUPDATE_METADATA\x10\x01\x12\x1c\n\x18UPDATE_PARTITION_ENTRIES\x10\x02\x12\x1b\n\x17\x46\x45TCH_PARTITION_ENTRIES\x10\x03\x12\x1c\n\x18\x44\x45LETE_PARTITION_ENTRIES\x10\x04\x12\x1d\n\x19INITIATE_FETCH_AND_UPDATE\x10\x05\x12\x1a\n\x16\x41SYNC_OPERATION_STATUS\x10\x06\x12\x1b\n\x17INITIATE_REBALANCE_NODE\x10\x07\x12\x18\n\x14\x41SYNC_OPERATION_STOP\x10\x08\x12\x18\n\x14\x41SYNC_OPERATION_LIST\x10\t\x12\x14\n\x10TRUNCATE_ENTRIES\x10\n\x12\r\n\tADD_STORE\x10\x0b\x12\x10\n\x0c\x44\x45LETE_STORE\x10\x0c\x12\x0f\n\x0b\x46\x45TCH_STORE\x10\r\x12\x0e\n\nSWAP_STORE\x10\x0e\x12\x12\n\x0eROLLBACK_STORE\x10\x0f\x12\x1a\n\x16GET_RO_MAX_VERSION_DIR\x10\x10\x12\x1e\n\x1aGET_RO_CURRENT_VERSION_DIR\x10\x11\x12\x19\n\x15\x46\x45TCH_PARTITION_FILES\x10\x12\x12\x17\n\x13UPDATE_SLOP_ENTRIES\x10\x14\x12\x16\n\x12\x46\x41ILED_FETCH_STORE\x10\x16\x12\x19\n\x15GET_RO_STORAGE_FORMAT\x10\x17\x12\x1a\n\x16REBALANCE_STATE_CHANGE\x10\x18\x12\x0e\n\nREPAIR_JOB\x10\x19\x12$\n INITIATE_REBALANCE_NODE_ON_DONOR\x10\x1a\x12 \n\x1c\x44\x45LETE_STORE_REBALANCE_STATE\x10\x1b\x12\x11\n\rNATIVE_BACKUP\x10\x1c\x12\x12\n\x0eRESERVE_MEMORY\x10\x1d\x42-\n\x1cvoldemort.client.protocol.pbB\x0bVAdminProtoH\x01')
+ serialized_pb='\n\x15voldemort-admin.proto\x12\tvoldemort\x1a\x16voldemort-client.proto\"!\n\x12GetMetadataRequest\x12\x0b\n\x03key\x18\x01 \x02(\x0c\"]\n\x13GetMetadataResponse\x12%\n\x07version\x18\x01 \x01(\x0b\x32\x14.voldemort.Versioned\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"M\n\x15UpdateMetadataRequest\x12\x0b\n\x03key\x18\x01 \x02(\x0c\x12\'\n\tversioned\x18\x02 \x02(\x0b\x32\x14.voldemort.Versioned\"9\n\x16UpdateMetadataResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"7\n\tFileEntry\x12\x11\n\tfile_name\x18\x01 \x02(\t\x12\x17\n\x0f\x66ile_size_bytes\x18\x02 \x02(\x03\"F\n\x0ePartitionEntry\x12\x0b\n\x03key\x18\x01 \x02(\x0c\x12\'\n\tversioned\x18\x02 \x02(\x0b\x32\x14.voldemort.Versioned\"\x8e\x01\n\x1dUpdatePartitionEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x32\n\x0fpartition_entry\x18\x02 \x02(\x0b\x32\x19.voldemort.PartitionEntry\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\"A\n\x1eUpdatePartitionEntriesResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"-\n\x0fVoldemortFilter\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\"\xaf\x01\n\x18UpdateSlopEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x0b\n\x03key\x18\x02 \x02(\x0c\x12\'\n\x07version\x18\x03 \x02(\x0b\x32\x16.voldemort.VectorClock\x12,\n\x0crequest_type\x18\x04 \x02(\x0e\x32\x16.voldemort.RequestType\x12\r\n\x05value\x18\x05 \x01(\x0c\x12\x11\n\ttransform\x18\x06 \x01(\x0c\"<\n\x19UpdateSlopEntriesResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"d\n\x1a\x46\x65tchPartitionFilesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x37\n\x14replica_to_partition\x18\x02 \x03(\x0b\x32\x19.voldemort.PartitionTuple\"\xef\x01\n\x1c\x46\x65tchPartitionEntriesRequest\x12\x37\n\x14replica_to_partition\x18\x01 \x03(\x0b\x32\x19.voldemort.PartitionTuple\x12\r\n\x05store\x18\x02 \x02(\t\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\x12\x14\n\x0c\x66\x65tch_values\x18\x04 \x01(\x08\x12\x14\n\x0cskip_records\x18\x05 \x01(\x03\x12\x17\n\x0finitial_cluster\x18\x06 \x01(\t\x12\x16\n\x0e\x66\x65tch_orphaned\x18\x07 \x01(\x08\"\x81\x01\n\x1d\x46\x65tchPartitionEntriesResponse\x12\x32\n\x0fpartition_entry\x18\x01 \x01(\x0b\x32\x19.voldemort.PartitionEntry\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x1f\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x10.voldemort.Error\"\xac\x01\n\x1d\x44\x65letePartitionEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\x12\x37\n\x14replica_to_partition\x18\x02 \x03(\x0b\x32\x19.voldemort.PartitionTuple\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\x12\x17\n\x0finitial_cluster\x18\x04 \x01(\t\"P\n\x1e\x44\x65letePartitionEntriesResponse\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"\xcf\x01\n\x1dInitiateFetchAndUpdateRequest\x12\x0f\n\x07node_id\x18\x01 \x02(\x05\x12\r\n\x05store\x18\x02 \x02(\t\x12*\n\x06\x66ilter\x18\x03 \x01(\x0b\x32\x1a.voldemort.VoldemortFilter\x12\x37\n\x14replica_to_partition\x18\x04 \x03(\x0b\x32\x19.voldemort.PartitionTuple\x12\x17\n\x0finitial_cluster\x18\x05 \x01(\t\x12\x10\n\x08optimize\x18\x06 \x01(\x08\"1\n\x1b\x41syncOperationStatusRequest\x12\x12\n\nrequest_id\x18\x01 \x02(\x05\"/\n\x19\x41syncOperationStopRequest\x12\x12\n\nrequest_id\x18\x01 \x02(\x05\"=\n\x1a\x41syncOperationStopResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"2\n\x19\x41syncOperationListRequest\x12\x15\n\rshow_complete\x18\x02 \x02(\x08\"R\n\x1a\x41syncOperationListResponse\x12\x13\n\x0brequest_ids\x18\x01 \x03(\x05\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\":\n\x0ePartitionTuple\x12\x14\n\x0creplica_type\x18\x01 \x02(\x05\x12\x12\n\npartitions\x18\x02 \x03(\x05\"e\n\x16PerStorePartitionTuple\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x37\n\x14replica_to_partition\x18\x02 \x03(\x0b\x32\x19.voldemort.PartitionTuple\"\xf8\x01\n\x19RebalancePartitionInfoMap\x12\x12\n\nstealer_id\x18\x01 \x02(\x05\x12\x10\n\x08\x64onor_id\x18\x02 \x02(\x05\x12\x0f\n\x07\x61ttempt\x18\x03 \x02(\x05\x12\x43\n\x18replica_to_add_partition\x18\x04 \x03(\x0b\x32!.voldemort.PerStorePartitionTuple\x12\x46\n\x1breplica_to_delete_partition\x18\x05 \x03(\x0b\x32!.voldemort.PerStorePartitionTuple\x12\x17\n\x0finitial_cluster\x18\x06 \x02(\t\"f\n\x1cInitiateRebalanceNodeRequest\x12\x46\n\x18rebalance_partition_info\x18\x01 \x02(\x0b\x32$.voldemort.RebalancePartitionInfoMap\"m\n#InitiateRebalanceNodeOnDonorRequest\x12\x46\n\x18rebalance_partition_info\x18\x01 \x03(\x0b\x32$.voldemort.RebalancePartitionInfoMap\"\x8a\x01\n\x1c\x41syncOperationStatusResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\x05\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x10\n\x08\x63omplete\x18\x04 \x01(\x08\x12\x1f\n\x05\x65rror\x18\x05 \x01(\x0b\x32\x10.voldemort.Error\"\'\n\x16TruncateEntriesRequest\x12\r\n\x05store\x18\x01 \x02(\t\":\n\x17TruncateEntriesResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"*\n\x0f\x41\x64\x64StoreRequest\x12\x17\n\x0fstoreDefinition\x18\x01 \x02(\t\"3\n\x10\x41\x64\x64StoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"\'\n\x12\x44\x65leteStoreRequest\x12\x11\n\tstoreName\x18\x01 \x02(\t\"6\n\x13\x44\x65leteStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"P\n\x11\x46\x65tchStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\x12\x14\n\x0cpush_version\x18\x03 \x01(\x03\"9\n\x10SwapStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\"P\n\x11SwapStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\x12\x1a\n\x12previous_store_dir\x18\x02 \x01(\t\"@\n\x14RollbackStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x14\n\x0cpush_version\x18\x02 \x02(\x03\"8\n\x15RollbackStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"&\n\x10RepairJobRequest\x12\x12\n\nstore_name\x18\x01 \x01(\t\"4\n\x11RepairJobResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"=\n\x14ROStoreVersionDirMap\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\"/\n\x19GetROMaxVersionDirRequest\x12\x12\n\nstore_name\x18\x01 \x03(\t\"y\n\x1aGetROMaxVersionDirResponse\x12:\n\x11ro_store_versions\x18\x01 \x03(\x0b\x32\x1f.voldemort.ROStoreVersionDirMap\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"3\n\x1dGetROCurrentVersionDirRequest\x12\x12\n\nstore_name\x18\x01 \x03(\t\"}\n\x1eGetROCurrentVersionDirResponse\x12:\n\x11ro_store_versions\x18\x01 \x03(\x0b\x32\x1f.voldemort.ROStoreVersionDirMap\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"/\n\x19GetROStorageFormatRequest\x12\x12\n\nstore_name\x18\x01 \x03(\t\"y\n\x1aGetROStorageFormatResponse\x12:\n\x11ro_store_versions\x18\x01 \x03(\x0b\x32\x1f.voldemort.ROStoreVersionDirMap\x12\x1f\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x10.voldemort.Error\"@\n\x17\x46\x61iledFetchStoreRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x11\n\tstore_dir\x18\x02 \x02(\t\";\n\x18\x46\x61iledFetchStoreResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"\xe6\x01\n\x1bRebalanceStateChangeRequest\x12K\n\x1drebalance_partition_info_list\x18\x01 \x03(\x0b\x32$.voldemort.RebalancePartitionInfoMap\x12\x16\n\x0e\x63luster_string\x18\x02 \x02(\t\x12\x0f\n\x07swap_ro\x18\x03 \x02(\x08\x12\x1f\n\x17\x63hange_cluster_metadata\x18\x04 \x02(\x08\x12\x1e\n\x16\x63hange_rebalance_state\x18\x05 \x02(\x08\x12\x10\n\x08rollback\x18\x06 \x02(\x08\"?\n\x1cRebalanceStateChangeResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"G\n DeleteStoreRebalanceStateRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x0f\n\x07node_id\x18\x02 \x02(\x05\"D\n!DeleteStoreRebalanceStateResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"h\n\x13NativeBackupRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x12\n\nbackup_dir\x18\x02 \x02(\t\x12\x14\n\x0cverify_files\x18\x03 \x02(\x08\x12\x13\n\x0bincremental\x18\x04 \x02(\x08\">\n\x14ReserveMemoryRequest\x12\x12\n\nstore_name\x18\x01 \x02(\t\x12\x12\n\nsize_in_mb\x18\x02 \x02(\x03\"8\n\x15ReserveMemoryResponse\x12\x1f\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x10.voldemort.Error\"\xf0\x0e\n\x15VoldemortAdminRequest\x12)\n\x04type\x18\x01 \x02(\x0e\x32\x1b.voldemort.AdminRequestType\x12\x33\n\x0cget_metadata\x18\x02 \x01(\x0b\x32\x1d.voldemort.GetMetadataRequest\x12\x39\n\x0fupdate_metadata\x18\x03 \x01(\x0b\x32 .voldemort.UpdateMetadataRequest\x12J\n\x18update_partition_entries\x18\x04 \x01(\x0b\x32(.voldemort.UpdatePartitionEntriesRequest\x12H\n\x17\x66\x65tch_partition_entries\x18\x05 \x01(\x0b\x32\'.voldemort.FetchPartitionEntriesRequest\x12J\n\x18\x64\x65lete_partition_entries\x18\x06 \x01(\x0b\x32(.voldemort.DeletePartitionEntriesRequest\x12K\n\x19initiate_fetch_and_update\x18\x07 \x01(\x0b\x32(.voldemort.InitiateFetchAndUpdateRequest\x12\x46\n\x16\x61sync_operation_status\x18\x08 \x01(\x0b\x32&.voldemort.AsyncOperationStatusRequest\x12H\n\x17initiate_rebalance_node\x18\t \x01(\x0b\x32\'.voldemort.InitiateRebalanceNodeRequest\x12\x42\n\x14\x61sync_operation_stop\x18\n \x01(\x0b\x32$.voldemort.AsyncOperationStopRequest\x12\x42\n\x14\x61sync_operation_list\x18\x0b \x01(\x0b\x32$.voldemort.AsyncOperationListRequest\x12;\n\x10truncate_entries\x18\x0c \x01(\x0b\x32!.voldemort.TruncateEntriesRequest\x12-\n\tadd_store\x18\r \x01(\x0b\x32\x1a.voldemort.AddStoreRequest\x12\x33\n\x0c\x64\x65lete_store\x18\x0e \x01(\x0b\x32\x1d.voldemort.DeleteStoreRequest\x12\x31\n\x0b\x66\x65tch_store\x18\x0f \x01(\x0b\x32\x1c.voldemort.FetchStoreRequest\x12/\n\nswap_store\x18\x10 \x01(\x0b\x32\x1b.voldemort.SwapStoreRequest\x12\x37\n\x0erollback_store\x18\x11 \x01(\x0b\x32\x1f.voldemort.RollbackStoreRequest\x12\x44\n\x16get_ro_max_version_dir\x18\x12 \x01(\x0b\x32$.voldemort.GetROMaxVersionDirRequest\x12L\n\x1aget_ro_current_version_dir\x18\x13 \x01(\x0b\x32(.voldemort.GetROCurrentVersionDirRequest\x12\x44\n\x15\x66\x65tch_partition_files\x18\x14 \x01(\x0b\x32%.voldemort.FetchPartitionFilesRequest\x12@\n\x13update_slop_entries\x18\x16 \x01(\x0b\x32#.voldemort.UpdateSlopEntriesRequest\x12>\n\x12\x66\x61iled_fetch_store\x18\x18 \x01(\x0b\x32\".voldemort.FailedFetchStoreRequest\x12\x43\n\x15get_ro_storage_format\x18\x19 \x01(\x0b\x32$.voldemort.GetROStorageFormatRequest\x12\x46\n\x16rebalance_state_change\x18\x1a \x01(\x0b\x32&.voldemort.RebalanceStateChangeRequest\x12/\n\nrepair_job\x18\x1b \x01(\x0b\x32\x1b.voldemort.RepairJobRequest\x12X\n initiate_rebalance_node_on_donor\x18\x1c \x01(\x0b\x32..voldemort.InitiateRebalanceNodeOnDonorRequest\x12Q\n\x1c\x64\x65lete_store_rebalance_state\x18\x1d \x01(\x0b\x32+.voldemort.DeleteStoreRebalanceStateRequest\x12\x35\n\rnative_backup\x18\x1e \x01(\x0b\x32\x1e.voldemort.NativeBackupRequest\x12\x37\n\x0ereserve_memory\x18\x1f \x01(\x0b\x32\x1f.voldemort.ReserveMemoryRequest*\xc8\x05\n\x10\x41\x64minRequestType\x12\x10\n\x0cGET_METADATA\x10\x00\x12\x13\n\x0fUPDATE_METADATA\x10\x01\x12\x1c\n\x18UPDATE_PARTITION_ENTRIES\x10\x02\x12\x1b\n\x17\x46\x45TCH_PARTITION_ENTRIES\x10\x03\x12\x1c\n\x18\x44\x45LETE_PARTITION_ENTRIES\x10\x04\x12\x1d\n\x19INITIATE_FETCH_AND_UPDATE\x10\x05\x12\x1a\n\x16\x41SYNC_OPERATION_STATUS\x10\x06\x12\x1b\n\x17INITIATE_REBALANCE_NODE\x10\x07\x12\x18\n\x14\x41SYNC_OPERATION_STOP\x10\x08\x12\x18\n\x14\x41SYNC_OPERATION_LIST\x10\t\x12\x14\n\x10TRUNCATE_ENTRIES\x10\n\x12\r\n\tADD_STORE\x10\x0b\x12\x10\n\x0c\x44\x45LETE_STORE\x10\x0c\x12\x0f\n\x0b\x46\x45TCH_STORE\x10\r\x12\x0e\n\nSWAP_STORE\x10\x0e\x12\x12\n\x0eROLLBACK_STORE\x10\x0f\x12\x1a\n\x16GET_RO_MAX_VERSION_DIR\x10\x10\x12\x1e\n\x1aGET_RO_CURRENT_VERSION_DIR\x10\x11\x12\x19\n\x15\x46\x45TCH_PARTITION_FILES\x10\x12\x12\x17\n\x13UPDATE_SLOP_ENTRIES\x10\x14\x12\x16\n\x12\x46\x41ILED_FETCH_STORE\x10\x16\x12\x19\n\x15GET_RO_STORAGE_FORMAT\x10\x17\x12\x1a\n\x16REBALANCE_STATE_CHANGE\x10\x18\x12\x0e\n\nREPAIR_JOB\x10\x19\x12$\n INITIATE_REBALANCE_NODE_ON_DONOR\x10\x1a\x12 \n\x1c\x44\x45LETE_STORE_REBALANCE_STATE\x10\x1b\x12\x11\n\rNATIVE_BACKUP\x10\x1c\x12\x12\n\x0eRESERVE_MEMORY\x10\x1d\x42-\n\x1cvoldemort.client.protocol.pbB\x0bVAdminProtoH\x01')
_ADMINREQUESTTYPE = descriptor.EnumDescriptor(
name='AdminRequestType',
@@ -133,8 +133,8 @@
],
containing_type=None,
options=None,
- serialized_start=6971,
- serialized_end=7683,
+ serialized_start=6995,
+ serialized_end=7707,
)
@@ -645,6 +645,13 @@
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
+ descriptor.FieldDescriptor(
+ name='fetch_orphaned', full_name='voldemort.FetchPartitionEntriesRequest.fetch_orphaned', index=6,
+ number=7, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
],
extensions=[
],
@@ -655,7 +662,7 @@
is_extendable=False,
extension_ranges=[],
serialized_start=1059,
- serialized_end=1274,
+ serialized_end=1298,
)
@@ -696,8 +703,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1277,
- serialized_end=1406,
+ serialized_start=1301,
+ serialized_end=1430,
)
@@ -745,8 +752,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1409,
- serialized_end=1581,
+ serialized_start=1433,
+ serialized_end=1605,
)
@@ -780,8 +787,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1583,
- serialized_end=1663,
+ serialized_start=1607,
+ serialized_end=1687,
)
@@ -843,8 +850,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1666,
- serialized_end=1873,
+ serialized_start=1690,
+ serialized_end=1897,
)
@@ -871,8 +878,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1875,
- serialized_end=1924,
+ serialized_start=1899,
+ serialized_end=1948,
)
@@ -899,8 +906,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1926,
- serialized_end=1973,
+ serialized_start=1950,
+ serialized_end=1997,
)
@@ -927,8 +934,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1975,
- serialized_end=2036,
+ serialized_start=1999,
+ serialized_end=2060,
)
@@ -955,8 +962,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2038,
- serialized_end=2088,
+ serialized_start=2062,
+ serialized_end=2112,
)
@@ -990,8 +997,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2090,
- serialized_end=2172,
+ serialized_start=2114,
+ serialized_end=2196,
)
@@ -1025,8 +1032,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2174,
- serialized_end=2232,
+ serialized_start=2198,
+ serialized_end=2256,
)
@@ -1060,8 +1067,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2234,
- serialized_end=2335,
+ serialized_start=2258,
+ serialized_end=2359,
)
@@ -1123,8 +1130,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2338,
- serialized_end=2586,
+ serialized_start=2362,
+ serialized_end=2610,
)
@@ -1151,8 +1158,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2588,
- serialized_end=2690,
+ serialized_start=2612,
+ serialized_end=2714,
)
@@ -1179,8 +1186,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2692,
- serialized_end=2801,
+ serialized_start=2716,
+ serialized_end=2825,
)
@@ -1235,8 +1242,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2804,
- serialized_end=2942,
+ serialized_start=2828,
+ serialized_end=2966,
)
@@ -1263,8 +1270,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2944,
- serialized_end=2983,
+ serialized_start=2968,
+ serialized_end=3007,
)
@@ -1291,8 +1298,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2985,
- serialized_end=3043,
+ serialized_start=3009,
+ serialized_end=3067,
)
@@ -1319,8 +1326,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3045,
- serialized_end=3087,
+ serialized_start=3069,
+ serialized_end=3111,
)
@@ -1347,8 +1354,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3089,
- serialized_end=3140,
+ serialized_start=3113,
+ serialized_end=3164,
)
@@ -1375,8 +1382,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3142,
- serialized_end=3181,
+ serialized_start=3166,
+ serialized_end=3205,
)
@@ -1403,8 +1410,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3183,
- serialized_end=3237,
+ serialized_start=3207,
+ serialized_end=3261,
)
@@ -1445,8 +1452,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3239,
- serialized_end=3319,
+ serialized_start=3263,
+ serialized_end=3343,
)
@@ -1480,8 +1487,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3321,
- serialized_end=3378,
+ serialized_start=3345,
+ serialized_end=3402,
)
@@ -1515,8 +1522,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3380,
- serialized_end=3460,
+ serialized_start=3404,
+ serialized_end=3484,
)
@@ -1550,8 +1557,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3462,
- serialized_end=3526,
+ serialized_start=3486,
+ serialized_end=3550,
)
@@ -1578,8 +1585,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3528,
- serialized_end=3584,
+ serialized_start=3552,
+ serialized_end=3608,
)
@@ -1606,8 +1613,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3586,
- serialized_end=3624,
+ serialized_start=3610,
+ serialized_end=3648,
)
@@ -1634,8 +1641,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3626,
- serialized_end=3678,
+ serialized_start=3650,
+ serialized_end=3702,
)
@@ -1669,8 +1676,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3680,
- serialized_end=3741,
+ serialized_start=3704,
+ serialized_end=3765,
)
@@ -1697,8 +1704,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3743,
- serialized_end=3790,
+ serialized_start=3767,
+ serialized_end=3814,
)
@@ -1732,8 +1739,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3792,
- serialized_end=3913,
+ serialized_start=3816,
+ serialized_end=3937,
)
@@ -1760,8 +1767,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3915,
- serialized_end=3966,
+ serialized_start=3939,
+ serialized_end=3990,
)
@@ -1795,8 +1802,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3968,
- serialized_end=4093,
+ serialized_start=3992,
+ serialized_end=4117,
)
@@ -1823,8 +1830,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4095,
- serialized_end=4142,
+ serialized_start=4119,
+ serialized_end=4166,
)
@@ -1858,8 +1865,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4144,
- serialized_end=4265,
+ serialized_start=4168,
+ serialized_end=4289,
)
@@ -1893,8 +1900,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4267,
- serialized_end=4331,
+ serialized_start=4291,
+ serialized_end=4355,
)
@@ -1921,8 +1928,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4333,
- serialized_end=4392,
+ serialized_start=4357,
+ serialized_end=4416,
)
@@ -1984,8 +1991,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4395,
- serialized_end=4625,
+ serialized_start=4419,
+ serialized_end=4649,
)
@@ -2012,8 +2019,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4627,
- serialized_end=4690,
+ serialized_start=4651,
+ serialized_end=4714,
)
@@ -2047,8 +2054,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4692,
- serialized_end=4763,
+ serialized_start=4716,
+ serialized_end=4787,
)
@@ -2075,8 +2082,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4765,
- serialized_end=4833,
+ serialized_start=4789,
+ serialized_end=4857,
)
@@ -2124,8 +2131,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4835,
- serialized_end=4939,
+ serialized_start=4859,
+ serialized_end=4963,
)
@@ -2159,8 +2166,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4941,
- serialized_end=5003,
+ serialized_start=4965,
+ serialized_end=5027,
)
@@ -2187,8 +2194,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=5005,
- serialized_end=5061,
+ serialized_start=5029,
+ serialized_end=5085,
)
@@ -2411,8 +2418,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=5064,
- serialized_end=6968,
+ serialized_start=5088,
+ serialized_end=6992,
)
import voldemort_client_pb2
diff --git a/config/single_node_cluster/config/stores.xml b/config/single_node_cluster/config/stores.xml
index d488d2b62d..082b7064ea 100644
--- a/config/single_node_cluster/config/stores.xml
+++ b/config/single_node_cluster/config/stores.xml
@@ -14,26 +14,6 @@
string
-
-
-
- test-evolution
- bdb
- Test store
- harry@hogwarts.edu, hermoine@hogwarts.edu
- consistent-routing
- client
- 1
- 1
- 1
-
- string
-
-
- avro-generic-versioned
- {"type": "record", "name": "myrec","fields": [{ "name": "original", "type": "string" }]}
- {"type": "record", "name": "myrec","fields": [{ "name": "original", "type": "string" }, { "name": "new-field", "type": "string", "default":"" }]}
-
-
-
+
+
\ No newline at end of file
diff --git a/contrib/ec2-testing/test/voldemort/utils/Ec2GossipTest.java b/contrib/ec2-testing/test/voldemort/utils/Ec2GossipTest.java
index 6fc0ddd049..b3fc661011 100644
--- a/contrib/ec2-testing/test/voldemort/utils/Ec2GossipTest.java
+++ b/contrib/ec2-testing/test/voldemort/utils/Ec2GossipTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2013 LinkedIn, Inc
+ *
+ * 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.
+ */
package voldemort.utils;
import static org.junit.Assert.assertEquals;
@@ -31,6 +46,7 @@
import voldemort.Attempt;
import voldemort.VoldemortException;
+import voldemort.client.ClientConfig;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
import voldemort.cluster.Cluster;
@@ -154,20 +170,23 @@ public boolean apply(Integer input) {
for(String hostname: newHostnames) {
int nodeId = nodeIds.get(hostname);
AdminClient adminClient = new AdminClient("tcp://" + hostname + ":6666",
- new AdminClientConfig());
+ new AdminClientConfig(),
+ new ClientConfig());
- Versioned versioned = adminClient.getRemoteMetadata(nodeId,
- MetadataStore.CLUSTER_KEY);
+ Versioned versioned = adminClient.metadataMgmtOps.getRemoteMetadata(nodeId,
+ MetadataStore.CLUSTER_KEY);
Version version = versioned.getVersion();
VectorClock vectorClock = (VectorClock) version;
vectorClock.incrementVersion(nodeId, System.currentTimeMillis());
try {
- adminClient.updateRemoteMetadata(peerNodeId,
- MetadataStore.CLUSTER_KEY,
- versioned);
- adminClient.updateRemoteMetadata(nodeId, MetadataStore.CLUSTER_KEY, versioned);
+ adminClient.metadataMgmtOps.updateRemoteMetadata(peerNodeId,
+ MetadataStore.CLUSTER_KEY,
+ versioned);
+ adminClient.metadataMgmtOps.updateRemoteMetadata(nodeId,
+ MetadataStore.CLUSTER_KEY,
+ versioned);
} catch(VoldemortException e) {
logger.error(e);
}
@@ -181,7 +200,8 @@ public boolean apply(Integer input) {
private int count = 1;
private AdminClient adminClient = new AdminClient("tcp://" + hostNames.get(0)
+ ":6666",
- new AdminClientConfig());
+ new AdminClientConfig(),
+ new ClientConfig());
public void checkCondition() throws Exception, AssertionError {
logger.info("Attempt " + count++);
@@ -189,7 +209,8 @@ public void checkCondition() throws Exception, AssertionError {
for(int testNodeId: oldNodeIdSet) {
logger.info("Testing node " + testNodeId);
try {
- Cluster cluster = adminClient.getRemoteCluster(testNodeId).getValue();
+ Cluster cluster = adminClient.metadataMgmtOps.getRemoteCluster(testNodeId)
+ .getValue();
Set allNodeIds = new HashSet();
for(Node node: cluster.getNodes()) {
allNodeIds.add(node.getId());
diff --git a/contrib/ec2-testing/test/voldemort/utils/Ec2RebalanceTest.java b/contrib/ec2-testing/test/voldemort/utils/Ec2RebalanceTest.java
index 3e402ffc5a..448a733c68 100644
--- a/contrib/ec2-testing/test/voldemort/utils/Ec2RebalanceTest.java
+++ b/contrib/ec2-testing/test/voldemort/utils/Ec2RebalanceTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2013 LinkedIn, Inc
+ *
+ * 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.
+ */
package voldemort.utils;
import static voldemort.utils.Ec2RemoteTestUtils.createInstances;
@@ -25,6 +40,7 @@
import org.junit.BeforeClass;
import voldemort.VoldemortException;
+import voldemort.client.ClientConfig;
import voldemort.client.protocol.RequestFormatType;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
@@ -41,6 +57,8 @@
*/
public class Ec2RebalanceTest extends AbstractRebalanceTest {
+ private static int NUM_KEYS;
+
private static final Logger logger = Logger.getLogger(Ec2RebalanceTest.class);
private static Ec2RebalanceTestConfig ec2RebalanceTestConfig;
private static List hostNamePairs;
@@ -68,13 +86,20 @@ public static void ec2TearDown() throws Exception {
destroyInstances(hostNames, ec2RebalanceTestConfig);
}
+ @Override
+ protected int getNumKeys() {
+ return NUM_KEYS;
+ }
+
@Override
protected Cluster getCurrentCluster(int nodeId) {
String hostName = nodeIdsInv.get(nodeId);
if(hostName == null) {
throw new VoldemortException("Node id " + nodeId + " does not exist");
} else {
- AdminClient adminClient = new AdminClient(hostName, new AdminClientConfig());
+ AdminClient adminClient = new AdminClient(hostName,
+ new AdminClientConfig(),
+ new ClientConfig());
return adminClient.getAdminClientCluster();
}
}
@@ -85,8 +110,10 @@ protected VoldemortState getCurrentState(int nodeId) {
if(hostName == null) {
throw new VoldemortException("Node id " + nodeId + " does not exist");
} else {
- AdminClient adminClient = new AdminClient(hostName, new AdminClientConfig());
- return adminClient.getRemoteServerState(nodeId).getValue();
+ AdminClient adminClient = new AdminClient(hostName,
+ new AdminClientConfig(),
+ new ClientConfig());
+ return adminClient.rebalanceOps.getRemoteServerState(nodeId).getValue();
}
}
diff --git a/contrib/hadoop-store-builder/lib/commons-configuration-1.6.jar b/contrib/hadoop-store-builder/lib/commons-configuration-1.6.jar
new file mode 100644
index 0000000000..2d4689a1b8
Binary files /dev/null and b/contrib/hadoop-store-builder/lib/commons-configuration-1.6.jar differ
diff --git a/contrib/hadoop-store-builder/lib/hadoop-0.20.2-core.jar b/contrib/hadoop-store-builder/lib/hadoop-0.20.2-core.jar
deleted file mode 100644
index 32ae0a1c9c..0000000000
Binary files a/contrib/hadoop-store-builder/lib/hadoop-0.20.2-core.jar and /dev/null differ
diff --git a/contrib/hadoop-store-builder/lib/hadoop-core-1.0.4-p2.jar b/contrib/hadoop-store-builder/lib/hadoop-core-1.0.4-p2.jar
new file mode 100644
index 0000000000..c7a9027b1a
Binary files /dev/null and b/contrib/hadoop-store-builder/lib/hadoop-core-1.0.4-p2.jar differ
diff --git a/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/BdbBuildPerformanceTest.java b/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/BdbBuildPerformanceTest.java
index b2c67df2ee..45aadaddde 100644
--- a/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/BdbBuildPerformanceTest.java
+++ b/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/BdbBuildPerformanceTest.java
@@ -52,7 +52,7 @@ public static void main(String[] args) throws FileNotFoundException, IOException
String storeName = args[1];
String jsonDataFile = args[2];
- final Store store = new BdbStorageConfiguration(new VoldemortConfig(new Props(new File(serverPropsFile)))).getStore(TestUtils.makeStoreDefinition(storeName));
+ final Store store = new BdbStorageConfiguration(new VoldemortConfig(new Props(new File(serverPropsFile)))).getStore(TestUtils.makeStoreDefinition(storeName), TestUtils.makeSingleNodeRoutingStrategy());
final AtomicInteger obsoletes = new AtomicInteger(0);
diff --git a/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/MysqlBuildPerformanceTest.java b/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/MysqlBuildPerformanceTest.java
index d7fe084ea1..3d7fd3df4f 100644
--- a/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/MysqlBuildPerformanceTest.java
+++ b/contrib/hadoop-store-builder/perf/voldemort/contrib/batchindexer/performance/MysqlBuildPerformanceTest.java
@@ -52,7 +52,7 @@ public static void main(String[] args) throws FileNotFoundException, IOException
String storeName = args[1];
String jsonDataFile = args[2];
- final Store store = new MysqlStorageConfiguration(new VoldemortConfig(new Props(new File(serverPropsFile)))).getStore(TestUtils.makeStoreDefinition(storeName));
+ final Store store = new MysqlStorageConfiguration(new VoldemortConfig(new Props(new File(serverPropsFile)))).getStore(TestUtils.makeStoreDefinition(storeName), TestUtils.makeSingleNodeRoutingStrategy());
final AtomicInteger obsoletes = new AtomicInteger(0);
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriter.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriter.java
index 87bebe74d8..2506cf1c51 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriter.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriter.java
@@ -26,6 +26,7 @@
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobConf;
@@ -38,6 +39,7 @@
import voldemort.store.readonly.ReadOnlyUtils;
import voldemort.store.readonly.checksum.CheckSum;
import voldemort.store.readonly.checksum.CheckSum.CheckSumType;
+import voldemort.store.readonly.mr.HadoopStoreBuilder;
import voldemort.utils.ByteUtils;
import voldemort.xml.ClusterMapper;
import voldemort.xml.StoreDefinitionsMapper;
@@ -146,7 +148,14 @@ public void conf(JobConf job) {
this.fs = this.taskIndexFileName.getFileSystem(job);
this.indexFileStream = fs.create(this.taskIndexFileName);
+ fs.setPermission(this.taskIndexFileName,
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + this.taskIndexFileName);
+
this.valueFileStream = fs.create(this.taskValueFileName);
+ fs.setPermission(this.taskValueFileName,
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + this.taskValueFileName);
logger.info("Opening " + this.taskIndexFileName + " and " + this.taskValueFileName
+ " for writing.");
@@ -304,6 +313,8 @@ public void close() throws IOException {
// Create output directory, if it doesn't exist
FileSystem outputFs = nodeDir.getFileSystem(this.conf);
outputFs.mkdirs(nodeDir);
+ outputFs.setPermission(nodeDir, new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + nodeDir);
// Write the checksum and output files
if(this.checkSumType != CheckSumType.NONE) {
@@ -312,11 +323,21 @@ public void close() throws IOException {
Path checkSumIndexFile = new Path(nodeDir, fileNamePrefix + ".index.checksum");
Path checkSumValueFile = new Path(nodeDir, fileNamePrefix + ".data.checksum");
+ if(outputFs.exists(checkSumIndexFile)) {
+ outputFs.delete(checkSumIndexFile);
+ }
FSDataOutputStream output = outputFs.create(checkSumIndexFile);
+ outputFs.setPermission(checkSumIndexFile,
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
output.write(this.checkSumDigestIndex.getCheckSum());
output.close();
+ if(outputFs.exists(checkSumValueFile)) {
+ outputFs.delete(checkSumValueFile);
+ }
output = outputFs.create(checkSumValueFile);
+ outputFs.setPermission(checkSumValueFile,
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
output.write(this.checkSumDigestValue.getCheckSum());
output.close();
} else {
@@ -331,8 +352,15 @@ public void close() throws IOException {
Path valueFile = new Path(nodeDir, fileNamePrefix + ".data");
logger.info("Moving " + this.taskIndexFileName + " to " + indexFile);
+ if(outputFs.exists(indexFile)) {
+ outputFs.delete(indexFile);
+ }
outputFs.rename(taskIndexFileName, indexFile);
+
logger.info("Moving " + this.taskValueFileName + " to " + valueFile);
+ if(outputFs.exists(valueFile)) {
+ outputFs.delete(valueFile);
+ }
outputFs.rename(this.taskValueFileName, valueFile);
}
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriterPerBucket.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriterPerBucket.java
index 6fdf34f910..ddc50857b2 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriterPerBucket.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/disk/HadoopStoreWriterPerBucket.java
@@ -26,6 +26,7 @@
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobConf;
@@ -38,6 +39,7 @@
import voldemort.store.readonly.ReadOnlyUtils;
import voldemort.store.readonly.checksum.CheckSum;
import voldemort.store.readonly.checksum.CheckSum.CheckSumType;
+import voldemort.store.readonly.mr.HadoopStoreBuilder;
import voldemort.utils.ByteUtils;
import voldemort.xml.ClusterMapper;
import voldemort.xml.StoreDefinitionsMapper;
@@ -117,7 +119,14 @@ public void conf(JobConf job) {
this.fs = this.taskIndexFileName[chunkId].getFileSystem(job);
this.indexFileStream[chunkId] = fs.create(this.taskIndexFileName[chunkId]);
+ fs.setPermission(this.taskIndexFileName[chunkId],
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + this.taskIndexFileName[chunkId]);
+
this.valueFileStream[chunkId] = fs.create(this.taskValueFileName[chunkId]);
+ fs.setPermission(this.taskValueFileName[chunkId],
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + this.taskValueFileName[chunkId]);
logger.info("Opening " + this.taskIndexFileName[chunkId] + " and "
+ this.taskValueFileName[chunkId] + " for writing.");
@@ -278,6 +287,8 @@ public void close() throws IOException {
// Create output directory, if it doesn't exist
FileSystem outputFs = nodeDir.getFileSystem(this.conf);
outputFs.mkdirs(nodeDir);
+ outputFs.setPermission(nodeDir, new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + nodeDir);
// Write the checksum and output files
for(int chunkId = 0; chunkId < getNumChunks(); chunkId++) {
@@ -290,11 +301,21 @@ public void close() throws IOException {
Path checkSumIndexFile = new Path(nodeDir, chunkFileName + ".index.checksum");
Path checkSumValueFile = new Path(nodeDir, chunkFileName + ".data.checksum");
+ if(outputFs.exists(checkSumIndexFile)) {
+ outputFs.delete(checkSumIndexFile);
+ }
FSDataOutputStream output = outputFs.create(checkSumIndexFile);
+ outputFs.setPermission(checkSumIndexFile,
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
output.write(this.checkSumDigestIndex[chunkId].getCheckSum());
output.close();
+ if(outputFs.exists(checkSumValueFile)) {
+ outputFs.delete(checkSumValueFile);
+ }
output = outputFs.create(checkSumValueFile);
+ outputFs.setPermission(checkSumValueFile,
+ new FsPermission(HadoopStoreBuilder.HADOOP_FILE_PERMISSION));
output.write(this.checkSumDigestValue[chunkId].getCheckSum());
output.close();
} else {
@@ -309,8 +330,15 @@ public void close() throws IOException {
Path valueFile = new Path(nodeDir, chunkFileName + ".data");
logger.info("Moving " + this.taskIndexFileName[chunkId] + " to " + indexFile);
+ if(outputFs.exists(indexFile)) {
+ outputFs.delete(indexFile);
+ }
fs.rename(taskIndexFileName[chunkId], indexFile);
+
logger.info("Moving " + this.taskValueFileName[chunkId] + " to " + valueFile);
+ if(outputFs.exists(valueFile)) {
+ outputFs.delete(valueFile);
+ }
fs.rename(this.taskValueFileName[chunkId], valueFile);
}
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/fetcher/HdfsFetcher.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/fetcher/HdfsFetcher.java
index a5cbb371d9..8a441916ec 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/fetcher/HdfsFetcher.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/fetcher/HdfsFetcher.java
@@ -21,6 +21,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.net.URI;
+import java.security.PrivilegedExceptionAction;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Comparator;
@@ -32,10 +34,12 @@
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
import org.apache.log4j.Logger;
import voldemort.VoldemortException;
@@ -61,6 +65,9 @@ public class HdfsFetcher implements FileFetcher {
private static final Logger logger = Logger.getLogger(HdfsFetcher.class);
+ private static String keytabPath = "";
+ private static String kerberosPrincipal = VoldemortConfig.DEFAULT_KERBEROS_PRINCIPAL;
+
private final Long maxBytesPerSecond, reportingIntervalBytes;
private final int bufferSize;
private static final AtomicInteger copyCount = new AtomicInteger(0);
@@ -69,22 +76,36 @@ public class HdfsFetcher implements FileFetcher {
private long minBytesPerSecond = 0;
private DynamicThrottleLimit globalThrottleLimit = null;
private static final int NUM_RETRIES = 3;
+ private VoldemortConfig voldemortConfig = null;
+
+ public static final String FS_DEFAULT_NAME = "fs.default.name";
+ /* Additional constructor invoked from ReadOnlyStoreManagementServlet */
public HdfsFetcher(VoldemortConfig config) {
- this(config.getMaxBytesPerSecond(),
- config.getReportingIntervalBytes(),
- config.getFetcherBufferSize());
+ this(null,
+ null,
+ config.getReadOnlyFetcherReportingIntervalBytes(),
+ config.getFetcherBufferSize(),
+ config.getReadOnlyFetcherMinBytesPerSecond(),
+ config.getReadOnlyKeytabPath(),
+ config.getReadOnlyKerberosUser());
- logger.info("Created hdfs fetcher with throttle rate " + maxBytesPerSecond
- + ", buffer size " + bufferSize + ", reporting interval bytes "
- + reportingIntervalBytes);
+ this.voldemortConfig = config;
+
+ logger.info("Created hdfs fetcher with no dynamic throttler, buffer size " + bufferSize
+ + ", reporting interval bytes " + reportingIntervalBytes);
}
public HdfsFetcher(VoldemortConfig config, DynamicThrottleLimit dynThrottleLimit) {
this(dynThrottleLimit,
- config.getReportingIntervalBytes(),
+ null,
+ config.getReadOnlyFetcherReportingIntervalBytes(),
config.getFetcherBufferSize(),
- config.getMinBytesPerSecond());
+ config.getReadOnlyFetcherMinBytesPerSecond(),
+ config.getReadOnlyKeytabPath(),
+ config.getReadOnlyKerberosUser());
+
+ this.voldemortConfig = config;
logger.info("Created hdfs fetcher with throttle rate " + dynThrottleLimit.getRate()
+ ", buffer size " + bufferSize + ", reporting interval bytes "
@@ -98,21 +119,16 @@ public HdfsFetcher() {
}
public HdfsFetcher(Long maxBytesPerSecond, Long reportingIntervalBytes, int bufferSize) {
- this(null, maxBytesPerSecond, reportingIntervalBytes, bufferSize, 0);
- }
-
- public HdfsFetcher(DynamicThrottleLimit dynThrottleLimit,
- Long reportingIntervalBytes,
- int bufferSize,
- long minBytesPerSecond) {
- this(dynThrottleLimit, null, reportingIntervalBytes, bufferSize, minBytesPerSecond);
+ this(null, maxBytesPerSecond, reportingIntervalBytes, bufferSize, 0, "", "");
}
public HdfsFetcher(DynamicThrottleLimit dynThrottleLimit,
Long maxBytesPerSecond,
Long reportingIntervalBytes,
int bufferSize,
- long minBytesPerSecond) {
+ long minBytesPerSecond,
+ String keytabLocation,
+ String kerberosUser) {
if(maxBytesPerSecond != null) {
this.maxBytesPerSecond = maxBytesPerSecond;
this.throttler = new EventThrottler(this.maxBytesPerSecond);
@@ -128,9 +144,20 @@ public HdfsFetcher(DynamicThrottleLimit dynThrottleLimit,
this.bufferSize = bufferSize;
this.status = null;
this.minBytesPerSecond = minBytesPerSecond;
+ HdfsFetcher.kerberosPrincipal = kerberosUser;
+ HdfsFetcher.keytabPath = keytabLocation;
}
public File fetch(String sourceFileUrl, String destinationFile) throws IOException {
+ String hadoopConfigPath = "";
+ if(this.voldemortConfig != null) {
+ hadoopConfigPath = this.voldemortConfig.getHadoopConfigPath();
+ }
+ return fetch(sourceFileUrl, destinationFile, hadoopConfigPath);
+ }
+
+ public File fetch(String sourceFileUrl, String destinationFile, String hadoopConfigPath)
+ throws IOException {
if(this.globalThrottleLimit != null) {
if(this.globalThrottleLimit.getSpeculativeRate() < this.minBytesPerSecond)
throw new VoldemortException("Too many push jobs.");
@@ -140,12 +167,117 @@ public File fetch(String sourceFileUrl, String destinationFile) throws IOExcepti
ObjectName jmxName = null;
try {
- Path path = new Path(sourceFileUrl);
- Configuration config = new Configuration();
+ final Configuration config = new Configuration();
+ FileSystem fs = null;
config.setInt("io.socket.receive.buffer", bufferSize);
config.set("hadoop.rpc.socket.factory.class.ClientProtocol",
ConfigurableSocketFactory.class.getName());
- FileSystem fs = path.getFileSystem(config);
+ config.set("hadoop.security.group.mapping",
+ "org.apache.hadoop.security.ShellBasedUnixGroupsMapping");
+
+ final Path path = new Path(sourceFileUrl);
+
+ boolean isHftpBasedFetch = sourceFileUrl.length() > 4
+ && sourceFileUrl.substring(0, 4).equals("hftp");
+ logger.info("URL : " + sourceFileUrl + " and hftp protocol enabled = "
+ + isHftpBasedFetch);
+ logger.info("Hadoop path = " + hadoopConfigPath + " , keytab path = "
+ + HdfsFetcher.keytabPath + " , kerberos principal = "
+ + HdfsFetcher.kerberosPrincipal);
+
+ if(hadoopConfigPath.length() > 0 && !isHftpBasedFetch) {
+
+ config.addResource(new Path(hadoopConfigPath + "/core-site.xml"));
+ config.addResource(new Path(hadoopConfigPath + "/hdfs-site.xml"));
+
+ String security = config.get(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION);
+
+ if(security == null || !security.equals("kerberos")) {
+ logger.error("Security isn't turned on in the conf: "
+ + CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION
+ + " = "
+ + config.get(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION));
+ logger.error("Please make sure that the Hadoop config directory path is valid.");
+ throw new VoldemortException("Error in getting Hadoop filesystem. Invalid Hadoop config directory path.");
+ } else {
+ logger.info("Security is turned on in the conf. Trying to authenticate ...");
+
+ }
+ }
+
+ if(HdfsFetcher.keytabPath.length() > 0 && !isHftpBasedFetch) {
+
+ /*
+ * We're seeing intermittent errors while trying to get the
+ * Hadoop filesystem in a privileged doAs block. This happens
+ * when we fetch the files over hdfs or webhdfs. This retry loop
+ * is inserted here as a temporary measure.
+ */
+ for(int retryCount = 0; retryCount < NUM_RETRIES; retryCount++) {
+ boolean isValidFilesystem = false;
+
+ if(!new File(HdfsFetcher.keytabPath).exists()) {
+ logger.error("Invalid keytab file path. Please provide a valid keytab path");
+ throw new VoldemortException("Error in getting Hadoop filesystem. Invalid keytab file path.");
+ }
+
+ /*
+ * The Hadoop path for getting a Filesystem object in a
+ * privileged doAs block is not thread safe. This might be
+ * causing intermittent NPE exceptions. Adding a
+ * synchronized block.
+ */
+ synchronized(this) {
+ /*
+ * First login using the specified principal and keytab
+ * file
+ */
+ UserGroupInformation.setConfiguration(config);
+ UserGroupInformation.loginUserFromKeytab(HdfsFetcher.kerberosPrincipal,
+ HdfsFetcher.keytabPath);
+
+ /*
+ * If login is successful, get the filesystem object.
+ * NOTE: Ideally we do not need a doAs block for this.
+ * Consider removing it in the future once the Hadoop
+ * jars have the corresponding patch (tracked in the
+ * Hadoop Apache project: HDFS-3367)
+ */
+ try {
+ logger.info("I've logged in and am now Doasing as "
+ + UserGroupInformation.getCurrentUser().getUserName());
+ fs = UserGroupInformation.getCurrentUser()
+ .doAs(new PrivilegedExceptionAction() {
+
+ @Override
+ public FileSystem run() throws Exception {
+ FileSystem fs = path.getFileSystem(config);
+ return fs;
+ }
+ });
+ isValidFilesystem = true;
+ } catch(InterruptedException e) {
+ logger.error(e.getMessage());
+ } catch(Exception e) {
+ logger.error("Got an exception while getting the filesystem object: ");
+ logger.error("Exception class : " + e.getClass());
+ e.printStackTrace();
+ for(StackTraceElement et: e.getStackTrace()) {
+ logger.error(et.toString());
+ }
+ }
+ }
+
+ if(isValidFilesystem) {
+ break;
+ } else if(retryCount < NUM_RETRIES - 1) {
+ logger.error("Could not get a valid Filesystem object. Trying again.");
+ }
+ }
+
+ } else {
+ fs = path.getFileSystem(config);
+ }
CopyStats stats = new CopyStats(sourceFileUrl, sizeOfPath(fs, path));
jmxName = JmxUtils.registerMbean("hdfs-copy-" + copyCount.getAndIncrement(), stats);
@@ -156,18 +288,33 @@ public File fetch(String sourceFileUrl, String destinationFile) throws IOExcepti
+ " already exists");
}
+ logger.info("Starting fetch for : " + sourceFileUrl);
boolean result = fetch(fs, path, destination, stats);
+ logger.info("Completed fetch : " + sourceFileUrl);
+
+ // Close the filesystem
+ fs.close();
if(result) {
return destination;
} else {
return null;
}
+ } catch(IOException e) {
+ e.printStackTrace();
+ logger.error("Error while getting Hadoop filesystem : " + e);
+ throw new VoldemortException("Error while getting Hadoop filesystem : " + e);
+ } catch(Throwable te) {
+ te.printStackTrace();
+ logger.error("Error thrown while trying to get Hadoop filesystem");
+ throw new VoldemortException("Error thrown while trying to get Hadoop filesystem : "
+ + te);
} finally {
if(this.globalThrottleLimit != null) {
this.globalThrottleLimit.decrementNumJobs();
}
- JmxUtils.unregisterMbean(jmxName);
+ if(jmxName != null)
+ JmxUtils.unregisterMbean(jmxName);
}
}
@@ -226,25 +373,28 @@ private boolean fetch(FileSystem fs, Path source, File dest, CopyStats stats)
logger.debug("Checksum from .metadata "
+ new String(Hex.encodeHex(origCheckSum)));
+
+ // Define the Global checksum generator
checkSumType = CheckSum.fromString(checkSumTypeString);
checkSumGenerator = CheckSum.getInstance(checkSumType);
- fileCheckSumGenerator = CheckSum.getInstance(checkSumType);
}
} else if(!status.getPath().getName().startsWith(".")) {
// Read other (.data , .index files)
File copyLocation = new File(dest, status.getPath().getName());
- copyFileWithCheckSum(fs,
- status.getPath(),
- copyLocation,
- stats,
- fileCheckSumGenerator);
+ fileCheckSumGenerator = copyFileWithCheckSum(fs,
+ status.getPath(),
+ copyLocation,
+ stats,
+ checkSumType);
if(fileCheckSumGenerator != null && checkSumGenerator != null) {
byte[] checkSum = fileCheckSumGenerator.getCheckSum();
- logger.debug("Checksum for " + status.getPath() + " - "
- + new String(Hex.encodeHex(checkSum)));
+ if(logger.isDebugEnabled()) {
+ logger.debug("Checksum for " + status.getPath() + " - "
+ + new String(Hex.encodeHex(checkSum)));
+ }
checkSumGenerator.update(checkSum);
}
}
@@ -275,18 +425,38 @@ private boolean fetch(FileSystem fs, Path source, File dest, CopyStats stats)
}
- private void copyFileWithCheckSum(FileSystem fs,
- Path source,
- File dest,
- CopyStats stats,
- CheckSum fileCheckSumGenerator) throws IOException {
- logger.info("Starting copy of " + source + " to " + dest);
+ /**
+ * Function to copy a file from the given filesystem with a checksum of type
+ * 'checkSumType' computed and returned. In case an error occurs during such
+ * a copy, we do a retry for a maximum of NUM_RETRIES
+ *
+ * @param fs Filesystem used to copy the file
+ * @param source Source path of the file to copy
+ * @param dest Destination path of the file on the local machine
+ * @param stats Stats for measuring the transfer progress
+ * @param checkSumType Type of the Checksum to be computed for this file
+ * @return A Checksum (generator) of type checkSumType which contains the
+ * computed checksum of the copied file
+ * @throws IOException
+ */
+ private CheckSum copyFileWithCheckSum(FileSystem fs,
+ Path source,
+ File dest,
+ CopyStats stats,
+ CheckSumType checkSumType) throws IOException {
+ CheckSum fileCheckSumGenerator = null;
+ logger.debug("Starting copy of " + source + " to " + dest);
FSDataInputStream input = null;
OutputStream output = null;
for(int attempt = 0; attempt < NUM_RETRIES; attempt++) {
boolean success = true;
try {
+ // Create a per file checksum generator
+ if(checkSumType != null) {
+ fileCheckSumGenerator = CheckSum.getInstance(checkSumType);
+ }
+
input = fs.open(source);
output = new BufferedOutputStream(new FileOutputStream(dest));
byte[] buffer = new byte[bufferSize];
@@ -298,10 +468,16 @@ private void copyFileWithCheckSum(FileSystem fs,
output.write(buffer, 0, read);
}
- if(fileCheckSumGenerator != null)
+ // Update the per file checksum
+ if(fileCheckSumGenerator != null) {
fileCheckSumGenerator.update(buffer, 0, read);
- if(throttler != null)
+ }
+
+ // Check if we need to throttle the fetch
+ if(throttler != null) {
throttler.maybeThrottle(read);
+ }
+
stats.recordBytes(read);
if(stats.getBytesSinceLastReport() > reportingIntervalBytes) {
NumberFormat format = NumberFormat.getNumberInstance();
@@ -334,7 +510,19 @@ private void copyFileWithCheckSum(FileSystem fs,
throw ioe;
}
- } finally {
+ } catch(Exception e) {
+ logger.error("Error during copying file ", e);
+ return null;
+
+ } catch(Throwable te) {
+ logger.error("Error during copying file ", te);
+ return null;
+
+ }
+ // the finally block _always_ executes even if we have
+ // return in the catch block
+
+ finally {
IOUtils.closeQuietly(output);
IOUtils.closeQuietly(input);
if(success) {
@@ -342,8 +530,9 @@ private void copyFileWithCheckSum(FileSystem fs,
}
}
-
+ logger.debug("Completed copy of " + source + " to " + dest);
}
+ return fileCheckSumGenerator;
}
private long sizeOfPath(FileSystem fs, Path path) throws IOException {
@@ -459,28 +648,120 @@ public void setAsyncOperationStatus(AsyncOperationStatus status) {
* Main method for testing fetching
*/
public static void main(String[] args) throws Exception {
- if(args.length != 1)
- Utils.croak("USAGE: java " + HdfsFetcher.class.getName() + " url");
+ if(args.length < 1)
+ Utils.croak("USAGE: java " + HdfsFetcher.class.getName()
+ + " url [keytab location] [kerberos username] [hadoop-config-path]");
String url = args[0];
+
+ String keytabLocation = "";
+ String kerberosUser = "";
+ String hadoopPath = "";
+ if(args.length == 4) {
+ keytabLocation = args[1];
+ kerberosUser = args[2];
+ hadoopPath = args[3];
+ }
+
long maxBytesPerSec = 1024 * 1024 * 1024;
Path p = new Path(url);
- Configuration config = new Configuration();
+
+ final Configuration config = new Configuration();
+ final URI uri = new URI(url);
config.setInt("io.file.buffer.size", VoldemortConfig.DEFAULT_BUFFER_SIZE);
config.set("hadoop.rpc.socket.factory.class.ClientProtocol",
ConfigurableSocketFactory.class.getName());
config.setInt("io.socket.receive.buffer", 1 * 1024 * 1024 - 10000);
- FileStatus status = p.getFileSystem(config).getFileStatus(p);
+
+ FileSystem fs = null;
+ p = new Path(url);
+ HdfsFetcher.keytabPath = keytabLocation;
+ HdfsFetcher.kerberosPrincipal = kerberosUser;
+
+ boolean isHftpBasedFetch = url.length() > 4 && url.substring(0, 4).equals("hftp");
+ logger.info("URL : " + url + " and hftp protocol enabled = " + isHftpBasedFetch);
+
+ if(hadoopPath.length() > 0 && !isHftpBasedFetch) {
+ config.set("hadoop.security.group.mapping",
+ "org.apache.hadoop.security.ShellBasedUnixGroupsMapping");
+
+ config.addResource(new Path(hadoopPath + "/core-site.xml"));
+ config.addResource(new Path(hadoopPath + "/hdfs-site.xml"));
+
+ String security = config.get(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION);
+
+ if(security == null || !security.equals("kerberos")) {
+ logger.info("Security isn't turned on in the conf: "
+ + CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION + " = "
+ + config.get(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION));
+ logger.info("Fix that. Exiting.");
+ return;
+ } else {
+ logger.info("Security is turned on in the conf. Trying to authenticate ...");
+ }
+ }
+
+ try {
+
+ // Get the filesystem object
+ if(keytabLocation.length() > 0 && !isHftpBasedFetch) {
+ UserGroupInformation.setConfiguration(config);
+ UserGroupInformation.loginUserFromKeytab(kerberosUser, keytabLocation);
+
+ final Path path = p;
+ try {
+ logger.debug("I've logged in and am now Doasing as "
+ + UserGroupInformation.getCurrentUser().getUserName());
+ fs = UserGroupInformation.getCurrentUser()
+ .doAs(new PrivilegedExceptionAction() {
+
+ public FileSystem run() throws Exception {
+ FileSystem fs = path.getFileSystem(config);
+ return fs;
+ }
+ });
+ } catch(InterruptedException e) {
+ logger.error(e.getMessage());
+ } catch(Exception e) {
+ logger.error("Got an exception while getting the filesystem object: ");
+ logger.error("Exception class : " + e.getClass());
+ e.printStackTrace();
+ for(StackTraceElement et: e.getStackTrace()) {
+ logger.error(et.toString());
+ }
+ }
+ } else {
+ fs = p.getFileSystem(config);
+ }
+
+ } catch(IOException e) {
+ e.printStackTrace();
+ System.err.println("IOException in getting Hadoop filesystem object !!! Exiting !!!");
+ System.exit(-1);
+ } catch(Throwable te) {
+ te.printStackTrace();
+ logger.error("Error thrown while trying to get Hadoop filesystem");
+ System.exit(-1);
+ }
+
+ FileStatus status = fs.listStatus(p)[0];
long size = status.getLen();
- HdfsFetcher fetcher = new HdfsFetcher(maxBytesPerSec,
+ HdfsFetcher fetcher = new HdfsFetcher(null,
+ maxBytesPerSec,
VoldemortConfig.REPORTING_INTERVAL_BYTES,
- VoldemortConfig.DEFAULT_BUFFER_SIZE);
+ VoldemortConfig.DEFAULT_BUFFER_SIZE,
+ 0,
+ keytabLocation,
+ kerberosUser);
long start = System.currentTimeMillis();
+
File location = fetcher.fetch(url, System.getProperty("java.io.tmpdir") + File.separator
- + start);
+ + start, hadoopPath);
+
double rate = size * Time.MS_PER_SECOND / (double) (System.currentTimeMillis() - start);
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
System.out.println("Fetch to " + location + " completed: "
+ nf.format(rate / (1024.0 * 1024.0)) + " MB/sec.");
+ fs.close();
}
}
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AbstractHadoopStoreBuilderMapper.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AbstractHadoopStoreBuilderMapper.java
index ea18558da6..cad736f861 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AbstractHadoopStoreBuilderMapper.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AbstractHadoopStoreBuilderMapper.java
@@ -26,6 +26,7 @@
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;
+import voldemort.cluster.Node;
import voldemort.routing.ConsistentRoutingStrategy;
import voldemort.serialization.DefaultSerializerFactory;
import voldemort.serialization.Serializer;
@@ -33,7 +34,6 @@
import voldemort.serialization.SerializerFactory;
import voldemort.store.compress.CompressionStrategy;
import voldemort.store.compress.CompressionStrategyFactory;
-import voldemort.store.readonly.mr.utils.MapperKeyValueWriter;
import voldemort.utils.ByteUtils;
/**
@@ -76,31 +76,100 @@ public void map(K key,
V value,
OutputCollector output,
Reporter reporter) throws IOException {
+
byte[] keyBytes = keySerializer.toBytes(makeKey(key, value));
byte[] valBytes = valueSerializer.toBytes(makeValue(key, value));
- MapperKeyValueWriter mapWriter = new MapperKeyValueWriter();
-
- List mapperList = mapWriter.map(routingStrategy,
- keySerializer,
- valueSerializer,
- valueCompressor,
- keyCompressor,
- keySerializerDefinition,
- valueSerializerDefinition,
- keyBytes,
- valBytes,
- getSaveKeys(),
- md5er);
-
- for(int i = 0; i < mapperList.size(); i++) {
- voldemort.utils.Pair pair = (voldemort.utils.Pair) mapperList.get(i);
- BytesWritable outputKey = pair.getFirst();
- BytesWritable outputVal = pair.getSecond();
+ // Compress key and values if required
+ if(keySerializerDefinition.hasCompression()) {
+ keyBytes = keyCompressor.deflate(keyBytes);
+ }
- output.collect(outputKey, outputVal);
+ if(valueSerializerDefinition.hasCompression()) {
+ valBytes = valueCompressor.deflate(valBytes);
}
+ // Get the output byte arrays ready to populate
+ byte[] outputValue;
+ BytesWritable outputKey;
+
+ // Leave initial offset for (a) node id (b) partition id
+ // since they are written later
+ int offsetTillNow = 2 * ByteUtils.SIZE_OF_INT;
+
+ if(getSaveKeys()) {
+
+ // In order - 4 ( for node id ) + 4 ( partition id ) + 1 ( replica
+ // type - primary | secondary | tertiary... ] + 4 ( key size )
+ // size ) + 4 ( value size ) + key + value
+ outputValue = new byte[valBytes.length + keyBytes.length + ByteUtils.SIZE_OF_BYTE + 4
+ * ByteUtils.SIZE_OF_INT];
+
+ // Write key length - leave byte for replica type
+ offsetTillNow += ByteUtils.SIZE_OF_BYTE;
+ ByteUtils.writeInt(outputValue, keyBytes.length, offsetTillNow);
+
+ // Write value length
+ offsetTillNow += ByteUtils.SIZE_OF_INT;
+ ByteUtils.writeInt(outputValue, valBytes.length, offsetTillNow);
+
+ // Write key
+ offsetTillNow += ByteUtils.SIZE_OF_INT;
+ System.arraycopy(keyBytes, 0, outputValue, offsetTillNow, keyBytes.length);
+
+ // Write value
+ offsetTillNow += keyBytes.length;
+ System.arraycopy(valBytes, 0, outputValue, offsetTillNow, valBytes.length);
+
+ // Generate MR key - upper 8 bytes of 16 byte md5
+ outputKey = new BytesWritable(ByteUtils.copy(md5er.digest(keyBytes),
+ 0,
+ 2 * ByteUtils.SIZE_OF_INT));
+
+ } else {
+
+ // In order - 4 ( for node id ) + 4 ( partition id ) + value
+ outputValue = new byte[valBytes.length + 2 * ByteUtils.SIZE_OF_INT];
+
+ // Write value
+ System.arraycopy(valBytes, 0, outputValue, offsetTillNow, valBytes.length);
+
+ // Generate MR key - 16 byte md5
+ outputKey = new BytesWritable(md5er.digest(keyBytes));
+
+ }
+
+ // Generate partition and node list this key is destined for
+ List partitionList = routingStrategy.getPartitionList(keyBytes);
+ Node[] partitionToNode = routingStrategy.getPartitionToNode();
+
+ for(int replicaType = 0; replicaType < partitionList.size(); replicaType++) {
+
+ // Node id
+ ByteUtils.writeInt(outputValue,
+ partitionToNode[partitionList.get(replicaType)].getId(),
+ 0);
+
+ if(getSaveKeys()) {
+ // Primary partition id
+ ByteUtils.writeInt(outputValue, partitionList.get(0), ByteUtils.SIZE_OF_INT);
+
+ // Replica type
+ ByteUtils.writeBytes(outputValue,
+ replicaType,
+ 2 * ByteUtils.SIZE_OF_INT,
+ ByteUtils.SIZE_OF_BYTE);
+ } else {
+ // Partition id
+ ByteUtils.writeInt(outputValue,
+ partitionList.get(replicaType),
+ ByteUtils.SIZE_OF_INT);
+ }
+ BytesWritable outputVal = new BytesWritable(outputValue);
+
+ output.collect(outputKey, outputVal);
+
+ }
md5er.reset();
}
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AvroStoreBuilderMapper.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AvroStoreBuilderMapper.java
index 2318346387..4d52358dec 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AvroStoreBuilderMapper.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/AvroStoreBuilderMapper.java
@@ -35,6 +35,7 @@
import voldemort.VoldemortException;
import voldemort.cluster.Cluster;
+import voldemort.cluster.Node;
import voldemort.routing.ConsistentRoutingStrategy;
import voldemort.serialization.DefaultSerializerFactory;
import voldemort.serialization.Serializer;
@@ -46,7 +47,6 @@
import voldemort.store.compress.CompressionStrategy;
import voldemort.store.compress.CompressionStrategyFactory;
import voldemort.store.readonly.mr.utils.HadoopUtils;
-import voldemort.store.readonly.mr.utils.MapperKeyValueWriter;
import voldemort.utils.ByteUtils;
import voldemort.xml.ClusterMapper;
import voldemort.xml.StoreDefinitionsMapper;
@@ -92,24 +92,93 @@ public void map(GenericData.Record record,
byte[] keyBytes = keySerializer.toBytes(record.get(keyField));
byte[] valBytes = valueSerializer.toBytes(record.get(valField));
- MapperKeyValueWriter mapWriter = new MapperKeyValueWriter();
-
- List mapperList = mapWriter.map(routingStrategy,
- keySerializer,
- valueSerializer,
- valueCompressor,
- keyCompressor,
- keySerializerDefinition,
- valueSerializerDefinition,
- keyBytes,
- valBytes,
- getSaveKeys(),
- md5er);
-
- for(int i = 0; i < mapperList.size(); i++) {
- voldemort.utils.Pair pair = (voldemort.utils.Pair) mapperList.get(i);
- BytesWritable outputKey = pair.getFirst();
- BytesWritable outputVal = pair.getSecond();
+ // Compress key and values if required
+ if(keySerializerDefinition.hasCompression()) {
+ keyBytes = keyCompressor.deflate(keyBytes);
+ }
+
+ if(valueSerializerDefinition.hasCompression()) {
+ valBytes = valueCompressor.deflate(valBytes);
+ }
+
+ // Get the output byte arrays ready to populate
+ byte[] outputValue;
+ BytesWritable outputKey;
+
+ // Leave initial offset for (a) node id (b) partition id
+ // since they are written later
+ int offsetTillNow = 2 * ByteUtils.SIZE_OF_INT;
+
+ if(getSaveKeys()) {
+
+ // In order - 4 ( for node id ) + 4 ( partition id ) + 1 (
+ // replica
+ // type - primary | secondary | tertiary... ] + 4 ( key size )
+ // size ) + 4 ( value size ) + key + value
+ outputValue = new byte[valBytes.length + keyBytes.length + ByteUtils.SIZE_OF_BYTE + 4
+ * ByteUtils.SIZE_OF_INT];
+
+ // Write key length - leave byte for replica type
+ offsetTillNow += ByteUtils.SIZE_OF_BYTE;
+ ByteUtils.writeInt(outputValue, keyBytes.length, offsetTillNow);
+
+ // Write value length
+ offsetTillNow += ByteUtils.SIZE_OF_INT;
+ ByteUtils.writeInt(outputValue, valBytes.length, offsetTillNow);
+
+ // Write key
+ offsetTillNow += ByteUtils.SIZE_OF_INT;
+ System.arraycopy(keyBytes, 0, outputValue, offsetTillNow, keyBytes.length);
+
+ // Write value
+ offsetTillNow += keyBytes.length;
+ System.arraycopy(valBytes, 0, outputValue, offsetTillNow, valBytes.length);
+
+ // Generate MR key - upper 8 bytes of 16 byte md5
+ outputKey = new BytesWritable(ByteUtils.copy(md5er.digest(keyBytes),
+ 0,
+ 2 * ByteUtils.SIZE_OF_INT));
+
+ } else {
+
+ // In order - 4 ( for node id ) + 4 ( partition id ) + value
+ outputValue = new byte[valBytes.length + 2 * ByteUtils.SIZE_OF_INT];
+
+ // Write value
+ System.arraycopy(valBytes, 0, outputValue, offsetTillNow, valBytes.length);
+
+ // Generate MR key - 16 byte md5
+ outputKey = new BytesWritable(md5er.digest(keyBytes));
+
+ }
+
+ // Generate partition and node list this key is destined for
+ List partitionList = routingStrategy.getPartitionList(keyBytes);
+ Node[] partitionToNode = routingStrategy.getPartitionToNode();
+
+ for(int replicaType = 0; replicaType < partitionList.size(); replicaType++) {
+
+ // Node id
+ ByteUtils.writeInt(outputValue,
+ partitionToNode[partitionList.get(replicaType)].getId(),
+ 0);
+
+ if(getSaveKeys()) {
+ // Primary partition id
+ ByteUtils.writeInt(outputValue, partitionList.get(0), ByteUtils.SIZE_OF_INT);
+
+ // Replica type
+ ByteUtils.writeBytes(outputValue,
+ replicaType,
+ 2 * ByteUtils.SIZE_OF_INT,
+ ByteUtils.SIZE_OF_BYTE);
+ } else {
+ // Partition id
+ ByteUtils.writeInt(outputValue,
+ partitionList.get(replicaType),
+ ByteUtils.SIZE_OF_INT);
+ }
+ BytesWritable outputVal = new BytesWritable(outputValue);
ByteBuffer keyBuffer = null, valueBuffer = null;
@@ -118,7 +187,6 @@ public void map(GenericData.Record record,
keyBuffer.put(md5KeyBytes);
keyBuffer.rewind();
- byte[] outputValue = outputVal.getBytes();
valueBuffer = ByteBuffer.allocate(outputValue.length);
valueBuffer.put(outputValue);
valueBuffer.rewind();
@@ -128,7 +196,6 @@ public void map(GenericData.Record record,
collector.collect(p);
}
-
md5er.reset();
}
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/HadoopStoreBuilder.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/HadoopStoreBuilder.java
index c1e3c9c70f..529c8b30bd 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/HadoopStoreBuilder.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/HadoopStoreBuilder.java
@@ -34,6 +34,7 @@
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.PathFilter;
+import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.mapred.Counters;
import org.apache.hadoop.mapred.FileInputFormat;
@@ -69,6 +70,7 @@ public class HadoopStoreBuilder {
public static final long MIN_CHUNK_SIZE = 1L;
public static final long MAX_CHUNK_SIZE = (long) (1.9 * 1024 * 1024 * 1024);
public static final int DEFAULT_BUFFER_SIZE = 64 * 1024;
+ public static final short HADOOP_FILE_PERMISSION = 493;
private static final Logger logger = Logger.getLogger(HadoopStoreBuilder.class);
@@ -470,6 +472,8 @@ public void build() {
logger.info("No data generated for node " + node.getId()
+ ". Generating empty folder");
outputFs.mkdirs(nodePath); // Create empty folder
+ outputFs.setPermission(nodePath, new FsPermission(HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + nodePath);
}
if(checkSumType != CheckSumType.NONE) {
@@ -518,7 +522,10 @@ public boolean accept(Path arg0) {
}
// Write metadata
- FSDataOutputStream metadataStream = outputFs.create(new Path(nodePath, ".metadata"));
+ Path metadataPath = new Path(nodePath, ".metadata");
+ FSDataOutputStream metadataStream = outputFs.create(metadataPath);
+ outputFs.setPermission(metadataPath, new FsPermission(HADOOP_FILE_PERMISSION));
+ logger.info("Setting permission to 755 for " + metadataPath);
metadataStream.write(metadata.toJsonString().getBytes());
metadataStream.flush();
metadataStream.close();
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/AbstractHadoopJob.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/AbstractHadoopJob.java
index bcd0170e9f..53a126a627 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/AbstractHadoopJob.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/AbstractHadoopJob.java
@@ -59,6 +59,10 @@ public abstract class AbstractHadoopJob extends AbstractJob {
private final Props _props;
private RunningJob _runningJob;
+ private final static String voldemortLibPath = "voldemort.distributedcache";
+
+ private final static String hadoopLibPath = "hdfs.default.classpath.dir";
+
public AbstractHadoopJob(String name, Props props) {
super(name);
this._props = props;
@@ -216,41 +220,67 @@ public boolean accept(Path arg0) {
}
}
- String hadoopCacheJarDir = _props.getString("hdfs.default.classpath.dir", null);
- if(hadoopCacheJarDir != null) {
+ // this property can be set by azkaban to manage voldemort lib path on
+ // hdfs
+ addToDistributedCache(voldemortLibPath, conf);
+
+ boolean isAddFiles = _props.getBoolean("hdfs.default.classpath.dir.enable", false);
+ if(isAddFiles) {
+ addToDistributedCache(hadoopLibPath, conf);
+ }
+
+ // May want to add this to HadoopUtils, but will await refactoring
+ for(String key: getProps().keySet()) {
+ String lowerCase = key.toLowerCase();
+ if(lowerCase.startsWith(HADOOP_PREFIX)) {
+ String newKey = key.substring(HADOOP_PREFIX.length());
+ conf.set(newKey, getProps().get(key));
+ }
+ }
+
+ HadoopUtils.setPropsInJob(conf, getProps());
+
+ // http://hadoop.apache.org/docs/r1.1.1/mapred_tutorial.html#Job+Credentials
+
+ // The MapReduce tokens are provided so that tasks can spawn jobs if
+ // they wish to.
+ // The tasks authenticate to the JobTracker via the MapReduce delegation
+ // tokens.
+ if(System.getenv("HADOOP_TOKEN_FILE_LOCATION") != null) {
+ conf.set("mapreduce.job.credentials.binary",
+ System.getenv("HADOOP_TOKEN_FILE_LOCATION"));
+ }
+ return conf;
+ }
+
+ /*
+ * Loads jar files into distributed cache This way the mappers and reducers
+ * have the jars they need at run time
+ */
+ private void addToDistributedCache(String propertyName, JobConf conf) throws IOException {
+ String jarDir = _props.getString(propertyName, null);
+ if(jarDir != null) {
FileSystem fs = FileSystem.get(conf);
if(fs != null) {
- FileStatus[] status = fs.listStatus(new Path(hadoopCacheJarDir));
+ FileStatus[] status = fs.listStatus(new Path(jarDir));
if(status != null) {
for(int i = 0; i < status.length; ++i) {
if(!status[i].isDir()) {
- Path path = new Path(hadoopCacheJarDir, status[i].getPath().getName());
+ Path path = new Path(jarDir, status[i].getPath().getName());
info("Adding Jar to Distributed Cache Archive File:" + path);
DistributedCache.addFileToClassPath(path, conf);
}
}
} else {
- info("hdfs.default.classpath.dir " + hadoopCacheJarDir + " is empty.");
+ info(propertyName + jarDir + " is empty.");
}
} else {
- info("hdfs.default.classpath.dir " + hadoopCacheJarDir
- + " filesystem doesn't exist");
- }
- }
-
- // May want to add this to HadoopUtils, but will await refactoring
- for(String key: getProps().keySet()) {
- String lowerCase = key.toLowerCase();
- if(lowerCase.startsWith(HADOOP_PREFIX)) {
- String newKey = key.substring(HADOOP_PREFIX.length());
- conf.set(newKey, getProps().get(key));
+ info(propertyName + jarDir + " filesystem doesn't exist");
}
}
- HadoopUtils.setPropsInJob(conf, getProps());
- return conf;
}
public Props getProps() {
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortBuildAndPushJob.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortBuildAndPushJob.java
index eb87c77ac1..49128e0f2f 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortBuildAndPushJob.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortBuildAndPushJob.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 LinkedIn, Inc
+ * Copyright 2008-2013 LinkedIn, Inc
*
* 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
@@ -40,6 +40,7 @@
import org.apache.hadoop.mapred.JobConf;
import org.apache.log4j.Logger;
+import voldemort.client.ClientConfig;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
import voldemort.cluster.Cluster;
@@ -98,11 +99,19 @@ public class VoldemortBuildAndPushJob extends AbstractJob {
private static final String AVRO_GENERIC_VERSIONED_TYPE_NAME = "avro-generic-versioned";
+ // new properties for the push job
+
+ private final String hdfsFetcherPort;
+ private final String hdfsFetcherProtocol;
+
/* Informed stuff */
private final String informedURL = "http://informed.corp.linkedin.com/_post";
private final List informedResults;
private ExecutorService informedExecutor;
+ private String jsonKeyField;
+ private String jsonValueField;
+
public VoldemortBuildAndPushJob(String name, Props props) {
super(name);
this.props = props;
@@ -134,6 +143,12 @@ public VoldemortBuildAndPushJob(String name, Props props) {
this.informedResults = Lists.newArrayList();
this.informedExecutor = Executors.newFixedThreadPool(2);
+ this.hdfsFetcherProtocol = props.getString("voldemort.fetcher.protocol", "hftp");
+ this.hdfsFetcherPort = props.getString("voldemort.fetcher.port", "50070");
+
+ log.info("voldemort.fetcher.protocol is set to : " + hdfsFetcherProtocol);
+ log.info("voldemort.fetcher.port is set to : " + hdfsFetcherPort);
+
isAvroJob = props.getBoolean("build.type.avro", false);
// Set default to false
@@ -161,6 +176,8 @@ public void run() throws Exception {
boolean build = props.getBoolean("build", true);
boolean push = props.getBoolean("push", true);
+ jsonKeyField = props.getString("key.selection", null);
+ jsonValueField = props.getString("value.selection", null);
if(build && push && dataDirs.size() != 1) {
// Should have only one data directory ( which acts like the parent
// directory to all
@@ -254,9 +271,16 @@ public void verifySchema(String url) throws Exception {
String owners = props.getString("push.store.owners", "");
String keySchema = "\n\t\tjson\n\t\t"
+ schema.getKeyType() + "\n\t";
+ if(jsonKeyField != null && jsonKeyField.length() > 0)
+ keySchema = "\n\t\tjson\n\t\t"
+ + schema.getKeyType().subtype(jsonKeyField) + "\n\t";
String valSchema = "\n\t\tjson\n\t\t"
+ schema.getValueType() + "\n\t";
+ if(jsonValueField != null && jsonValueField.length() > 0)
+ valSchema = "\n\t\tjson\n\t\t"
+ + schema.getValueType().subtype(jsonValueField) + "\n\t";
+
boolean hasCompression = false;
if(props.containsKey("build.compress.value"))
hasCompression = true;
@@ -295,10 +319,10 @@ public void verifySchema(String url) throws Exception {
// get store def from cluster
log.info("Getting store definition from: " + url + " (node id " + this.nodeId + ")");
- AdminClient adminClient = new AdminClient(url, new AdminClientConfig());
+ AdminClient adminClient = new AdminClient(url, new AdminClientConfig(), new ClientConfig());
try {
- List remoteStoreDefs = adminClient.getRemoteStoreDefList(this.nodeId)
- .getValue();
+ List remoteStoreDefs = adminClient.metadataMgmtOps.getRemoteStoreDefList(this.nodeId)
+ .getValue();
boolean foundStore = false;
// go over all store defs and see if one has the same name as the
@@ -412,7 +436,7 @@ public void verifySchema(String url) throws Exception {
log.info("Could not find store " + storeName
+ " on Voldemort. Adding it to all nodes ");
- adminClient.addStore(newStoreDef);
+ adminClient.storeMgmtOps.addStore(newStoreDef);
}
// don't use newStoreDef because we want to ALWAYS use the JSON
@@ -434,7 +458,7 @@ public void verifySchema(String url) throws Exception {
valSchema)));
cluster = adminClient.getAdminClientCluster();
} finally {
- adminClient.stop();
+ adminClient.close();
}
}
@@ -446,8 +470,8 @@ public String runBuildStore(Props props, String url) throws Exception {
URI uri = new URI(url);
Path outputDir = new Path(props.getString("build.output.dir"), uri.getHost());
Path inputPath = getInputPath();
- String keySelection = props.getString("build.key.selection", null);
- String valSelection = props.getString("build.value.selection", null);
+ String keySelection = props.getString("key.selection", null);
+ String valSelection = props.getString("value.selection", null);
CheckSumType checkSumType = CheckSum.fromString(props.getString("checksum.type",
CheckSum.toString(CheckSumType.MD5)));
boolean saveKeys = props.getBoolean("save.keys", true);
@@ -632,10 +656,10 @@ public void verifyAvroSchemaAndVersions(String url, boolean isVersioned) throws
// get store def from cluster
log.info("Getting store definition from: " + url + " (node id " + this.nodeId + ")");
- AdminClient adminClient = new AdminClient(url, new AdminClientConfig());
+ AdminClient adminClient = new AdminClient(url, new AdminClientConfig(), new ClientConfig());
try {
- List remoteStoreDefs = adminClient.getRemoteStoreDefList(this.nodeId)
- .getValue();
+ List remoteStoreDefs = adminClient.metadataMgmtOps.getRemoteStoreDefList(this.nodeId)
+ .getValue();
boolean foundStore = false;
// go over all store defs and see if one has the same name as the
@@ -791,7 +815,7 @@ public void verifyAvroSchemaAndVersions(String url, boolean isVersioned) throws
log.info("Could not find store " + storeName
+ " on Voldemort. Adding it to all nodes ");
- adminClient.addStore(newStoreDef);
+ adminClient.storeMgmtOps.addStore(newStoreDef);
}
storeDefs = ImmutableList.of(VoldemortUtils.getStoreDef(VoldemortUtils.getStoreDefXml(storeName,
@@ -806,7 +830,7 @@ public void verifyAvroSchemaAndVersions(String url, boolean isVersioned) throws
valSchema)));
cluster = adminClient.getAdminClientCluster();
} finally {
- adminClient.stop();
+ adminClient.close();
}
}
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortMultiStoreBuildAndPushJob.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortMultiStoreBuildAndPushJob.java
index 80280a5d53..8ed0d86c9b 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortMultiStoreBuildAndPushJob.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortMultiStoreBuildAndPushJob.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 LinkedIn, Inc
+ * Copyright 2008-2013 LinkedIn, Inc
*
* 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
@@ -43,6 +43,7 @@
import org.apache.log4j.Logger;
import voldemort.VoldemortException;
+import voldemort.client.ClientConfig;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
import voldemort.cluster.Cluster;
@@ -253,7 +254,8 @@ public List call() throws Exception {
// verification of
// schema + pushing
adminClient = new AdminClient(url,
- new AdminClientConfig());
+ new AdminClientConfig(),
+ new ClientConfig());
// Verify the store
// exists ( If not,
@@ -309,7 +311,7 @@ public List call() throws Exception {
+ url
+ "'");
- Map pushVersions = adminClient.getROMaxVersion(Lists.newArrayList(storeName));
+ Map pushVersions = adminClient.readonlyOps.getROMaxVersion(Lists.newArrayList(storeName));
if(pushVersions == null
|| !pushVersions.containsKey(storeName)) {
@@ -388,7 +390,7 @@ public List call() throws Exception {
TimeUnit.SECONDS);
}
if(adminClient != null) {
- adminClient.stop();
+ adminClient.close();
}
}
}
@@ -431,7 +433,9 @@ public List call() throws Exception {
AdminClient adminClient = null;
try {
- adminClient = new AdminClient(cluster, new AdminClientConfig());
+ adminClient = new AdminClient(cluster,
+ new AdminClientConfig(),
+ new ClientConfig());
for(final String storeName: storeNames) {
// Check if the [ cluster , store name ] succeeded. We
// need to roll it back
@@ -448,7 +452,9 @@ public List call() throws Exception {
log.info("Deleting data ( " + nodeDir
+ " ) for successful pushes to '" + clusterUrl
+ "' and store '" + storeName + "' and node " + nodeId);
- adminClient.failedFetchStore(nodeId, storeName, nodeDir);
+ adminClient.readonlyOps.failedFetchStore(nodeId,
+ storeName,
+ nodeDir);
log.info("Successfully deleted data for successful pushes to '"
+ clusterUrl + "' and store '" + storeName
+ "' and node " + nodeId);
@@ -464,7 +470,7 @@ public List call() throws Exception {
}
} finally {
if(adminClient != null) {
- adminClient.stop();
+ adminClient.close();
}
}
}
@@ -500,7 +506,9 @@ public List call() throws Exception {
String url = clusterUrls.get(index);
Cluster cluster = urlToCluster.get(url);
- AdminClient adminClient = new AdminClient(cluster, new AdminClientConfig());
+ AdminClient adminClient = new AdminClient(cluster,
+ new AdminClientConfig(),
+ new ClientConfig());
log.info("Swapping all stores on cluster " + url);
try {
@@ -520,10 +528,10 @@ public List call() throws Exception {
previousNodeDirPerClusterStore.put(key,
Pair.create(node.getId(),
- adminClient.swapStore(node.getId(),
- storeName,
- nodeDirPerClusterStore.get(key)
- .get(node.getId()))));
+ adminClient.readonlyOps.swapStore(node.getId(),
+ storeName,
+ nodeDirPerClusterStore.get(key)
+ .get(node.getId()))));
log.info("Successfully swapped '" + storeName + "' store on cluster "
+ url + " and node " + node.getId());
@@ -532,7 +540,7 @@ public List call() throws Exception {
}
} finally {
if(adminClient != null) {
- adminClient.stop();
+ adminClient.close();
}
}
}
@@ -548,16 +556,18 @@ public List call() throws Exception {
log.info("Rolling back for cluster " + url + " and store "
+ clusterStoreTuple.getSecond());
- AdminClient adminClient = new AdminClient(cluster, new AdminClientConfig());
+ AdminClient adminClient = new AdminClient(cluster,
+ new AdminClientConfig(),
+ new ClientConfig());
try {
for(Pair nodeToPreviousDir: nodeToPreviousDirs) {
log.info("Rolling back for cluster " + url + " and store "
+ clusterStoreTuple.getSecond() + " and node "
+ nodeToPreviousDir.getFirst() + " to dir "
+ nodeToPreviousDir.getSecond());
- adminClient.rollbackStore(nodeToPreviousDir.getFirst(),
- nodeToPreviousDir.getSecond(),
- ReadOnlyUtils.getVersionId(new File(nodeToPreviousDir.getSecond())));
+ adminClient.readonlyOps.rollbackStore(nodeToPreviousDir.getFirst(),
+ nodeToPreviousDir.getSecond(),
+ ReadOnlyUtils.getVersionId(new File(nodeToPreviousDir.getSecond())));
log.info("Successfully rolled back for cluster " + url + " and store "
+ clusterStoreTuple.getSecond() + " and node "
+ nodeToPreviousDir.getFirst() + " to dir "
@@ -566,7 +576,7 @@ public List call() throws Exception {
}
} finally {
if(adminClient != null) {
- adminClient.stop();
+ adminClient.close();
}
}
}
@@ -667,8 +677,8 @@ public Pair verifySchema(String storeName,
// get store def from cluster
log.info("Getting store definition from: " + url + " ( node id " + this.nodeId + " )");
- List remoteStoreDefs = adminClient.getRemoteStoreDefList(this.nodeId)
- .getValue();
+ List remoteStoreDefs = adminClient.metadataMgmtOps.getRemoteStoreDefList(this.nodeId)
+ .getValue();
boolean foundStore = false;
// go over all store defs and see if one has the same name as the store
@@ -771,7 +781,7 @@ public Pair verifySchema(String storeName,
log.info("Could not find store " + storeName
+ " on Voldemort. Adding it to all nodes for cluster " + url);
- adminClient.addStore(newStoreDef);
+ adminClient.storeMgmtOps.addStore(newStoreDef);
}
// don't use newStoreDef because we want to ALWAYS use the JSON
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortRollbackJob.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortRollbackJob.java
index bb22c1b1fd..696cb72ae4 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortRollbackJob.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortRollbackJob.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 LinkedIn, Inc
+ * Copyright 2008-2013 LinkedIn, Inc
*
* 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
@@ -27,6 +27,7 @@
import org.apache.log4j.Logger;
import voldemort.VoldemortException;
+import voldemort.client.ClientConfig;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
import voldemort.cluster.Cluster;
@@ -75,7 +76,9 @@ public void run() throws Exception {
ExecutorService service = null;
try {
service = Executors.newCachedThreadPool();
- adminClient = new AdminClient(clusterUrl, new AdminClientConfig());
+ adminClient = new AdminClient(clusterUrl,
+ new AdminClientConfig(),
+ new ClientConfig());
Cluster cluster = adminClient.getAdminClientCluster();
AdminStoreSwapper swapper = new AdminStoreSwapper(cluster,
service,
@@ -88,8 +91,8 @@ public void run() throws Exception {
// Get the current version for all stores on all nodes
Map> previousVersions = Maps.newHashMap();
for(Node node: cluster.getNodes()) {
- Map currentVersion = adminClient.getROCurrentVersion(node.getId(),
- storeNames);
+ Map currentVersion = adminClient.readonlyOps.getROCurrentVersion(node.getId(),
+ storeNames);
log.info("Retrieving current version information on node " + node.getId());
Map previousVersion = Maps.newHashMap();
@@ -123,7 +126,7 @@ public void run() throws Exception {
service = null;
}
if(adminClient != null) {
- adminClient.stop();
+ adminClient.close();
adminClient = null;
}
}
diff --git a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortSwapJob.java b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortSwapJob.java
index f4e51b5dd1..6da1767ee6 100644
--- a/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortSwapJob.java
+++ b/contrib/hadoop-store-builder/src/java/voldemort/store/readonly/mr/azkaban/VoldemortSwapJob.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 LinkedIn, Inc
+ * Copyright 2008-2013 LinkedIn, Inc
*
* 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
@@ -28,6 +28,7 @@
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapred.JobConf;
+import voldemort.client.ClientConfig;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
import voldemort.cluster.Cluster;
@@ -43,16 +44,23 @@ public class VoldemortSwapJob extends AbstractJob {
private final Props _props;
private VoldemortSwapConf swapConf;
+ private String hdfsFetcherProtocol;
+ private String hdfsFetcherPort;
public VoldemortSwapJob(String id, Props props) throws IOException {
super(id);
_props = props;
+
+ this.hdfsFetcherProtocol = props.getString("voldemort.fetcher.protocol", "hftp");
+ this.hdfsFetcherPort = props.getString("voldemort.fetcher.port", "50070");
swapConf = new VoldemortSwapConf(_props);
}
public VoldemortSwapJob(String id, Props props, VoldemortSwapConf conf) throws IOException {
super(id);
_props = props;
+ this.hdfsFetcherProtocol = props.getString("voldemort.fetcher.protocol", "hftp");
+ this.hdfsFetcherPort = props.getString("voldemort.fetcher.port", "50070");
swapConf = conf;
}
@@ -149,17 +157,6 @@ public void run() throws Exception {
Path dataPath = new Path(dataDir);
dataDir = dataPath.makeQualified(FileSystem.get(conf)).toString();
- /*
- * Set the protocol according to config: webhdfs if its enabled
- * Otherwise use hftp.
- */
- Configuration hadoopConfig = new Configuration();
- String protocolName = hadoopConfig.get("dfs.webhdfs.enabled");
- String protocolPort = "";
- if(hadoopConfig.get("dfs.http.address").split(":").length >= 2)
- protocolPort = hadoopConfig.get("dfs.http.address").split(":")[1];
- protocolName = (protocolName == null) ? "hftp" : "webhdfs";
-
/*
* Replace the default protocol and port with the one derived as above
*/
@@ -171,25 +168,24 @@ public void run() throws Exception {
existingPort = pathComponents[2].split("/")[0];
}
info("Existing protocol = " + existingProtocol + " and port = " + existingPort);
- if(protocolName.length() > 0 && protocolPort.length() > 0) {
- dataDir = dataDir.replaceFirst(existingProtocol, protocolName);
- dataDir = dataDir.replaceFirst(existingPort, protocolPort);
+ if(hdfsFetcherProtocol.length() > 0 && hdfsFetcherPort.length() > 0) {
+ dataDir = dataDir.replaceFirst(existingProtocol, this.hdfsFetcherProtocol);
+ dataDir = dataDir.replaceFirst(existingPort, this.hdfsFetcherPort);
}
- info("dfs.webhdfs.enabled = " + hadoopConfig.get("dfs.webhdfs.enabled")
- + " and new protocol = " + protocolName + " and port = " + protocolPort);
// Create admin client
AdminClient client = new AdminClient(cluster,
new AdminClientConfig().setMaxConnectionsPerNode(cluster.getNumberOfNodes())
.setAdminConnectionTimeoutSec(httpTimeoutMs / 1000)
- .setMaxBackoffDelayMs(swapConf.getMaxBackoffDelayMs()));
+ .setMaxBackoffDelayMs(swapConf.getMaxBackoffDelayMs()),
+ new ClientConfig());
if(pushVersion == -1L) {
// Need to retrieve max version
ArrayList stores = new ArrayList();
stores.add(storeName);
- Map pushVersions = client.getROMaxVersion(stores);
+ Map pushVersions = client.readonlyOps.getROMaxVersion(stores);
if(pushVersions == null || !pushVersions.containsKey(storeName)) {
throw new RuntimeException("Push version could not be determined for store "
diff --git a/contrib/hadoop-store-builder/test/voldemort/store/readonly/fetcher/HDFSFetcherAdvancedTest.java b/contrib/hadoop-store-builder/test/voldemort/store/readonly/fetcher/HDFSFetcherAdvancedTest.java
new file mode 100644
index 0000000000..6157d58a20
--- /dev/null
+++ b/contrib/hadoop-store-builder/test/voldemort/store/readonly/fetcher/HDFSFetcherAdvancedTest.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2008-2009 LinkedIn, Inc
+ *
+ * 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.
+ */
+
+package voldemort.store.readonly.fetcher;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Random;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mortbay.jetty.EofException;
+
+import voldemort.TestUtils;
+import voldemort.server.VoldemortConfig;
+import voldemort.store.readonly.ReadOnlyStorageFormat;
+import voldemort.store.readonly.ReadOnlyStorageMetadata;
+import voldemort.store.readonly.checksum.CheckSum;
+import voldemort.store.readonly.checksum.CheckSum.CheckSumType;
+import voldemort.store.readonly.checksum.CheckSumTests;
+import voldemort.store.readonly.fetcher.HdfsFetcher.CopyStats;
+import voldemort.utils.Utils;
+
+/*
+ * This test suite tests the HDFSFetcher We test the fetch from hadoop by
+ * simulating exceptions during fetches
+ */
+public class HDFSFetcherAdvancedTest {
+
+ public static final Random UNSEEDED_RANDOM = new Random();
+
+ /*
+ * Tests that HdfsFetcher can correctly fetch a file in happy path
+ */
+ @Test
+ public void testCheckSumMetadata() throws Exception {
+
+ // Generate 0_0.[index | data] and their corresponding metadata
+ File testSourceDirectory = createTempDir();
+ File testDestinationDirectory = testSourceDirectory;
+
+ File indexFile = new File(testSourceDirectory, "0_0.index");
+ FileUtils.writeByteArrayToFile(indexFile, TestUtils.randomBytes(100));
+
+ File dataFile = new File(testSourceDirectory, "0_0.data");
+ FileUtils.writeByteArrayToFile(dataFile, TestUtils.randomBytes(400));
+
+ HdfsFetcher fetcher = new HdfsFetcher();
+
+ File metadataFile = new File(testSourceDirectory, ".metadata");
+
+ ReadOnlyStorageMetadata metadata = new ReadOnlyStorageMetadata();
+ metadata.add(ReadOnlyStorageMetadata.FORMAT, ReadOnlyStorageFormat.READONLY_V2.getCode());
+
+ metadata.add(ReadOnlyStorageMetadata.CHECKSUM_TYPE, CheckSum.toString(CheckSumType.MD5));
+ // Correct metadata checksum - MD5
+ metadata.add(ReadOnlyStorageMetadata.CHECKSUM,
+ new String(Hex.encodeHex(CheckSumTests.calculateCheckSum(testSourceDirectory.listFiles(),
+ CheckSumType.MD5))));
+ FileUtils.writeStringToFile(metadataFile, metadata.toJsonString());
+
+ File tempDest = new File(testDestinationDirectory.getAbsolutePath() + "1");
+ if(tempDest.exists()) {
+
+ deleteDir(tempDest);
+ }
+
+ File fetchedFile = fetcher.fetch(testSourceDirectory.getAbsolutePath(),
+ testDestinationDirectory.getAbsolutePath() + "1");
+
+ assertNotNull(fetchedFile);
+ assertEquals(fetchedFile.getAbsolutePath(), testDestinationDirectory.getAbsolutePath()
+ + "1");
+
+ tempDest = new File(testDestinationDirectory.getAbsolutePath() + "1");
+ if(tempDest.exists()) {
+
+ deleteDir(tempDest);
+ }
+
+ }
+
+ public static File createTempDir() {
+ return createTempDir(new File(System.getProperty("java.io.tmpdir")));
+ }
+
+ /**
+ * Create a temporary directory that is a child of the given directory
+ *
+ * @param parent The parent directory
+ * @return The temporary directory
+ */
+ public static File createTempDir(File parent) {
+ File temp = new File(parent, "hdfsfetchertestadvanced");
+ temp.delete();
+ temp.mkdir();
+ temp.deleteOnExit();
+ return temp;
+ }
+
+ /**
+ * Convenient method to execute private methods from other classes.
+ *
+ * @param test Instance of the class we want to test
+ * @param methodName Name of the method we want to test
+ * @param params Arguments we want to pass to the method
+ * @return Object with the result of the executed method
+ * @throws Exception
+ */
+ private Object invokePrivateMethod(Object test, String methodName, Object params[])
+ throws Exception {
+ Object ret = null;
+
+ final Method[] methods = test.getClass().getDeclaredMethods();
+ for(int i = 0; i < methods.length; ++i) {
+ if(methods[i].getName().equals(methodName)) {
+ methods[i].setAccessible(true);
+ ret = methods[i].invoke(test, params);
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ /*
+ * Tests that HdfsFetcher can correctly fetch a file when there is an
+ * IOException, specifically an EofException during the fetch
+ */
+ @Test
+ public void testEofExceptionIntermittent() throws Exception {
+
+ File testSourceDirectory = createTempDir();
+ File testDestinationDirectory = testSourceDirectory;
+
+ File indexFile = new File(testSourceDirectory, "0_0.index");
+ byte[] indexBytes = TestUtils.randomBytes(100);
+ FileUtils.writeByteArrayToFile(indexFile, indexBytes);
+
+ final Path source = new Path(indexFile.getAbsolutePath());
+ CheckSum fileCheckSumGenerator = CheckSum.getInstance(CheckSumType.MD5);
+
+ fileCheckSumGenerator.update(indexBytes);
+ byte[] checksumCalculated = calculateCheckSumForFile(source);
+
+ HdfsFetcher fetcher = new HdfsFetcher();
+
+ Configuration config = new Configuration();
+
+ FileSystem fs = source.getFileSystem(config);
+
+ FileSystem spyfs = Mockito.spy(fs);
+ CopyStats stats = new CopyStats(testSourceDirectory.getAbsolutePath(), sizeOfPath(fs,
+ source));
+
+ File destination = new File(testDestinationDirectory.getAbsolutePath() + "1");
+ Utils.mkdirs(destination);
+ File copyLocation = new File(destination, "0_0.index");
+
+ Mockito.doThrow(new IOException())
+ .doAnswer(Mockito.CALLS_REAL_METHODS)
+ .when(spyfs)
+ .open(source);
+
+ Object[] params = { spyfs, source, copyLocation, stats, CheckSumType.MD5 };
+
+ CheckSum ckSum = (CheckSum) this.invokePrivateMethod(fetcher,
+ "copyFileWithCheckSum",
+ params);
+
+ assertEquals(Arrays.equals(ckSum.getCheckSum(), checksumCalculated), true);
+
+ }
+
+ /*
+ * Tests that HdfsFetcher can correctly fetch a file when there is an
+ * IOException, specifically an EofException during the fetch this test case
+ * is different from the earlier one since it simulates an excpetion midway
+ * a fetch
+ */
+
+ @Test
+ public void testEofExceptionIntermittentDuringFetch() throws Exception {
+
+ File testSourceDirectory = createTempDir();
+ File testDestinationDirectory = testSourceDirectory;
+
+ File indexFile = new File(testSourceDirectory, "0_0.index");
+ byte[] indexBytes = TestUtils.randomBytes(VoldemortConfig.DEFAULT_BUFFER_SIZE * 3);
+ FileUtils.writeByteArrayToFile(indexFile, indexBytes);
+
+ final Path source = new Path(indexFile.getAbsolutePath());
+ CheckSum fileCheckSumGenerator = CheckSum.getInstance(CheckSumType.MD5);
+
+ fileCheckSumGenerator.update(indexBytes);
+ byte[] checksumCalculated = calculateCheckSumForFile(source);
+
+ HdfsFetcher fetcher = new HdfsFetcher();
+
+ Configuration config = new Configuration();
+
+ FileSystem fs = source.getFileSystem(config);
+
+ FileSystem spyfs = Mockito.spy(fs);
+ CopyStats stats = new CopyStats(testSourceDirectory.getAbsolutePath(), sizeOfPath(fs,
+ source));
+
+ File destination = new File(testDestinationDirectory.getAbsolutePath() + "1");
+ Utils.mkdirs(destination);
+ File copyLocation = new File(destination, "0_0.index");
+
+ FSDataInputStream input = null;
+
+ input = fs.open(source);
+ FSDataInputStream spyinput = Mockito.spy(input);
+
+ Mockito.doAnswer(Mockito.CALLS_REAL_METHODS)
+ .doThrow(new EofException())
+ .when(spyinput)
+ .read();
+
+ Mockito.doReturn(spyinput).doReturn(input).when(spyfs).open(source);
+
+ Object[] params = { spyfs, source, copyLocation, stats, CheckSumType.MD5 };
+
+ CheckSum ckSum = (CheckSum) this.invokePrivateMethod(fetcher,
+ "copyFileWithCheckSum",
+ params);
+
+ assertEquals(Arrays.equals(ckSum.getCheckSum(), checksumCalculated), true);
+
+ }
+
+ /*
+ * Tests that HdfsFetcher can correctly handle when there is an
+ * RuntimeException
+ *
+ * Expected- the exception should be consumed without spilling it over
+ */
+
+ @Test
+ public void testIntermittentRuntimeExceptions() throws Exception {
+
+ File testSourceDirectory = createTempDir();
+ File testDestinationDirectory = createTempDir();
+
+ File indexFile = new File(testSourceDirectory, "0_0.index");
+ byte[] indexBytes = TestUtils.randomBytes(100);
+ FileUtils.writeByteArrayToFile(indexFile, indexBytes);
+
+ final Path source = new Path(indexFile.getAbsolutePath());
+ CheckSum fileCheckSumGenerator = CheckSum.getInstance(CheckSumType.MD5);
+
+ fileCheckSumGenerator.update(indexBytes);
+
+ HdfsFetcher fetcher = new HdfsFetcher();
+
+ Configuration config = new Configuration();
+
+ FileSystem fs = source.getFileSystem(config);
+
+ FileSystem spyfs = Mockito.spy(fs);
+ CopyStats stats = new CopyStats(testSourceDirectory.getAbsolutePath(), sizeOfPath(fs,
+ source));
+
+ File destination = new File(testDestinationDirectory.getAbsolutePath() + "1");
+ Utils.mkdirs(destination);
+ File copyLocation = new File(destination, "0_0.index");
+
+ Mockito.doThrow(new RuntimeException())
+ .doAnswer(Mockito.CALLS_REAL_METHODS)
+ .when(spyfs)
+ .open(source);
+
+ Object[] params = { spyfs, source, copyLocation, stats, CheckSumType.MD5 };
+
+ CheckSum ckSum = (CheckSum) this.invokePrivateMethod(fetcher,
+ "copyFileWithCheckSum",
+ params);
+
+ }
+
+ private long sizeOfPath(FileSystem fs, Path path) throws IOException {
+ long size = 0;
+ FileStatus[] statuses = fs.listStatus(path);
+ if(statuses != null) {
+ for(FileStatus status: statuses) {
+ if(status.isDir())
+ size += sizeOfPath(fs, status.getPath());
+ else
+ size += status.getLen();
+ }
+ }
+ return size;
+ }
+
+ /*
+ * Helper method to delete a non empty directory
+ */
+ public static boolean deleteDir(File dir) {
+ if(dir.isDirectory()) {
+ String[] children = dir.list();
+ for(int i = 0; i < children.length; i++) {
+ boolean success = deleteDir(new File(dir, children[i]));
+ if(!success) {
+ return false;
+ }
+ }
+ }
+ return dir.delete();
+ }
+
+ /*
+ * Helper method to calculate checksum for a single file
+ */
+ private byte[] calculateCheckSumForFile(Path source) throws Exception {
+ CheckSum fileCheckSumGenerator = CheckSum.getInstance(CheckSumType.MD5);
+ byte[] buffer = new byte[VoldemortConfig.DEFAULT_BUFFER_SIZE];
+
+ FSDataInputStream input = null;
+
+ Configuration config = new Configuration();
+
+ FileSystem fs = source.getFileSystem(config);
+ input = fs.open(source);
+
+ while(true) {
+ int read = input.read(buffer);
+ if(read < 0) {
+ break;
+ }
+ // Update the per file checksum
+ if(fileCheckSumGenerator != null) {
+ fileCheckSumGenerator.update(buffer, 0, read);
+ }
+
+ }
+
+ return fileCheckSumGenerator.getCheckSum();
+ }
+}
diff --git a/contrib/krati/src/java/voldemort/store/krati/KratiStorageConfiguration.java b/contrib/krati/src/java/voldemort/store/krati/KratiStorageConfiguration.java
index 5f3a41574c..f5d2590e62 100644
--- a/contrib/krati/src/java/voldemort/store/krati/KratiStorageConfiguration.java
+++ b/contrib/krati/src/java/voldemort/store/krati/KratiStorageConfiguration.java
@@ -8,6 +8,7 @@
import org.apache.log4j.Logger;
import voldemort.VoldemortException;
+import voldemort.routing.RoutingStrategy;
import voldemort.server.VoldemortConfig;
import voldemort.store.StorageConfiguration;
import voldemort.store.StorageEngine;
@@ -45,7 +46,8 @@ public KratiStorageConfiguration(VoldemortConfig config) {
public void close() {}
- public StorageEngine getStore(StoreDefinition storeDef) {
+ public StorageEngine getStore(StoreDefinition storeDef,
+ RoutingStrategy strategy) {
synchronized(lock) {
File storeDir = new File(dataDirectory, storeDef.getName());
if(!storeDir.exists()) {
diff --git a/contrib/krati/src/java/voldemort/store/krati/KratiStorageEngine.java b/contrib/krati/src/java/voldemort/store/krati/KratiStorageEngine.java
index 098c083df3..c30eea305f 100644
--- a/contrib/krati/src/java/voldemort/store/krati/KratiStorageEngine.java
+++ b/contrib/krati/src/java/voldemort/store/krati/KratiStorageEngine.java
@@ -20,25 +20,21 @@
import org.apache.log4j.Logger;
import voldemort.VoldemortException;
-import voldemort.store.NoSuchCapabilityException;
-import voldemort.store.StorageEngine;
-import voldemort.store.StoreCapabilityType;
+import voldemort.store.AbstractStorageEngine;
import voldemort.store.StoreUtils;
import voldemort.utils.ByteArray;
import voldemort.utils.ClosableIterator;
import voldemort.utils.Pair;
import voldemort.utils.StripedLock;
-import voldemort.utils.Utils;
import voldemort.versioning.ObsoleteVersionException;
import voldemort.versioning.Occurred;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Version;
import voldemort.versioning.Versioned;
-public class KratiStorageEngine implements StorageEngine {
+public class KratiStorageEngine extends AbstractStorageEngine {
private static final Logger logger = Logger.getLogger(KratiStorageEngine.class);
- private final String name;
private final DynamicDataStore datastore;
private final StripedLock locks;
@@ -49,7 +45,7 @@ public KratiStorageEngine(String name,
double hashLoadFactor,
int initLevel,
File dataDirectory) {
- this.name = Utils.notNull(name);
+ super(name);
try {
this.datastore = new DynamicDataStore(dataDirectory,
initLevel,
@@ -64,16 +60,7 @@ public KratiStorageEngine(String name,
}
- public Object getCapability(StoreCapabilityType capability) {
- throw new NoSuchCapabilityException(capability, getName());
- }
-
- public String getName() {
- return this.name;
- }
-
- public void close() throws VoldemortException {}
-
+ @Override
public Map>> getAll(Iterable keys,
Map transforms)
throws VoldemortException {
@@ -81,19 +68,22 @@ public Map>> getAll(Iterable keys,
return StoreUtils.getAll(this, keys, null);
}
+ @Override
public List getVersions(ByteArray key) {
return StoreUtils.getVersions(get(key, null));
}
+ @Override
public void truncate() {
try {
datastore.clear();
} catch(Exception e) {
- logger.error("Failed to truncate store '" + name + "': ", e);
- throw new VoldemortException("Failed to truncate store '" + name + "'.");
+ logger.error("Failed to truncate store '" + getName() + "': ", e);
+ throw new VoldemortException("Failed to truncate store '" + getName() + "'.");
}
}
+ @Override
public List> get(ByteArray key, byte[] transforms) throws VoldemortException {
StoreUtils.assertValidKey(key);
try {
@@ -104,6 +94,7 @@ public List> get(ByteArray key, byte[] transforms) throws Vold
}
}
+ @Override
public ClosableIterator>> entries() {
List>> returnedList = new ArrayList>>();
DataArray array = datastore.getDataArray();
@@ -143,10 +134,22 @@ public ClosableIterator>> entries() {
return new KratiClosableIterator(returnedList);
}
+ @Override
public ClosableIterator keys() {
return StoreUtils.keys(entries());
}
+ @Override
+ public ClosableIterator>> entries(int partition) {
+ throw new UnsupportedOperationException("Partition based entries scan not supported for this storage type");
+ }
+
+ @Override
+ public ClosableIterator keys(int partition) {
+ throw new UnsupportedOperationException("Partition based key scan not supported for this storage type");
+ }
+
+ @Override
public boolean delete(ByteArray key, Version maxVersion) throws VoldemortException {
StoreUtils.assertValidKey(key);
@@ -189,6 +192,7 @@ public boolean delete(ByteArray key, Version maxVersion) throws VoldemortExcepti
}
}
+ @Override
public void put(ByteArray key, Versioned value, byte[] transforms)
throws VoldemortException {
StoreUtils.assertValidKey(key);
@@ -290,26 +294,26 @@ public KratiClosableIterator(List>> list) {
iter = list.iterator();
}
+ @Override
public void close() {
// Nothing to close here
}
+ @Override
public boolean hasNext() {
return iter.hasNext();
}
+ @Override
public Pair> next() {
return iter.next();
}
+ @Override
public void remove() {
Pair> currentPair = next();
delete(currentPair.getFirst(), currentPair.getSecond().getVersion());
}
}
-
- public boolean isPartitionAware() {
- return false;
- }
}
diff --git a/contrib/restclient/lib/data-1.5.10.jar b/contrib/restclient/lib/data-1.5.10.jar
new file mode 100644
index 0000000000..d7d966bc4c
Binary files /dev/null and b/contrib/restclient/lib/data-1.5.10.jar differ
diff --git a/contrib/restclient/lib/pegasus-common-1.5.10.jar b/contrib/restclient/lib/pegasus-common-1.5.10.jar
new file mode 100644
index 0000000000..6dbed4b622
Binary files /dev/null and b/contrib/restclient/lib/pegasus-common-1.5.10.jar differ
diff --git a/contrib/restclient/lib/r2-1.5.10.jar b/contrib/restclient/lib/r2-1.5.10.jar
new file mode 100644
index 0000000000..e9ab4d3a38
Binary files /dev/null and b/contrib/restclient/lib/r2-1.5.10.jar differ
diff --git a/contrib/restclient/src/java/voldemort/restclient/R2Store.java b/contrib/restclient/src/java/voldemort/restclient/R2Store.java
new file mode 100644
index 0000000000..4b2abc26f7
--- /dev/null
+++ b/contrib/restclient/src/java/voldemort/restclient/R2Store.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2008-2013 LinkedIn, Inc
+ *
+ * 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.
+ */
+
+package voldemort.restclient;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.util.ByteArrayDataSource;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import voldemort.VoldemortException;
+import voldemort.coordinator.VectorClockWrapper;
+import voldemort.store.AbstractStore;
+import voldemort.utils.ByteArray;
+import voldemort.versioning.VectorClock;
+import voldemort.versioning.Version;
+import voldemort.versioning.Versioned;
+
+import com.linkedin.common.callback.FutureCallback;
+import com.linkedin.common.util.None;
+import com.linkedin.data.ByteString;
+import com.linkedin.r2.message.rest.RestRequest;
+import com.linkedin.r2.message.rest.RestRequestBuilder;
+import com.linkedin.r2.message.rest.RestResponse;
+import com.linkedin.r2.transport.common.Client;
+import com.linkedin.r2.transport.common.bridge.client.TransportClient;
+import com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter;
+import com.linkedin.r2.transport.http.client.HttpClientFactory;
+
+/**
+ * A class that implements the Store interface for interacting with the RESTful
+ * Coordinator. It leverages the R2 library for doing this.
+ *
+ */
+public class R2Store extends AbstractStore {
+
+ private static final String GET = "GET";
+ private static final String POST = "POST";
+ private static final String DELETE = "DELETE";
+ private static final String ETAG = "ETag";
+ public static final String X_VOLD_REQUEST_TIMEOUT_MS = "X-VOLD-Request-Timeout-ms";
+ public static final String X_VOLD_INCONSISTENCY_RESOLVER = "X-VOLD-Inconsistency-Resolver";
+ public static final String CUSTOM_RESOLVING_STRATEGY = "custom";
+ public static final String DEFAULT_RESOLVING_STRATEGY = "timestamp";
+ private static final String LAST_MODIFIED = "Last-Modified";
+ private static final String MULTIPART_CONTENT_TYPE = "multipart/binary";
+ private final Logger logger = Logger.getLogger(R2Store.class);
+
+ HttpURLConnection conn = null;
+ private HttpClientFactory _clientFactory;
+ private Client client = null;
+ private String baseURL;
+
+ public R2Store(String baseURL, String storeName) {
+ super(storeName);
+ try {
+ _clientFactory = new HttpClientFactory();
+ final TransportClient transportClient = _clientFactory.getClient(new HashMap());
+ client = new TransportClientAdapter(transportClient);
+ this.baseURL = baseURL;
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void close() throws VoldemortException {
+ final FutureCallback callback = new FutureCallback();
+ client.shutdown(callback);
+ try {
+ callback.get();
+ } catch(InterruptedException e) {
+ e.printStackTrace();
+ } catch(ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public boolean delete(ByteArray key, Version version) throws VoldemortException {
+ try {
+
+ // Create the REST request with this byte array
+ String base64Key = new String(Base64.encodeBase64(key.get()));
+ RestRequestBuilder rb = new RestRequestBuilder(new URI(this.baseURL + "/" + getName()
+ + "/" + base64Key));
+
+ // Create a HTTP POST request
+ // TODO: Create a proper request based on client config
+ rb.setMethod(DELETE);
+ rb.setHeader("Content-Type", "application/json");
+ rb.setHeader("Content-Length", "0");
+ rb.setHeader(X_VOLD_REQUEST_TIMEOUT_MS, "1000");
+
+ RestRequest request = rb.build();
+ Future f = client.restRequest(request);
+
+ // This will block
+ RestResponse response = f.get();
+ final ByteString entity = response.getEntity();
+ if(entity == null) {
+ logger.error("Empty response !");
+ }
+ } catch(VoldemortException ve) {
+ ve.printStackTrace();
+ throw ve;
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ @Override
+ public List> get(ByteArray key, byte[] transforms) throws VoldemortException {
+
+ List> resultList = new ArrayList>();
+
+ try {
+ String base64Key = new String(Base64.encodeBase64(key.get()));
+ RestRequestBuilder rb = new RestRequestBuilder(new URI(this.baseURL + "/" + getName()
+ + "/" + base64Key));
+
+ // TODO: Form a proper request based on client config
+ rb.setMethod(GET);
+ rb.setHeader("Accept", "application/json");
+ rb.setHeader(X_VOLD_REQUEST_TIMEOUT_MS, "1000");
+ rb.setHeader(X_VOLD_INCONSISTENCY_RESOLVER, "custom");
+
+ RestRequest request = rb.build();
+ Future f = client.restRequest(request);
+
+ // This will block
+ RestResponse response = f.get();
+
+ // Parse the response
+ final ByteString entity = response.getEntity();
+ String eTag = response.getHeader(ETAG);
+ String lastModified = response.getHeader(LAST_MODIFIED);
+ if(entity != null) {
+ resultList = readResults(entity, eTag, lastModified);
+ } else {
+ logger.error("Did not get any response!");
+ }
+
+ } catch(VoldemortException ve) {
+ ve.printStackTrace();
+ throw ve;
+ } catch(Exception e) {
+ if(!e.getMessage().contains("status=404")) {
+ logger.error("ERROR: " + e);
+ }
+ }
+
+ return resultList;
+ }
+
+ @Override
+ public void put(ByteArray key, Versioned value, byte[] transform)
+ throws VoldemortException {
+ try {
+
+ // Write the value in the payload
+ ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();
+ DataOutputStream outputStream = new DataOutputStream(outputBytes);
+ byte[] payload = value.getValue();
+ outputStream.write(payload);
+
+ // Create the REST request with this byte array
+ String base64Key = new String(Base64.encodeBase64(key.get()));
+ RestRequestBuilder rb = new RestRequestBuilder(new URI(this.baseURL + "/" + getName()
+ + "/" + base64Key));
+
+ // Create a HTTP POST request
+ // TODO: Create a proper request based on client config
+ rb.setMethod(POST);
+ rb.setEntity(outputBytes.toByteArray());
+ rb.setHeader("Content-Type", "application/json");
+ rb.setHeader("Content-Length", "" + payload.length);
+ rb.setHeader(X_VOLD_REQUEST_TIMEOUT_MS, "1000");
+ rb.setHeader(X_VOLD_INCONSISTENCY_RESOLVER, "custom");
+
+ RestRequest request = rb.build();
+ Future f = client.restRequest(request);
+
+ // This will block
+ RestResponse response = f.get();
+ final ByteString entity = response.getEntity();
+ if(entity == null) {
+ logger.error("Empty response !");
+ }
+ } catch(VoldemortException ve) {
+ ve.printStackTrace();
+ throw ve;
+ } catch(Exception e) {
+ logger.error("ERROR: " + e);
+ }
+ }
+
+ private List> readResults(ByteString entity, String eTag, String lastModified)
+ throws IOException {
+
+ ObjectMapper mapper = new ObjectMapper();
+ logger.debug("Received etag : " + eTag);
+ logger.debug("Received last modified date : " + lastModified);
+ VectorClockWrapper vcWrapper = mapper.readValue(eTag, VectorClockWrapper.class);
+ List> results = new ArrayList>(2);
+
+ byte[] bytes = new byte[entity.length()];
+ entity.copyBytes(bytes, 0);
+ VectorClock clock = new VectorClock(vcWrapper.getVersions(), vcWrapper.getTimestamp());
+ results.add(new Versioned(bytes, clock));
+ return results;
+ }
+
+ @Override
+ public Map>> getAll(Iterable keys,
+ Map tranforms)
+ throws VoldemortException {
+
+ Map>> resultMap = new HashMap>>();
+
+ try {
+ Iterator it = keys.iterator();
+ String keyArgs = null;
+
+ while(it.hasNext()) {
+ ByteArray key = it.next();
+ String base64Key = new String(Base64.encodeBase64(key.get()));
+ if(keyArgs == null) {
+ keyArgs = base64Key;
+ } else {
+ keyArgs += "," + base64Key;
+ }
+ }
+
+ RestRequestBuilder rb = new RestRequestBuilder(new URI(this.baseURL + "/" + getName()
+ + "/" + keyArgs));
+
+ // TODO: Form a proper request based on client config
+ rb.setMethod(GET);
+ rb.setHeader("Accept", MULTIPART_CONTENT_TYPE);
+ rb.setHeader(X_VOLD_REQUEST_TIMEOUT_MS, "1000");
+
+ RestRequest request = rb.build();
+ Future f = client.restRequest(request);
+
+ // This will block
+ RestResponse response = f.get();
+
+ // Parse the response
+ final ByteString entity = response.getEntity();
+ String contentType = response.getHeader("Content-Type");
+ // String eTag = response.getHeader(ETAG);
+ // String lastModified = response.getHeader(LAST_MODIFIED);
+ if(entity != null) {
+ if(contentType.equalsIgnoreCase(MULTIPART_CONTENT_TYPE)) {
+ resultMap = readResultsGetAll(entity);
+ } else {
+ logger.error("Did not receive a multipart response");
+ }
+
+ } else {
+ logger.error("Did not get any response!");
+ }
+
+ } catch(VoldemortException ve) {
+ ve.printStackTrace();
+ throw ve;
+ } catch(Exception e) {
+ if(!e.getMessage().contains("status=404")) {
+ logger.error("ERROR: " + e);
+ }
+ }
+
+ return resultMap;
+ }
+
+ private Map>> readResultsGetAll(ByteString entity) {
+ Map>> results = new HashMap>>();
+
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ // VectorClockWrapper vcWrapper = mapper.readValue(eTag,
+ // VectorClockWrapper.class);
+
+ // Build the multipart object
+ byte[] bytes = new byte[entity.length()];
+ entity.copyBytes(bytes, 0);
+
+ ByteArrayDataSource ds = new ByteArrayDataSource(bytes, "multipart/mixed");
+ // logger.info("received data = ");
+ // BufferedReader in = new BufferedReader(new
+ // InputStreamReader(ds.getInputStream()));
+ // String inputLine;
+ // while((inputLine = in.readLine()) != null)
+ // System.out.println(inputLine);
+ // in.close();
+
+ MimeMultipart mp = new MimeMultipart(ds);
+ for(int i = 0; i < mp.getCount(); i++) {
+ MimeBodyPart part = (MimeBodyPart) mp.getBodyPart(i);
+ String eTag = part.getHeader("ETag")[0];
+ String contentLocation = part.getHeader("Content-Location")[0];
+
+ logger.debug("Received etag : " + eTag);
+ logger.debug("Content-Location : " + contentLocation);
+
+ // Get the key
+ String base64Key = contentLocation.split("/")[2];
+
+ logger.debug("Base 64 key : " + base64Key);
+ ByteArray key = new ByteArray(Base64.decodeBase64(base64Key.getBytes()));
+
+ VectorClockWrapper vcWrapper = mapper.readValue(eTag, VectorClockWrapper.class);
+ List> keyResultList = new ArrayList>(2);
+
+ // get the value bytes
+ byte[] bodyPartBytes = ((String) part.getContent()).getBytes();
+ VectorClock clock = new VectorClock(vcWrapper.getVersions(),
+ vcWrapper.getTimestamp());
+ keyResultList.add(new Versioned(bodyPartBytes, clock));
+ results.put(key, keyResultList);
+
+ }
+
+ // VectorClock clock = new VectorClock(vcWrapper.getVersions(),
+ // vcWrapper.getTimestamp());
+ // results.add(new Versioned(bytes, clock));
+ } catch(MessagingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch(JsonParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch(JsonMappingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch(IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return results;
+
+ }
+
+ @Override
+ public List getVersions(ByteArray arg0) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/contrib/restclient/src/java/voldemort/restclient/RESTClient.java b/contrib/restclient/src/java/voldemort/restclient/RESTClient.java
new file mode 100644
index 0000000000..531a35178b
--- /dev/null
+++ b/contrib/restclient/src/java/voldemort/restclient/RESTClient.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2008-2013 LinkedIn, Inc
+ *
+ * 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.
+ */
+
+package voldemort.restclient;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import voldemort.client.RoutingTier;
+import voldemort.client.StoreClient;
+import voldemort.client.UpdateAction;
+import voldemort.cluster.Node;
+import voldemort.routing.RoutingStrategyType;
+import voldemort.serialization.DefaultSerializerFactory;
+import voldemort.serialization.Serializer;
+import voldemort.serialization.SerializerDefinition;
+import voldemort.serialization.SerializerFactory;
+import voldemort.store.Store;
+import voldemort.store.StoreDefinition;
+import voldemort.store.StoreDefinitionBuilder;
+import voldemort.store.serialized.SerializingStore;
+import voldemort.store.versioned.InconsistencyResolvingStore;
+import voldemort.utils.ByteArray;
+import voldemort.versioning.ChainedResolver;
+import voldemort.versioning.InconsistencyResolver;
+import voldemort.versioning.InconsistentDataException;
+import voldemort.versioning.ObsoleteVersionException;
+import voldemort.versioning.TimeBasedInconsistencyResolver;
+import voldemort.versioning.VectorClock;
+import voldemort.versioning.VectorClockInconsistencyResolver;
+import voldemort.versioning.Version;
+import voldemort.versioning.Versioned;
+
+import com.google.common.collect.Maps;
+
+public class RESTClient implements StoreClient {
+
+ private Store clientStore = null;
+ private SerializerFactory serializerFactory = new DefaultSerializerFactory();
+ private StoreDefinition storeDef;
+ private String storeName;
+
+ /**
+ * A REST ful equivalent of the DefaultStoreClient. This uses the R2Store to
+ * interact with the RESTful Coordinator
+ *
+ * @param bootstrapURL The bootstrap URL of the Voldemort cluster
+ * @param storeName Name of the store to interact with
+ */
+ public RESTClient(String bootstrapURL, String storeName) {
+
+ String baseURL = "http://" + bootstrapURL.split(":")[1].substring(2) + ":8080";
+ // The lowest layer : Transporting request to coordinator
+ Store store = new R2Store(baseURL, storeName);
+
+ // TODO
+ // Get the store definition so that we can learn the Serialization
+ // and
+ // compression properties
+
+ // TODO
+ // Add compression layer
+
+ // Add Serialization layer
+
+ // Set the following values although we don't need them
+ // TODO: Fix this, so that we only need to set the needed parameters
+ storeDef = new StoreDefinitionBuilder().setName(storeName)
+ .setType("bdb")
+ .setKeySerializer(new SerializerDefinition("string"))
+ .setValueSerializer(new SerializerDefinition("string"))
+ .setRoutingPolicy(RoutingTier.CLIENT)
+ .setRoutingStrategyType(RoutingStrategyType.CONSISTENT_STRATEGY)
+ .setReplicationFactor(1)
+ .setPreferredReads(1)
+ .setRequiredReads(1)
+ .setPreferredWrites(1)
+ .setRequiredWrites(1)
+ .build();
+ Serializer keySerializer = (Serializer) serializerFactory.getSerializer(storeDef.getKeySerializer());
+ Serializer valueSerializer = (Serializer) serializerFactory.getSerializer(storeDef.getValueSerializer());
+ clientStore = SerializingStore.wrap(store, keySerializer, valueSerializer, null);
+
+ // Add inconsistency Resolving layer
+ InconsistencyResolver> secondaryResolver = new TimeBasedInconsistencyResolver();
+ clientStore = new InconsistencyResolvingStore(clientStore,
+ new ChainedResolver>(new VectorClockInconsistencyResolver(),
+ secondaryResolver));
+
+ this.storeName = storeName;
+ }
+
+ @Override
+ public V getValue(K key) {
+ return getValue(key, null);
+ }
+
+ @Override
+ public V getValue(K key, V defaultValue) {
+ Versioned retVal = get(key);
+ return retVal.getValue();
+ }
+
+ @Override
+ public Versioned get(K key) {
+ return get(key, null);
+ }
+
+ @Override
+ public Versioned get(K key, Object transforms) {
+ return this.clientStore.get(key, null).get(0);
+ }
+
+ protected Versioned getItemOrThrow(K key, Versioned defaultValue, List> items) {
+ if(items.size() == 0)
+ return defaultValue;
+ else if(items.size() == 1)
+ return items.get(0);
+ else
+ throw new InconsistentDataException("Unresolved versions returned from get(" + key
+ + ") = " + items, items);
+ }
+
+ @Override
+ public Map> getAll(Iterable keys) {
+ Map>> items = null;
+ items = this.clientStore.getAll(keys, null);
+ Map> result = Maps.newHashMapWithExpectedSize(items.size());
+
+ for(Entry>> mapEntry: items.entrySet()) {
+ Versioned value = getItemOrThrow(mapEntry.getKey(), null, mapEntry.getValue());
+ result.put(mapEntry.getKey(), value);
+ }
+ return result;
+ }
+
+ @Override
+ public Map> getAll(Iterable keys, Map transforms) {
+ return null;
+ }
+
+ @Override
+ public Versioned get(K key, Versioned defaultValue) {
+ List> resultList = this.clientStore.get(key, null);
+ if(resultList.size() == 0) {
+ return null;
+ }
+ return resultList.get(0);
+ }
+
+ @Override
+ public Version put(K key, V value) {
+ clientStore.put(key, new Versioned(value), null);
+ return new VectorClock();
+ }
+
+ @Override
+ public Version put(K key, V value, Object transforms) {
+ return put(key, value);
+ }
+
+ @Override
+ public Version put(K key, Versioned versioned) throws ObsoleteVersionException {
+ clientStore.put(key, versioned, null);
+ return new VectorClock();
+ }
+
+ @Override
+ public boolean putIfNotObsolete(K key, Versioned versioned) {
+ try {
+ put(key, versioned);
+ return true;
+ } catch(ObsoleteVersionException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean applyUpdate(UpdateAction action) {
+ return applyUpdate(action, 3);
+ }
+
+ @Override
+ public boolean applyUpdate(UpdateAction action, int maxTries) {
+ boolean success = false;
+ try {
+ for(int i = 0; i < maxTries; i++) {
+ try {
+ action.update(this);
+ success = true;
+ return success;
+ } catch(ObsoleteVersionException e) {
+ // ignore for now
+ }
+ }
+ } finally {
+ if(!success)
+ action.rollback();
+ }
+
+ // if we got here we have seen too many ObsoleteVersionExceptions
+ // and have rolled back the updates
+ return false;
+ }
+
+ @Override
+ public boolean delete(K key) {
+ Versioned versioned = get(key);
+ if(versioned == null)
+ return false;
+ return this.clientStore.delete(key, versioned.getVersion());
+ }
+
+ @Override
+ public boolean delete(K key, Version version) {
+ return this.clientStore.delete(key, version);
+ }
+
+ @Override
+ public List getResponsibleNodes(K key) {
+ return null;
+ }
+
+ public void close() {
+ this.clientStore.close();
+ }
+}
diff --git a/contrib/restclient/src/java/voldemort/restclient/SampleRESTClient.java b/contrib/restclient/src/java/voldemort/restclient/SampleRESTClient.java
new file mode 100644
index 0000000000..595351117d
--- /dev/null
+++ b/contrib/restclient/src/java/voldemort/restclient/SampleRESTClient.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008-2013 LinkedIn, Inc
+ *
+ * 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.
+ */
+
+package voldemort.restclient;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SampleRESTClient {
+
+ public static void main(String[] args) {
+
+ // Create the client
+ RESTClient clientStore = new RESTClient("http://localhost:8080",
+ "test");
+
+ // Sample put
+ clientStore.put("a", "Howdy!!!!");
+ clientStore.put("b", "Partner!!!!");
+
+ // Do a sample operation:
+ System.out.println("Received response : " + clientStore.get("a"));
+ List keyList = new ArrayList();
+ keyList.add("a");
+ keyList.add("b");
+ System.out.println("Received response : " + clientStore.getAll(keyList));
+
+ clientStore.close();
+ }
+}
diff --git a/lib/commons-codec-1.3.jar b/lib/commons-codec-1.3.jar
deleted file mode 100644
index 957b6752af..0000000000
Binary files a/lib/commons-codec-1.3.jar and /dev/null differ
diff --git a/lib/commons-codec-1.4.jar b/lib/commons-codec-1.4.jar
new file mode 100644
index 0000000000..458d432da8
Binary files /dev/null and b/lib/commons-codec-1.4.jar differ
diff --git a/lib/je-4.0.92.jar b/lib/je-4.0.92.jar
deleted file mode 100644
index fa9225dd07..0000000000
Binary files a/lib/je-4.0.92.jar and /dev/null differ
diff --git a/lib/je-4.1.17.jar b/lib/je-4.1.17.jar
new file mode 100644
index 0000000000..17cc9f11f6
Binary files /dev/null and b/lib/je-4.1.17.jar differ
diff --git a/lib/netty-3.5.8.Final.jar b/lib/netty-3.5.8.Final.jar
new file mode 100644
index 0000000000..e2e42a528e
Binary files /dev/null and b/lib/netty-3.5.8.Final.jar differ
diff --git a/release_notes.txt b/release_notes.txt
index d26d880b3d..4288726d15 100644
--- a/release_notes.txt
+++ b/release_notes.txt
@@ -1,8 +1,223 @@
+Release 1.3.1 on 03/25/2013
+* HDFSFetcher
+ - Fixed the bug in calculating checksums when we entere a retry loop
+ - refactored per file checksums
+ - added junit test case to simulate intermittent IO exceptions
+* voldemort.client.protocol.admin.AdminClient
+ - Added AdminStoreClient so that AdminClient can do store operations
+ against specific store on a specific node.
+ - Added helper methods for diong put & get for specific node/store
+ - Added voldemort.client.protocol.admin.QueryKeyResult type to
+ simplify QueryKey interface
+* Improved FetchStreamRequestHandler and sub-classes
+ - Renamed all sub-classes: 'FullScan' and 'PartitionScan' prefixes
+ for pertinent stream request handler implementations.
+ - Removed unused skipRecords parameter.
+ - Added recordsPerPartition parameter to fetch limited portion of
+ each partition.
+ - All logic about how many keys to fetch (return to invoker) is
+ server side now.
+* RebalanceCLI
+ - Added many options to help improve the balance of (zoned) clusters.
+ - Analysis of the balance of a cluster is significantly more detailed.
+ - Fixed a bug that reduced the balance of a cluster each time it was
+ expanded.
+ - Many different algorithms for improving cluster balance are
+ implemented in voldemort.utils.RebalanceClusterUtils
+* ConsistencyCheck & ConsistencyFixCLI
+ - New tools for ensuring data durability. These tools are necessary
+ because slop creation can fail during put operations.
+ - ConsistencyCheck determines which keys, if any, lack
+ "consistency". I.e., are present on only a subset of the expected
+ partitions.
+ - ConsistencyFix takes a list of bad (inconsistent) keys and makes
+ sure they are present on all expected partitions.
+ - ConsistencyFix also has an interface for repairing "orphaned" keys
+ that could result from an aborted rebalance.
+* KeySamplerCLI & KeyVersionFetcherCLI
+ - KeySamplerCLI is a new tool that reads some number of keys for
+ specified partitions/stores.
+ - KeyVersionFetcherCLI is a new tool that, given a key and a store,
+ fetches the version from all nodes that host a partition that
+ ought to store a replica of the key's value.
+ - Together, KeySamplerCLI and KeyVersionFetcherCLI correctly
+ implement the intended functionality of the Entropy tool (for
+ servers that implement either FullScan and PartitionScan fetches).
+ - Entropy tool had been used in the past to verify a sample of keys
+ before and after a rebalance. Entropy tool does not work as
+ intended/expected. This is exacerbated by the partition aware
+ layouts. Instead of trying to fix the Entropy tool, these two new
+ tools were developed. Entropy is deprecated and will eventually be
+ removed from the code base.
+* Substantial refactoring of helper & util methods:
+ - voldemort.cluster.Cluster : added helper methods
+ - voldemort.utils.ClusterInstance : wraps up one Cluster &
+ List
+ - voldemort.utils.Cluster : utils for single Cluster object.
+ - voldemort.utils.NodeUtils : utils for Node object.
+ - voldemort.utils.RebalanceUtils : Many methods moved to more
+ appropriate helper classes
+ - voldemort.utils.StoreDefinitionUtils : utils for StoreDefinition
+ object.
+ - voldemort.utils.StoreInstance : wraps up one Cluster & one
+ StoreDefinition
+* Et cetera
+ - ByteUtils toHexString & from HexString now rely on standard
+ libraries
+ - voldemort.client.AdminFetchTest now tests FullScan and
+ PartitionScan fetches
+ - voldemort.store.routed.ReadRepairerTest annotated all tests with
+ @Test
+
+
+Release 1.3.0 on 03/08/2013
+
+NOTE: This is an open source release! This release can be downloaded here:
+ http://github.com/voldemort/voldemort/downloads.
+
+Changes made since 1.2.3
+* VoldemortConfig and ClientConfig now contain detailed documentation
+* BDB-JE defaults set to ones in prod@linkedin
+* Bug fixes on kerberos support for Hadoop
+
+
+Release 1.2.3 on 02/20/2013
+
+Changes made since 1.2.2
+* Added a retry loop and synchronized block while getting Hadoop FS
+* Code cleanup in HdfsFetcher to make it more readable.
+* Throwing explicit exceptions in HdfsFetcher instead of
+ returning null to be more precise in the Azkaban logs.
+
+
+Release 1.2.2 on 02/19/2013
+
+Changes made since 1.2.1
+* Synchronized the streaming API
+* Fixed some of the streaming API tests.
+
+
+Release 1.2.1 on 0/30/2013
+
+Changes made since 1.2.0
+* Added a Streaming API and related tests.
+* Refactoring of the admin client apis into functional inner classes
+
+
+Release 1.2.0 on 01/21/2013
+
+Changes made since 1.1.9
+* Added an Admin API to fetch orphaned key / entries
+* Improved some tests related to streaming API.
+* Correcting commons-codec version in ivy file (1.4)
+
+
+Release 1.1.9 on 01/15/2013
+
+Changes made since 1.1.8
+* Asynchronous socket checkout improvements
+ * Changed checkout behavior of KeyedResourcePool to only create new
+ connections when there are no resources available (rather than
+ creating new connections until the pool is full)
+ * Changed QueuedKeyedResourcePool.reset behavior to better match
+ KeyedResourcePool (i.e., to not cancel queued asynchronous
+ requests unnecessarily)
+ * Removed (unnecessary) synchronization primitives from keyed resource pool
+ * Reduce granularity of failure detector locking within ThresholdFailureDetector
+* Minor features/improvements
+ * Less verbose logging in the face of expected exceptions and errors
+ * Refactored (Queued)KeyedResourcePoolTest
+* Bug fixes
+ * Fixed possible race condition for resource creation in KeyedResourcePool
+ * More efficient (time & space) and simpler Histogram implementation
+ with improved tests
+
+
+Release 1.1.8 on 01/14/2013
+
+Changes made since release 1.1.7
+* Enhanced Server Monitoring
+ -- Server NIO layer
+ -- Streaming operations to the server
+ -- BDB storage exception counts
+* Ability to turn off BDB Checkpointing during batch modifications
+* Added ability to delete old checksum files in Build and Push reducer
+* Upgrade Hadoop jar to 1.0.4-p2
+
+
+Release 1.1.7 on 01/03/2013
+
+NOTE: This release is based off of release 1.1.4
+
+Changes made since release 1.1.4
+* Upgrading Hadoop jar to 1.0.2
+* Added support for Kerberos authentication in HdfsFetcher
+* Extra config parameters for Kerberos config and keytab file
+
+
+NOTE: Release 1.1.5 and 1.1.6 are special client side releases
+not based off of master. 1.1.5 was rolled back to to a weird bug.
+1.1.6 is a special client side release including Auto-
+bootstrapper and Versioned Avro support.
+
+
+Release 1.1.4 on 11/29/2012
+
+Changes made since release 1.1.3
+* Added BDB parameters to control LRU behavior in cache & proactive cleaner migration
+* Added a mlock fix for pinning the indexes of RO stores in memory
+
+
+Release 1.1.3 on 11/28/2012
+
+Changes made since release 1.1.2
+* Fixed a bug in the build and push job, specifically the Mapper
+ that caused collisions
+* Added retry mechanism with the HDFS fetcher for hftp
+
+
+Release 1.1.2 on 10/31/2012
+
+Changes made since release 1.1.1
+* Reverted a change to voldemort.versioning.Versioned.getVersion() so
+ that a Version is returned as our clients expect.
+
+
+Release 1.1.1 on 10/30/2012
+
+Changes made since release 1.1.0
+* Fixed connection leak in ClientRequestExecutorFactory
+* Changed client to default to DefaultStoreClient
+
+
+Release 1.1.0 on 10/19/2012
+
+Changes made since release 1.0.0
+
+IMPORTANT NOTE : This release has significant changes to the BDB storage layer.
+Users are required to read the bin/PREUPGRADE_FOR_1_1_X_README file
+thoroughly before attempting to upgrade to 1.1.0. The necessary data
+conversion will be done through bin/voldemort-convert-bdb.sh
+
+* Upgrading to JE 4.1.17
+* New data format that handles conflicting updates in Voldemort more
+ efficiently
+* Move data off heap and only use it for Index
+* When scanning, evict whatever you bring in right away.
+* Partition based scan api to dramatically speed up rebalancing & restore
+ using Partition aware scans (you exactly scan whatever you want to fetch)
+* Flexible knobs to control scheduling of DataCleanupJob
+
+
Release 1.0.0 on 10/17/2012
-NOTE: This is not a major release. This is a minor release. The large
-version number jump from 0.96 is to standardize on a version number of
-the sort MAJOR.MINOR.PATCH.
+NOTE: The large version number jump from 0.96 to 1.0.0 is to
+standardize on a version number of the sort MAJOR.MINOR.PATCH. This
+change is part of our effort to treat internal and open source
+releases in a much more similar manner. Along these lines, release
+notes for internal releases (like this one) are committed on the
+master branch. We hope this improves transparency as we work towards
+the next open source release.
Changes made since release 0.96
diff --git a/src/java/log4j.properties b/src/java/log4j.properties
index 9a16ef00d2..3cb4b7c790 100755
--- a/src/java/log4j.properties
+++ b/src/java/log4j.properties
@@ -6,15 +6,18 @@ log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# log4j.appender.stdout.layout.ConversionPattern=[%d %c] %p %m %n
-log4j.appender.stdout.layout.ConversionPattern=[%d{ABSOLUTE} %c] %p %m [%t]%n
+log4j.appender.stdout.layout.ConversionPattern=[%d{ABSOLUTE} %c] %p %m [%t]%n
# Turn on all our debugging info
log4j.logger=INFO
log4j.logger.httpclient.wire=INFO
log4j.logger.org.mortbay.log=WARN
+log4j.logger.voldemort.server=INFO
log4j.logger.voldemort.store.routed=INFO
log4j.logger.voldemort.server.niosocket=INFO
log4j.logger.voldemort.utils=INFO
log4j.logger.voldemort.client.rebalance=INFO
log4j.logger.voldemort.server=INFO
+log4j.logger.voldemort.routing=INFO
+log4j.logger.voldemort.store.stats=INFO
log4j.logger.krati=WARN
diff --git a/src/java/voldemort/VoldemortAdminTool.java b/src/java/voldemort/VoldemortAdminTool.java
index 04d8ab7828..c462150b65 100644
--- a/src/java/voldemort/VoldemortAdminTool.java
+++ b/src/java/voldemort/VoldemortAdminTool.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2010 LinkedIn, Inc
+ * Copyright 2008-2013 LinkedIn, Inc
*
* 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
@@ -54,8 +54,10 @@
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
+import voldemort.client.ClientConfig;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
+import voldemort.client.protocol.admin.QueryKeyResult;
import voldemort.cluster.Cluster;
import voldemort.cluster.Node;
import voldemort.serialization.DefaultSerializerFactory;
@@ -252,6 +254,15 @@ public static void main(String[] args) throws Exception {
.describedAs("query-keys")
.withValuesSeparatedBy(',')
.ofType(String.class);
+ parser.accepts("mirror-from-url", "Cluster url to mirror data from")
+ .withRequiredArg()
+ .describedAs("mirror-cluster-bootstrap-url")
+ .ofType(String.class);
+ parser.accepts("mirror-node", "Node id in the mirror cluster to mirror from")
+ .withRequiredArg()
+ .describedAs("id-of-mirror-node")
+ .ofType(Integer.class);
+ parser.accepts("fetch-orphaned", "Fetch any orphaned keys/entries in the node");
OptionSet options = parser.parse(args);
@@ -263,6 +274,8 @@ public static void main(String[] args) throws Exception {
Set missing = CmdUtils.missing(options, "url", "node");
if(missing.size() > 0) {
// Not the most elegant way to do this
+ // basically check if only "node" is missing for these set of
+ // options; all these can live without explicit node ids
if(!(missing.equals(ImmutableSet.of("node"))
&& (options.has("add-stores") || options.has("delete-store")
|| options.has("ro-metadata") || options.has("set-metadata")
@@ -282,7 +295,10 @@ public static void main(String[] args) throws Exception {
Integer zoneId = CmdUtils.valueOf(options, "zone", -1);
int zone = zoneId == -1 ? 0 : zoneId;
- AdminClient adminClient = new AdminClient(url, new AdminClientConfig(), zone);
+ AdminClient adminClient = new AdminClient(url,
+ new AdminClientConfig(),
+ new ClientConfig(),
+ zone);
if(options.has("verify-metadata-version")) {
checkMetadataVersion(adminClient);
@@ -290,54 +306,51 @@ public static void main(String[] args) throws Exception {
}
String ops = "";
- if(options.has("delete-partitions")) {
- ops += "d";
- }
- if(options.has("fetch-keys")) {
- ops += "k";
- }
- if(options.has("fetch-entries")) {
- ops += "v";
- }
- if(options.has("restore")) {
- ops += "r";
- }
+ // Honestly, the most insane code I have seen. Atleast sorting this for
+ // now so its easy to find a spare character
if(options.has("add-stores")) {
ops += "a";
}
- if(options.has("update-entries")) {
- ops += "u";
+ if(options.has("async")) {
+ ops += "b";
}
- if(options.has("delete-store")) {
- ops += "s";
+ if(options.has("check-metadata")) {
+ ops += "c";
}
- if(options.has("get-metadata")) {
- ops += "g";
+ if(options.has("delete-partitions")) {
+ ops += "d";
}
if(options.has("ro-metadata")) {
ops += "e";
}
- if(options.has("truncate")) {
- ops += "t";
- }
- if(options.has("set-metadata")) {
- ops += "m";
+ if(options.has("reserve-memory")) {
+ if(!options.has("stores")) {
+ Utils.croak("Specify the list of stores to reserve memory");
+ }
+ ops += "f";
}
- if(options.has("check-metadata")) {
- ops += "c";
+ if(options.has("get-metadata")) {
+ ops += "g";
}
- if(options.has("key-distribution")) {
- ops += "y";
+ if(options.has("mirror-from-url")) {
+ if(!options.has("mirror-node")) {
+ Utils.croak("Specify the mirror node to fetch from");
+ }
+ ops += "h";
}
if(options.has("clear-rebalancing-metadata")) {
ops += "i";
}
- if(options.has("async")) {
- ops += "b";
+ if(options.has("fetch-keys")) {
+ ops += "k";
}
+
if(options.has("repair-job")) {
ops += "l";
}
+ if(options.has("set-metadata")) {
+ ops += "m";
+ }
if(options.has("native-backup")) {
if(!options.has("backup-dir")) {
Utils.croak("A backup directory must be specified with backup-dir option");
@@ -350,24 +363,38 @@ public static void main(String[] args) throws Exception {
}
ops += "o";
}
- if(options.has("synchronize-metadata-version")) {
- ops += "z";
- }
- if(options.has("reserve-memory")) {
- if(!options.has("stores")) {
- Utils.croak("Specify the list of stores to reserve memory");
- }
- ops += "f";
- }
if(options.has("query-keys")) {
ops += "q";
}
+ if(options.has("restore")) {
+ ops += "r";
+ }
+ if(options.has("delete-store")) {
+ ops += "s";
+ }
+ if(options.has("truncate")) {
+ ops += "t";
+ }
+ if(options.has("update-entries")) {
+ ops += "u";
+ }
+ if(options.has("fetch-entries")) {
+ ops += "v";
+ }
+
+ if(options.has("key-distribution")) {
+ ops += "y";
+ }
+
+ if(options.has("synchronize-metadata-version")) {
+ ops += "z";
+ }
if(ops.length() < 1) {
Utils.croak("At least one of (delete-partitions, restore, add-node, fetch-entries, "
+ "fetch-keys, add-stores, delete-store, update-entries, get-metadata, ro-metadata, "
+ "set-metadata, check-metadata, key-distribution, clear-rebalancing-metadata, async, "
- + "repair-job, native-backup, rollback, reserve-memory, verify-metadata-version) must be specified");
+ + "repair-job, native-backup, rollback, reserve-memory, mirror-url, verify-metadata-version) must be specified");
}
List storeNames = null;
@@ -395,7 +422,7 @@ public static void main(String[] args) throws Exception {
System.exit(1);
}
System.out.println("Starting restore");
- adminClient.restoreDataFromReplications(nodeId, parallelism, zoneId);
+ adminClient.restoreOps.restoreDataFromReplications(nodeId, parallelism, zoneId);
System.out.println("Finished restore");
}
if(ops.contains("k")) {
@@ -409,7 +436,8 @@ public static void main(String[] args) throws Exception {
partitionIdList,
outputDir,
storeNames,
- useAscii);
+ useAscii,
+ options.has("fetch-orphaned"));
}
if(ops.contains("v")) {
boolean useAscii = options.has("ascii");
@@ -422,8 +450,10 @@ public static void main(String[] args) throws Exception {
partitionIdList,
outputDir,
storeNames,
- useAscii);
+ useAscii,
+ options.has("fetch-orphaned"));
}
+
if(ops.contains("a")) {
String storesXml = (String) options.valueOf("add-stores");
executeAddStores(adminClient, storesXml, nodeId);
@@ -516,7 +546,7 @@ public static void main(String[] args) throws Exception {
+ storeNames);
try {
for(String name: storeNames) {
- adminClient.updateMetadataversion(name);
+ adminClient.metadataMgmtOps.updateMetadataversion(name);
}
} catch(Exception e) {
System.err.println("Error while updating metadata version for the specified store.");
@@ -557,12 +587,12 @@ public static void main(String[] args) throws Exception {
String backupDir = (String) options.valueOf("backup-dir");
String storeName = (String) options.valueOf("native-backup");
int timeout = CmdUtils.valueOf(options, "backup-timeout", 30);
- adminClient.nativeBackup(nodeId,
- storeName,
- backupDir,
- timeout,
- options.has("backup-verify"),
- options.has("backup-incremental"));
+ adminClient.storeMntOps.nativeBackup(nodeId,
+ storeName,
+ backupDir,
+ timeout,
+ options.has("backup-verify"),
+ options.has("backup-incremental"));
}
if(ops.contains("o")) {
String storeName = (String) options.valueOf("rollback");
@@ -574,7 +604,7 @@ public static void main(String[] args) throws Exception {
}
if(ops.contains("f")) {
long reserveMB = (Long) options.valueOf("reserve-memory");
- adminClient.reserveMemory(nodeId, storeNames, reserveMB);
+ adminClient.storeMntOps.reserveMemory(nodeId, storeNames, reserveMB);
}
if(ops.contains("q")) {
List keyList = (List) options.valuesOf("query-keys");
@@ -583,6 +613,21 @@ public static void main(String[] args) throws Exception {
}
executeQueryKeys(nodeId, adminClient, storeNames, keyList);
}
+ if(ops.contains("h")) {
+ if(nodeId == -1) {
+ System.err.println("Cannot run mirroring without node id");
+ System.exit(1);
+ }
+ Integer mirrorNodeId = CmdUtils.valueOf(options, "mirror-node", -1);
+ if(mirrorNodeId == -1) {
+ System.err.println("Cannot run mirroring without mirror node id");
+ System.exit(1);
+ }
+ adminClient.restoreOps.mirrorData(nodeId,
+ mirrorNodeId,
+ (String) options.valueOf("mirror-from-url"),
+ storeNames);
+ }
} catch(Exception e) {
e.printStackTrace();
Utils.croak(e.getMessage());
@@ -595,11 +640,11 @@ private static String getMetadataVersionsForNode(AdminClient adminClient, int no
partitionIdList.addAll(node.getPartitionIds());
}
- Iterator>> entriesIterator = adminClient.fetchEntries(nodeId,
- SystemStoreConstants.SystemStoreName.voldsys$_metadata_version_persistence.name(),
- partitionIdList,
- null,
- true);
+ Iterator>> entriesIterator = adminClient.bulkFetchOps.fetchEntries(nodeId,
+ SystemStoreConstants.SystemStoreName.voldsys$_metadata_version_persistence.name(),
+ partitionIdList,
+ null,
+ true);
Serializer serializer = new StringSerializer("UTF8");
String keyObject = null;
String valueObject = null;
@@ -665,7 +710,7 @@ private static void synchronizeMetadataVersion(AdminClient adminClient, int base
System.err.println("The specified node does not have any versions metadata ! Exiting ...");
System.exit(-1);
}
- adminClient.setMetadataversion(props);
+ adminClient.metadataMgmtOps.setMetadataversion(props);
System.out.println("Metadata versions synchronized successfully.");
} catch(IOException e) {
System.err.println("Error while retrieving Metadata versions from node : " + baseNodeId
@@ -682,20 +727,20 @@ private static void executeRollback(Integer nodeId,
AdminClient adminClient) {
if(nodeId < 0) {
for(Node node: adminClient.getAdminClientCluster().getNodes()) {
- adminClient.rollbackStore(node.getId(), storeName, pushVersion);
+ adminClient.readonlyOps.rollbackStore(node.getId(), storeName, pushVersion);
}
} else {
- adminClient.rollbackStore(nodeId, storeName, pushVersion);
+ adminClient.readonlyOps.rollbackStore(nodeId, storeName, pushVersion);
}
}
private static void executeRepairJob(Integer nodeId, AdminClient adminClient) {
if(nodeId < 0) {
for(Node node: adminClient.getAdminClientCluster().getNodes()) {
- adminClient.repairJob(node.getId());
+ adminClient.storeMntOps.repairJob(node.getId());
}
} else {
- adminClient.repairJob(nodeId);
+ adminClient.storeMntOps.repairJob(nodeId);
}
}
@@ -775,6 +820,14 @@ public static void printHelp(PrintStream stream, OptionParser parser) throws IOE
stream.println("\t\t./bin/voldemort-admin-tool.sh --update-entries [folder path from output of --fetch-entries --outdir] --url [url] --node [node-id] --stores [comma-separated list of store names]");
stream.println("\t10) Query stores for a set of keys on a specific node.");
stream.println("\t\t./bin/voldemort-admin-tool.sh --query-keys [comma-separated list of keys] --url [url] --node [node-id] --stores [comma-separated list of store names]");
+ stream.println("\t11) Mirror data from another voldemort server (possibly in another cluster) for specified stores");
+ stream.println("\t\t./bin/voldemort-admin-tool.sh --mirror-from-url [bootstrap url to mirror from] --mirror-node [node to mirror from] --url [url] --node [node-id] --stores [comma-separated-list-of-store-names]");
+ stream.println("\t12) Mirror data from another voldemort server (possibly in another cluster) for all stores in current cluster");
+ stream.println("\t\t./bin/voldemort-admin-tool.sh --mirror-from-url [bootstrap url to mirror from] --mirror-node [node to mirror from] --url [url] --node [node-id]");
+ stream.println("\t13) Fetch all orphaned keys on a particular node");
+ stream.println("\t\t./bin/voldemort-admin-tool.sh --fetch-keys --url [url] --node [node-id] --fetch-orphaned");
+ stream.println("\t14) Fetch all orphaned entries on a particular node");
+ stream.println("\t\t./bin/voldemort-admin-tool.sh --fetch-entries --url [url] --node [node-id] --fetch-orphaned");
stream.println();
stream.println("READ-ONLY OPERATIONS");
stream.println("\t1) Retrieve metadata information of read-only data for a particular node and all stores");
@@ -826,11 +879,14 @@ private static void executeAsync(Integer nodeId,
// Print the job information
for(int currentNodeId: nodeIds) {
System.out.println("Retrieving async jobs from node " + currentNodeId);
- List asyncIds = adminClient.getAsyncRequestList(currentNodeId);
+ List asyncIds = adminClient.rpcOps.getAsyncRequestList(currentNodeId);
System.out.println("Async Job Ids on node " + currentNodeId + " : " + asyncIds);
for(int asyncId: asyncIds) {
- System.out.println("Async Job Id " + asyncId + " ] "
- + adminClient.getAsyncRequestStatus(currentNodeId, asyncId));
+ System.out.println("Async Job Id "
+ + asyncId
+ + " ] "
+ + adminClient.rpcOps.getAsyncRequestStatus(currentNodeId,
+ asyncId));
System.out.println();
}
}
@@ -845,7 +901,7 @@ private static void executeAsync(Integer nodeId,
for(int asyncId: asyncIdsToStop) {
System.out.println("Stopping async id " + asyncId);
- adminClient.stopAsyncRequest(nodeId, asyncId);
+ adminClient.rpcOps.stopAsyncRequest(nodeId, asyncId);
System.out.println("Stopped async id " + asyncId);
}
} else {
@@ -874,12 +930,12 @@ private static void executeClearRebalancing(int nodeId, AdminClient adminClient)
private static void executeKeyDistribution(AdminClient adminClient) {
List keys = KeyDistributionGenerator.generateKeys(KeyDistributionGenerator.DEFAULT_NUM_KEYS);
System.out.println(KeyDistributionGenerator.printStoreWiseDistribution(adminClient.getAdminClientCluster(),
- adminClient.getRemoteStoreDefList(0)
- .getValue(),
+ adminClient.metadataMgmtOps.getRemoteStoreDefList(0)
+ .getValue(),
keys));
System.out.println(KeyDistributionGenerator.printOverallDistribution(adminClient.getAdminClientCluster(),
- adminClient.getRemoteStoreDefList(0)
- .getValue(),
+ adminClient.metadataMgmtOps.getRemoteStoreDefList(0)
+ .getValue(),
keys));
}
@@ -888,7 +944,8 @@ private static void executeCheckMetadata(AdminClient adminClient, String metadat
Set