check_format_compatible.sh 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. #!/usr/bin/env bash
  2. # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  3. #
  4. # A shell script to build and run different versions of ldb to check for
  5. # expected forward and backward compatibility with "current" version. The
  6. # working copy must have no uncommitted changes.
  7. #
  8. # Usage: <SCRIPT> [ref_for_current]
  9. # `ref_for_current` can be a revision, tag, commit or branch name. Default is HEAD.
  10. #
  11. # Return value 0 means all regression tests pass. 1 if not pass.
  12. #
  13. # Environment options:
  14. # SANITY_CHECK=1 - Do a syntax check and git checkout test as a sanity check
  15. # that the script hasn't been broken by e.g. adding a new release wrongly.
  16. # SHORT_TEST=1 - Test only the oldest branch for each kind of test. This is
  17. # a good choice for PR validation as it is relatively fast and will find
  18. # most issues.
  19. # LONG_TEST=1 - Test all branches known to build for this test, rather than
  20. # the default of randomly sampling the branches that aren't the oldest in
  21. # each set.
  22. # USE_SSH=1 - Connect to GitHub with ssh instead of https
  23. if ! git diff-index --quiet HEAD; then
  24. echo "You have uncommitted changes. Aborting."
  25. exit 1
  26. fi
  27. current_checkout_name=${1:-HEAD}
  28. # This allows the script to work even if with transient refs like "HEAD"
  29. current_checkout_hash="$(git rev-parse --quiet --verify $current_checkout_name)"
  30. if [ "$current_checkout_hash" == "" ]; then
  31. echo "Not a recognized ref: $current_checkout_name"
  32. exit 1
  33. fi
  34. # To restore to prior branch at the end
  35. orig_branch="$(git rev-parse --abbrev-ref HEAD)"
  36. tmp_branch=_tmp_format_compatible
  37. tmp_origin=_tmp_origin
  38. # Don't depend on what current "origin" might be
  39. set -e
  40. git remote remove $tmp_origin 2>/dev/null || true
  41. if [ "$USE_SSH" ]; then
  42. git remote add $tmp_origin "git@github.com:facebook/rocksdb.git"
  43. else
  44. git remote add $tmp_origin "https://github.com/facebook/rocksdb.git"
  45. fi
  46. git fetch $tmp_origin
  47. # Used in building some ancient RocksDB versions where by default it tries to
  48. # use a precompiled libsnappy.a checked in to the repo.
  49. export SNAPPY_LDFLAGS=-lsnappy
  50. cleanup() {
  51. echo "== Cleaning up"
  52. git reset --hard || true
  53. git checkout "$orig_branch" || true
  54. git branch -D $tmp_branch || true
  55. git remote remove $tmp_origin || true
  56. }
  57. trap cleanup EXIT # Always clean up, even on failure or Ctrl+C
  58. scriptpath=`dirname ${BASH_SOURCE[0]}`
  59. test_dir=${TEST_TMPDIR:-"/tmp"}"/rocksdb_format_compatible_$USER"
  60. rm -rf ${test_dir:?}
  61. # Prevent 'make clean' etc. from wiping out test_dir
  62. export TEST_TMPDIR=$test_dir"/misc"
  63. # For saving current version of scripts as we checkout different versions to test
  64. script_copy_dir=$test_dir"/script_copy"
  65. mkdir -p $script_copy_dir
  66. cp -f $scriptpath/*.sh $script_copy_dir
  67. # For shared raw input data
  68. input_data_path=$test_dir"/test_data_input"
  69. mkdir -p $input_data_path
  70. # For external sst ingestion test
  71. ext_test_dir=$test_dir"/ext"
  72. mkdir -p $ext_test_dir
  73. # For DB dump test
  74. db_test_dir=$test_dir"/db"
  75. mkdir -p $db_test_dir
  76. # For backup/restore test (uses DB test)
  77. bak_test_dir=$test_dir"/bak"
  78. mkdir -p $bak_test_dir
  79. python_bin=$(which python3 || which python || echo python3)
  80. if [ "$J" == "" ]; then
  81. # make parallelism
  82. J=32
  83. fi
  84. # Generate random files. We want enough files to cover a variety of compression
  85. # settings and low enough entropy in the files to make compression highly
  86. # likely, including for index blocks.
  87. for i in {1..8}
  88. do
  89. input_data[$i]=$input_data_path/data$i
  90. echo == Generating random input file ${input_data[$i]}
  91. $python_bin - <<EOF
  92. import random
  93. random.seed($i)
  94. symbols=['a', 'b', 'c', 'd', 'e', 'f', 'g']
  95. with open('${input_data[$i]}', 'w') as f:
  96. for i in range(1,1024):
  97. k = ""
  98. for j in range(1, random.randint(1,80)):
  99. k=k + symbols[random.randint(0, len(symbols) - 1)]
  100. vb = ""
  101. for j in range(1, random.randint(0,128)):
  102. vb = vb + symbols[random.randint(0, len(symbols) - 1)]
  103. v = ""
  104. for j in range(1, random.randint(1, 5)):
  105. v = v + vb
  106. print(k + " ==> " + v, file=f)
  107. EOF
  108. done
  109. # Generate file(s) with sorted keys.
  110. sorted_input_data=$input_data_path/sorted_data
  111. echo == Generating file with sorted keys ${sorted_input_data}
  112. $python_bin - <<EOF
  113. with open('${sorted_input_data}', 'w') as f:
  114. for i in range(0,10):
  115. k = str(i)
  116. v = "value" + k
  117. print(k + " ==> " + v, file=f)
  118. EOF
  119. # db_backward_only_refs defined below the rest
  120. # To check for DB forward compatibility with loading options (old version
  121. # reading data from new), as well as backward compatibility
  122. declare -a db_forward_with_options_refs=("8.6.fb" "8.7.fb" "8.8.fb" "8.9.fb" "8.10.fb" "8.11.fb" "9.0.fb" "9.1.fb" "9.2.fb" "9.3.fb" "9.4.fb" "9.5.fb" "9.6.fb" "9.7.fb" "9.8.fb" "9.9.fb" "9.10.fb" "9.11.fb" "10.0.fb" "10.1.fb" "10.2.fb" "10.3.fb" "10.4.fb" "10.5.fb" "10.6.fb" "10.7.fb" "10.8.fb")
  123. # To check for DB forward compatibility without loading options (in addition
  124. # to the "with loading options" set), as well as backward compatibility
  125. declare -a db_forward_no_options_refs=() # N/A at the moment
  126. # To check for SST ingestion backward compatibility (new version reading
  127. # data from old) (ldb ingest_extern_sst added in 5.16.x, back-ported to
  128. # 5.14.x, 5.15.x)
  129. declare -a ext_backward_only_refs=("5.14.fb" "5.15.fb" "5.16.fb" "5.17.fb" "5.18.fb" "6.0.fb" "6.1.fb" "6.2.fb" "6.3.fb" "6.4.fb" "6.5.fb" "6.6.fb" "6.7.fb" "6.8.fb" "6.9.fb" "6.10.fb" "6.11.fb" "6.12.fb" "6.13.fb" "6.14.fb" "6.15.fb" "6.16.fb" "6.17.fb" "6.18.fb" "6.19.fb" "6.20.fb" "6.21.fb" "6.22.fb" "6.23.fb" "6.24.fb" "6.25.fb" "6.26.fb" "6.27.fb" "6.28.fb" "6.29.fb" "7.0.fb" "7.1.fb" "7.2.fb" "7.3.fb" "7.4.fb" "7.5.fb" "7.6.fb" "7.7.fb" "7.8.fb" "7.9.fb" "7.10.fb" "8.0.fb" "8.1.fb" "8.2.fb" "8.3.fb" "8.4.fb" "8.5.fb")
  130. # To check for SST ingestion forward compatibility (old version reading
  131. # data from new) as well as backward compatibility
  132. declare -a ext_forward_refs=("${db_forward_no_options_refs[@]}" "${db_forward_with_options_refs[@]}")
  133. # To check for backup backward compatibility (new version reading data
  134. # from old) (ldb backup/restore added in 4.11.x)
  135. declare -a bak_backward_only_refs=("4.11.fb" "4.12.fb" "4.13.fb" "5.0.fb" "5.1.fb" "5.2.fb" "5.3.fb" "5.4.fb" "5.5.fb" "5.6.fb" "5.7.fb" "5.8.fb" "5.9.fb" "5.10.fb" "5.11.fb" "5.12.fb" "5.13.fb" "${ext_backward_only_refs[@]}")
  136. # To check for backup forward compatibility (old version reading data
  137. # from new) as well as backward compatibility
  138. declare -a bak_forward_refs=("${db_forward_no_options_refs[@]}" "${db_forward_with_options_refs[@]}")
  139. # Branches (git refs) to check for DB backward compatibility (new version
  140. # reading data from old) (in addition to the "forward compatible" list)
  141. # NOTE: 2.7.fb.branch shows assertion violation in some configurations
  142. declare -a db_backward_only_refs=("2.2.fb.branch" "2.3.fb.branch" "2.4.fb.branch" "2.5.fb.branch" "2.6.fb.branch" "2.8.1.fb" "3.0.fb.branch" "3.1.fb" "3.2.fb" "3.3.fb" "3.4.fb" "3.5.fb" "3.6.fb" "3.7.fb" "3.8.fb" "3.9.fb" "4.2.fb" "4.3.fb" "4.4.fb" "4.5.fb" "4.6.fb" "4.7.fb" "4.8.fb" "4.9.fb" "4.10.fb" "${bak_backward_only_refs[@]}")
  143. if [ "$SHORT_TEST" ]; then
  144. # Use only the first (if exists) of each list
  145. db_backward_only_refs=(${db_backward_only_refs[0]})
  146. db_forward_no_options_refs=(${db_forward_no_options_refs[0]})
  147. db_forward_with_options_refs=(${db_forward_with_options_refs[0]})
  148. ext_backward_only_refs=(${ext_backward_only_refs[0]})
  149. ext_forward_refs=(${ext_forward_refs[0]})
  150. bak_backward_only_refs=(${bak_backward_only_refs[0]})
  151. bak_forward_refs=(${bak_forward_refs[0]})
  152. fi
  153. # De-duplicate & accumulate
  154. declare -a checkout_refs=()
  155. # Always include first release on each list
  156. for checkout_ref in "${db_backward_only_refs[0]}" "${db_forward_no_options_refs[0]}" "${db_forward_with_options_refs[0]}" "${ext_backward_only_refs[0]}" "${ext_forward_refs[0]}" "${bak_backward_only_refs[0]}" "${bak_forward_refs[0]}"
  157. do
  158. if [ ! -e $db_test_dir/$checkout_ref ]; then
  159. mkdir -p $db_test_dir/$checkout_ref
  160. checkout_refs+=($checkout_ref)
  161. fi
  162. done
  163. # Maybe include rest if not short test
  164. if [ "$SHORT_TEST" == "" ]; then
  165. for checkout_ref in "${db_backward_only_refs[@]}" "${db_forward_no_options_refs[@]}" "${db_forward_with_options_refs[@]}" "${ext_backward_only_refs[@]}" "${ext_forward_refs[@]}" "${bak_backward_only_refs[@]}" "${bak_forward_refs[@]}"
  166. do
  167. if [ ! -e $db_test_dir/$checkout_ref ]; then
  168. mkdir -p $db_test_dir/$checkout_ref
  169. # Randomly sample remaining releases, unless long test
  170. if [ "$LONG_TEST" ] || [ "$(($RANDOM % 3))" == "0" ]; then
  171. checkout_refs+=($checkout_ref)
  172. fi
  173. fi
  174. done
  175. fi
  176. invoke_make()
  177. {
  178. [ "$SANITY_CHECK" ] || make "$@"
  179. }
  180. generate_db()
  181. {
  182. set +e
  183. [ "$SANITY_CHECK" ] || bash "$script_copy_dir"/generate_random_db.sh "$1" "$2"
  184. if [ $? -ne 0 ]; then
  185. echo ==== Error loading data from $2 to $1 ====
  186. exit 1
  187. fi
  188. set -e
  189. }
  190. compare_db()
  191. {
  192. set +e
  193. [ "$SANITY_CHECK" ] || bash "$script_copy_dir"/verify_random_db.sh "$1" "$2" "$3" "$4" "$5"
  194. if [ $? -ne 0 ]; then
  195. echo ==== Read different content from $1 and $2 or error happened. ====
  196. exit 1
  197. fi
  198. set -e
  199. }
  200. write_external_sst()
  201. {
  202. set +e
  203. [ "$SANITY_CHECK" ] || bash "$script_copy_dir"/write_external_sst.sh "$1" "$2" "$3"
  204. if [ $? -ne 0 ]; then
  205. echo ==== Error writing external SST file using data from $1 to $3 ====
  206. exit 1
  207. fi
  208. set -e
  209. }
  210. ingest_external_sst()
  211. {
  212. set +e
  213. [ "$SANITY_CHECK" ] || bash "$script_copy_dir"/ingest_external_sst.sh "$1" "$2"
  214. if [ $? -ne 0 ]; then
  215. echo ==== Error ingesting external SST in $2 to DB at $1 ====
  216. exit 1
  217. fi
  218. set -e
  219. }
  220. backup_db()
  221. {
  222. set +e
  223. [ "$SANITY_CHECK" ] || bash "$script_copy_dir"/backup_db.sh "$1" "$2"
  224. if [ $? -ne 0 ]; then
  225. echo ==== Error backing up DB $1 to $2 ====
  226. exit 1
  227. fi
  228. set -e
  229. }
  230. restore_db()
  231. {
  232. set +e
  233. [ "$SANITY_CHECK" ] || bash "$script_copy_dir"/restore_db.sh "$1" "$2"
  234. if [ $? -ne 0 ]; then
  235. echo ==== Error restoring from $1 to $2 ====
  236. exit 1
  237. fi
  238. set -e
  239. }
  240. member_of_array()
  241. {
  242. local e match="$1"
  243. shift
  244. for e; do [[ "$e" == "$match" ]] && return 0; done
  245. return 1
  246. }
  247. force_no_fbcode()
  248. {
  249. # Not all branches recognize ROCKSDB_NO_FBCODE and we should not need
  250. # to patch old branches for changes to available FB compilers.
  251. sed -i -e 's|-d /mnt/gvfs/third-party|"$ROCKSDB_FORCE_FBCODE"|' build_tools/build_detect_platform
  252. # Fix a build issue affecting at least 4.2.fb
  253. if [ -e include/rocksdb/delete_scheduler.h ]; then
  254. sed -i -e 's|pragma once|pragma once\n#include <memory>|' include/rocksdb/delete_scheduler.h
  255. fi
  256. }
  257. # General structure from here:
  258. # * Check out, build, and do stuff with the "current" branch.
  259. # * For each older branch under consideration,
  260. # * Check out, build, and do stuff with it, potentially using data
  261. # generated from "current" branch.
  262. # * (Again) check out, build, and do (other) stuff with the "current"
  263. # branch, potentially using data from older branches.
  264. #
  265. # This way, we only do at most n+1 checkout+build steps, without the
  266. # need to stash away executables.
  267. # Decorate name
  268. current_checkout_name="$current_checkout_name ($current_checkout_hash)"
  269. echo "== Building $current_checkout_name debug"
  270. git checkout -B $tmp_branch $current_checkout_hash
  271. force_no_fbcode
  272. invoke_make clean
  273. DISABLE_WARNING_AS_ERROR=1 invoke_make ldb -j$J
  274. echo "== Using $current_checkout_name, generate DB with extern SST and ingest"
  275. current_ext_test_dir=$ext_test_dir"/current"
  276. write_external_sst $input_data_path ${current_ext_test_dir}_pointless $current_ext_test_dir
  277. ingest_external_sst ${current_ext_test_dir}_ingest $current_ext_test_dir
  278. echo "== Generating DB from $current_checkout_name ..."
  279. current_db_test_dir=$db_test_dir"/current"
  280. generate_db $input_data_path $current_db_test_dir
  281. echo "== Creating backup of DB from $current_checkout_name ..."
  282. current_bak_test_dir=$bak_test_dir"/current"
  283. backup_db $current_db_test_dir $current_bak_test_dir
  284. for checkout_ref in "${checkout_refs[@]}"
  285. do
  286. echo "== Building $checkout_ref debug"
  287. git reset --hard $tmp_origin/$checkout_ref
  288. force_no_fbcode
  289. invoke_make clean
  290. DISABLE_WARNING_AS_ERROR=1 invoke_make ldb -j$J
  291. # We currently assume DB backward compatibility for every branch listed
  292. echo "== Use $checkout_ref to generate a DB ..."
  293. generate_db $input_data_path $db_test_dir/$checkout_ref
  294. if member_of_array "$checkout_ref" "${ext_backward_only_refs[@]}" ||
  295. member_of_array "$checkout_ref" "${ext_forward_refs[@]}"
  296. then
  297. echo "== Use $checkout_ref to generate DB with extern SST file"
  298. write_external_sst $input_data_path $ext_test_dir/${checkout_ref}_pointless $ext_test_dir/$checkout_ref
  299. fi
  300. if member_of_array "$checkout_ref" "${ext_forward_refs[@]}"
  301. then
  302. echo "== Use $checkout_ref to ingest extern SST file and compare vs. $current_checkout_name"
  303. ingest_external_sst $ext_test_dir/${checkout_ref}_ingest $ext_test_dir/$checkout_ref
  304. compare_db $ext_test_dir/${checkout_ref}_ingest ${current_ext_test_dir}_ingest db_dump.txt 1 1
  305. rm -rf ${ext_test_dir:?}/${checkout_ref}_ingest
  306. echo "== Use $checkout_ref to ingest extern SST file from $current_checkout_name"
  307. ingest_external_sst $ext_test_dir/${checkout_ref}_ingest $current_ext_test_dir
  308. compare_db $ext_test_dir/${checkout_ref}_ingest ${current_ext_test_dir}_ingest db_dump.txt 1 1
  309. fi
  310. if member_of_array "$checkout_ref" "${db_forward_no_options_refs[@]}" ||
  311. member_of_array "$checkout_ref" "${db_forward_with_options_refs[@]}"
  312. then
  313. echo "== Use $checkout_ref to open DB generated using $current_checkout_name..."
  314. compare_db $db_test_dir/$checkout_ref $current_db_test_dir forward_${checkout_ref}_dump.txt 0
  315. fi
  316. if member_of_array "$checkout_ref" "${db_forward_with_options_refs[@]}"
  317. then
  318. echo "== Use $checkout_ref to open DB generated using $current_checkout_name with its options..."
  319. compare_db $db_test_dir/$checkout_ref $current_db_test_dir forward_${checkout_ref}_dump.txt 1 1
  320. fi
  321. if member_of_array "$checkout_ref" "${bak_backward_only_refs[@]}" ||
  322. member_of_array "$checkout_ref" "${bak_forward_refs[@]}"
  323. then
  324. echo "== Use $checkout_ref to backup DB"
  325. backup_db $db_test_dir/$checkout_ref $bak_test_dir/$checkout_ref
  326. fi
  327. if member_of_array "$checkout_ref" "${bak_forward_refs[@]}"
  328. then
  329. echo "== Use $checkout_ref to restore DB from $current_checkout_name"
  330. rm -rf ${db_test_dir:?}/$checkout_ref
  331. restore_db $current_bak_test_dir $db_test_dir/$checkout_ref
  332. compare_db $db_test_dir/$checkout_ref $current_db_test_dir forward_${checkout_ref}_dump.txt 0
  333. fi
  334. done
  335. echo "== Building $current_checkout_name debug (again, final)"
  336. git reset --hard $current_checkout_hash
  337. force_no_fbcode
  338. invoke_make clean
  339. DISABLE_WARNING_AS_ERROR=1 invoke_make ldb -j$J
  340. for checkout_ref in "${checkout_refs[@]}"
  341. do
  342. # We currently assume DB backward compatibility for every branch listed
  343. echo "== Use $current_checkout_name to open DB generated using $checkout_ref..."
  344. compare_db $db_test_dir/$checkout_ref $current_db_test_dir db_dump.txt 1 0
  345. if member_of_array "$checkout_ref" "${ext_backward_only_refs[@]}" ||
  346. member_of_array "$checkout_ref" "${ext_forward_refs[@]}"
  347. then
  348. rm -rf ${ext_test_dir:?}/${checkout_ref}_ingest
  349. echo "== Use $current_checkout_name to ingest extern SST file from $checkout_ref"
  350. ingest_external_sst $ext_test_dir/${checkout_ref}_ingest $current_ext_test_dir
  351. compare_db $ext_test_dir/${checkout_ref}_ingest ${current_ext_test_dir}_ingest db_dump.txt 1 1
  352. fi
  353. if member_of_array "$checkout_ref" "${bak_backward_only_refs[@]}" ||
  354. member_of_array "$checkout_ref" "${bak_forward_refs[@]}"
  355. then
  356. echo "== Use $current_checkout_name to restore DB from $checkout_ref"
  357. rm -rf ${db_test_dir:?}/$checkout_ref
  358. restore_db $bak_test_dir/$checkout_ref $db_test_dir/$checkout_ref
  359. compare_db $db_test_dir/$checkout_ref $current_db_test_dir db_dump.txt 1 0
  360. fi
  361. done
  362. if [ "$SANITY_CHECK" ]; then
  363. echo "==== check_format_compatible.sh sanity check PASSED ===="
  364. else
  365. echo ==== Compatibility Test PASSED ====
  366. fi