switchman 1.5.0 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (667) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/switchman/shard.rb +11 -653
  3. data/app/models/switchman/shard_internal.rb +658 -0
  4. data/lib/switchman/active_record/connection_handler.rb +0 -1
  5. data/lib/switchman/engine.rb +7 -3
  6. data/lib/switchman/version.rb +1 -1
  7. metadata +19 -1323
  8. data/spec/dummy/Rakefile +0 -7
  9. data/spec/dummy/app/models/appendage.rb +0 -22
  10. data/spec/dummy/app/models/digit.rb +0 -7
  11. data/spec/dummy/app/models/face.rb +0 -3
  12. data/spec/dummy/app/models/feature.rb +0 -3
  13. data/spec/dummy/app/models/mirror_user.rb +0 -5
  14. data/spec/dummy/app/models/root.rb +0 -5
  15. data/spec/dummy/app/models/user.rb +0 -29
  16. data/spec/dummy/config/application.rb +0 -48
  17. data/spec/dummy/config/boot.rb +0 -10
  18. data/spec/dummy/config/database.yml +0 -21
  19. data/spec/dummy/config/database.yml.example +0 -25
  20. data/spec/dummy/config/database.yml.travis +0 -4
  21. data/spec/dummy/config/environment.rb +0 -5
  22. data/spec/dummy/config/environments/development.rb +0 -26
  23. data/spec/dummy/config/environments/production.rb +0 -66
  24. data/spec/dummy/config/environments/test.rb +0 -28
  25. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  26. data/spec/dummy/config/initializers/migrations_path.rb +0 -5
  27. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  28. data/spec/dummy/config/initializers/session_store.rb +0 -8
  29. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  30. data/spec/dummy/config/routes.rb +0 -8
  31. data/spec/dummy/config.ru +0 -4
  32. data/spec/dummy/db/development.sqlite3 +0 -0
  33. data/spec/dummy/db/migrate/20130403132607_create_users.rb +0 -10
  34. data/spec/dummy/db/migrate/20130411202442_create_appendages.rb +0 -10
  35. data/spec/dummy/db/migrate/20130411202551_create_mirror_users.rb +0 -9
  36. data/spec/dummy/db/migrate/20131022202028_create_digits.rb +0 -10
  37. data/spec/dummy/db/migrate/20131206172923_create_features.rb +0 -12
  38. data/spec/dummy/db/migrate/20140123154135_add_parent_id_to_users.rb +0 -5
  39. data/spec/dummy/db/migrate/20140219183820_create_roots.rb +0 -9
  40. data/spec/dummy/db/migrate/20150618035859_add_dummy_foreign_key.rb +0 -5
  41. data/spec/dummy/db/migrate/20160122150718_create_faces.rb +0 -9
  42. data/spec/dummy/db/schema.rb +0 -74
  43. data/spec/dummy/db/shard_1006.sqlite3 +0 -0
  44. data/spec/dummy/db/shard_101.sqlite3 +0 -0
  45. data/spec/dummy/db/shard_1020.sqlite3 +0 -0
  46. data/spec/dummy/db/shard_1038.sqlite3 +0 -0
  47. data/spec/dummy/db/shard_1051.sqlite3 +0 -0
  48. data/spec/dummy/db/shard_1067.sqlite3 +0 -0
  49. data/spec/dummy/db/shard_1083.sqlite3 +0 -0
  50. data/spec/dummy/db/shard_1088.sqlite3 +0 -0
  51. data/spec/dummy/db/shard_1093.sqlite3 +0 -0
  52. data/spec/dummy/db/shard_1119.sqlite3 +0 -0
  53. data/spec/dummy/db/shard_1124.sqlite3 +0 -0
  54. data/spec/dummy/db/shard_1126.sqlite3 +0 -0
  55. data/spec/dummy/db/shard_1147.sqlite3 +0 -0
  56. data/spec/dummy/db/shard_1156.sqlite3 +0 -0
  57. data/spec/dummy/db/shard_117.sqlite3 +0 -0
  58. data/spec/dummy/db/shard_1173.sqlite3 +0 -0
  59. data/spec/dummy/db/shard_1186.sqlite3 +0 -0
  60. data/spec/dummy/db/shard_120.sqlite3 +0 -0
  61. data/spec/dummy/db/shard_1206.sqlite3 +0 -0
  62. data/spec/dummy/db/shard_1220.sqlite3 +0 -0
  63. data/spec/dummy/db/shard_1248.sqlite3 +0 -0
  64. data/spec/dummy/db/shard_1259.sqlite3 +0 -0
  65. data/spec/dummy/db/shard_1276.sqlite3 +0 -0
  66. data/spec/dummy/db/shard_1286.sqlite3 +0 -0
  67. data/spec/dummy/db/shard_1297.sqlite3 +0 -0
  68. data/spec/dummy/db/shard_1309.sqlite3 +0 -0
  69. data/spec/dummy/db/shard_1330.sqlite3 +0 -0
  70. data/spec/dummy/db/shard_1345.sqlite3 +0 -0
  71. data/spec/dummy/db/shard_1361.sqlite3 +0 -0
  72. data/spec/dummy/db/shard_1377.sqlite3 +0 -0
  73. data/spec/dummy/db/shard_1384.sqlite3 +0 -0
  74. data/spec/dummy/db/shard_1392.sqlite3 +0 -0
  75. data/spec/dummy/db/shard_1422.sqlite3 +0 -0
  76. data/spec/dummy/db/shard_143.sqlite3 +0 -0
  77. data/spec/dummy/db/shard_1446.sqlite3 +0 -0
  78. data/spec/dummy/db/shard_1463.sqlite3 +0 -0
  79. data/spec/dummy/db/shard_1481.sqlite3 +0 -0
  80. data/spec/dummy/db/shard_1493.sqlite3 +0 -0
  81. data/spec/dummy/db/shard_1508.sqlite3 +0 -0
  82. data/spec/dummy/db/shard_1517.sqlite3 +0 -0
  83. data/spec/dummy/db/shard_1528.sqlite3 +0 -0
  84. data/spec/dummy/db/shard_1542.sqlite3 +0 -0
  85. data/spec/dummy/db/shard_1553.sqlite3 +0 -0
  86. data/spec/dummy/db/shard_156.sqlite3 +0 -0
  87. data/spec/dummy/db/shard_1588.sqlite3 +0 -0
  88. data/spec/dummy/db/shard_1596.sqlite3 +0 -0
  89. data/spec/dummy/db/shard_1609.sqlite3 +0 -0
  90. data/spec/dummy/db/shard_1630.sqlite3 +0 -0
  91. data/spec/dummy/db/shard_1643.sqlite3 +0 -0
  92. data/spec/dummy/db/shard_1652.sqlite3 +0 -0
  93. data/spec/dummy/db/shard_1658.sqlite3 +0 -0
  94. data/spec/dummy/db/shard_1679.sqlite3 +0 -0
  95. data/spec/dummy/db/shard_170.sqlite3 +0 -0
  96. data/spec/dummy/db/shard_1700.sqlite3 +0 -0
  97. data/spec/dummy/db/shard_1703.sqlite3 +0 -0
  98. data/spec/dummy/db/shard_1721.sqlite3 +0 -0
  99. data/spec/dummy/db/shard_1733.sqlite3 +0 -0
  100. data/spec/dummy/db/shard_1746.sqlite3 +0 -0
  101. data/spec/dummy/db/shard_1759.sqlite3 +0 -0
  102. data/spec/dummy/db/shard_1783.sqlite3 +0 -0
  103. data/spec/dummy/db/shard_1809.sqlite3 +0 -0
  104. data/spec/dummy/db/shard_1846.sqlite3 +0 -0
  105. data/spec/dummy/db/shard_1872.sqlite3 +0 -0
  106. data/spec/dummy/db/shard_1881.sqlite3 +0 -0
  107. data/spec/dummy/db/shard_19.sqlite3 +0 -0
  108. data/spec/dummy/db/shard_1906.sqlite3 +0 -0
  109. data/spec/dummy/db/shard_191.sqlite3 +0 -0
  110. data/spec/dummy/db/shard_193.sqlite3 +0 -0
  111. data/spec/dummy/db/shard_1934.sqlite3 +0 -0
  112. data/spec/dummy/db/shard_1981.sqlite3 +0 -0
  113. data/spec/dummy/db/shard_2.sqlite3 +0 -0
  114. data/spec/dummy/db/shard_2006.sqlite3 +0 -0
  115. data/spec/dummy/db/shard_2013.sqlite3 +0 -0
  116. data/spec/dummy/db/shard_2041.sqlite3 +0 -0
  117. data/spec/dummy/db/shard_206.sqlite3 +0 -0
  118. data/spec/dummy/db/shard_2086.sqlite3 +0 -0
  119. data/spec/dummy/db/shard_2097.sqlite3 +0 -0
  120. data/spec/dummy/db/shard_2132.sqlite3 +0 -0
  121. data/spec/dummy/db/shard_2158.sqlite3 +0 -0
  122. data/spec/dummy/db/shard_2193.sqlite3 +0 -0
  123. data/spec/dummy/db/shard_2203.sqlite3 +0 -0
  124. data/spec/dummy/db/shard_2256.sqlite3 +0 -0
  125. data/spec/dummy/db/shard_23.sqlite3 +0 -0
  126. data/spec/dummy/db/shard_2301.sqlite3 +0 -0
  127. data/spec/dummy/db/shard_2336.sqlite3 +0 -0
  128. data/spec/dummy/db/shard_234.sqlite3 +0 -0
  129. data/spec/dummy/db/shard_235.sqlite3 +0 -0
  130. data/spec/dummy/db/shard_2360.sqlite3 +0 -0
  131. data/spec/dummy/db/shard_2385.sqlite3 +0 -0
  132. data/spec/dummy/db/shard_2406.sqlite3 +0 -0
  133. data/spec/dummy/db/shard_2452.sqlite3 +0 -0
  134. data/spec/dummy/db/shard_2465.sqlite3 +0 -0
  135. data/spec/dummy/db/shard_248.sqlite3 +0 -0
  136. data/spec/dummy/db/shard_2507.sqlite3 +0 -0
  137. data/spec/dummy/db/shard_2515.sqlite3 +0 -0
  138. data/spec/dummy/db/shard_2557.sqlite3 +0 -0
  139. data/spec/dummy/db/shard_257.sqlite3 +0 -0
  140. data/spec/dummy/db/shard_2580.sqlite3 +0 -0
  141. data/spec/dummy/db/shard_2598.sqlite3 +0 -0
  142. data/spec/dummy/db/shard_2626.sqlite3 +0 -0
  143. data/spec/dummy/db/shard_2672.sqlite3 +0 -0
  144. data/spec/dummy/db/shard_2681.sqlite3 +0 -0
  145. data/spec/dummy/db/shard_270.sqlite3 +0 -0
  146. data/spec/dummy/db/shard_2754.sqlite3 +0 -0
  147. data/spec/dummy/db/shard_277.sqlite3 +0 -0
  148. data/spec/dummy/db/shard_2790.sqlite3 +0 -0
  149. data/spec/dummy/db/shard_2803.sqlite3 +0 -0
  150. data/spec/dummy/db/shard_2834.sqlite3 +0 -0
  151. data/spec/dummy/db/shard_2862.sqlite3 +0 -0
  152. data/spec/dummy/db/shard_2897.sqlite3 +0 -0
  153. data/spec/dummy/db/shard_2928.sqlite3 +0 -0
  154. data/spec/dummy/db/shard_2951.sqlite3 +0 -0
  155. data/spec/dummy/db/shard_2970.sqlite3 +0 -0
  156. data/spec/dummy/db/shard_3009.sqlite3 +0 -0
  157. data/spec/dummy/db/shard_304.sqlite3 +0 -0
  158. data/spec/dummy/db/shard_3046.sqlite3 +0 -0
  159. data/spec/dummy/db/shard_3071.sqlite3 +0 -0
  160. data/spec/dummy/db/shard_311.sqlite3 +0 -0
  161. data/spec/dummy/db/shard_3114.sqlite3 +0 -0
  162. data/spec/dummy/db/shard_3157.sqlite3 +0 -0
  163. data/spec/dummy/db/shard_3234.sqlite3 +0 -0
  164. data/spec/dummy/db/shard_324.sqlite3 +0 -0
  165. data/spec/dummy/db/shard_3288.sqlite3 +0 -0
  166. data/spec/dummy/db/shard_333.sqlite3 +0 -0
  167. data/spec/dummy/db/shard_3352.sqlite3 +0 -0
  168. data/spec/dummy/db/shard_3380.sqlite3 +0 -0
  169. data/spec/dummy/db/shard_342.sqlite3 +0 -0
  170. data/spec/dummy/db/shard_3424.sqlite3 +0 -0
  171. data/spec/dummy/db/shard_3442.sqlite3 +0 -0
  172. data/spec/dummy/db/shard_3460.sqlite3 +0 -0
  173. data/spec/dummy/db/shard_347.sqlite3 +0 -0
  174. data/spec/dummy/db/shard_3488.sqlite3 +0 -0
  175. data/spec/dummy/db/shard_3524.sqlite3 +0 -0
  176. data/spec/dummy/db/shard_3554.sqlite3 +0 -0
  177. data/spec/dummy/db/shard_3594.sqlite3 +0 -0
  178. data/spec/dummy/db/shard_3611.sqlite3 +0 -0
  179. data/spec/dummy/db/shard_3639.sqlite3 +0 -0
  180. data/spec/dummy/db/shard_3661.sqlite3 +0 -0
  181. data/spec/dummy/db/shard_3689.sqlite3 +0 -0
  182. data/spec/dummy/db/shard_3749.sqlite3 +0 -0
  183. data/spec/dummy/db/shard_375.sqlite3 +0 -0
  184. data/spec/dummy/db/shard_3792.sqlite3 +0 -0
  185. data/spec/dummy/db/shard_3819.sqlite3 +0 -0
  186. data/spec/dummy/db/shard_385.sqlite3 +0 -0
  187. data/spec/dummy/db/shard_3866.sqlite3 +0 -0
  188. data/spec/dummy/db/shard_389.sqlite3 +0 -0
  189. data/spec/dummy/db/shard_3897.sqlite3 +0 -0
  190. data/spec/dummy/db/shard_405.sqlite3 +0 -0
  191. data/spec/dummy/db/shard_427.sqlite3 +0 -0
  192. data/spec/dummy/db/shard_428.sqlite3 +0 -0
  193. data/spec/dummy/db/shard_441.sqlite3 +0 -0
  194. data/spec/dummy/db/shard_452.sqlite3 +0 -0
  195. data/spec/dummy/db/shard_462.sqlite3 +0 -0
  196. data/spec/dummy/db/shard_472.sqlite3 +0 -0
  197. data/spec/dummy/db/shard_483.sqlite3 +0 -0
  198. data/spec/dummy/db/shard_49.sqlite3 +0 -0
  199. data/spec/dummy/db/shard_505.sqlite3 +0 -0
  200. data/spec/dummy/db/shard_508.sqlite3 +0 -0
  201. data/spec/dummy/db/shard_531.sqlite3 +0 -0
  202. data/spec/dummy/db/shard_554.sqlite3 +0 -0
  203. data/spec/dummy/db/shard_577.sqlite3 +0 -0
  204. data/spec/dummy/db/shard_58.sqlite3 +0 -0
  205. data/spec/dummy/db/shard_600.sqlite3 +0 -0
  206. data/spec/dummy/db/shard_623.sqlite3 +0 -0
  207. data/spec/dummy/db/shard_646.sqlite3 +0 -0
  208. data/spec/dummy/db/shard_668.sqlite3 +0 -0
  209. data/spec/dummy/db/shard_680.sqlite3 +0 -0
  210. data/spec/dummy/db/shard_698.sqlite3 +0 -0
  211. data/spec/dummy/db/shard_708.sqlite3 +0 -0
  212. data/spec/dummy/db/shard_727.sqlite3 +0 -0
  213. data/spec/dummy/db/shard_735.sqlite3 +0 -0
  214. data/spec/dummy/db/shard_74.sqlite3 +0 -0
  215. data/spec/dummy/db/shard_753.sqlite3 +0 -0
  216. data/spec/dummy/db/shard_76.sqlite3 +0 -0
  217. data/spec/dummy/db/shard_766.sqlite3 +0 -0
  218. data/spec/dummy/db/shard_778.sqlite3 +0 -0
  219. data/spec/dummy/db/shard_802.sqlite3 +0 -0
  220. data/spec/dummy/db/shard_818.sqlite3 +0 -0
  221. data/spec/dummy/db/shard_827.sqlite3 +0 -0
  222. data/spec/dummy/db/shard_869.sqlite3 +0 -0
  223. data/spec/dummy/db/shard_887.sqlite3 +0 -0
  224. data/spec/dummy/db/shard_895.sqlite3 +0 -0
  225. data/spec/dummy/db/shard_923.sqlite3 +0 -0
  226. data/spec/dummy/db/shard_930.sqlite3 +0 -0
  227. data/spec/dummy/db/shard_948.sqlite3 +0 -0
  228. data/spec/dummy/db/shard_953.sqlite3 +0 -0
  229. data/spec/dummy/db/shard_955.sqlite3 +0 -0
  230. data/spec/dummy/db/shard_982.sqlite3 +0 -0
  231. data/spec/dummy/db/shard_988.sqlite3 +0 -0
  232. data/spec/dummy/db/shard_989.sqlite3 +0 -0
  233. data/spec/dummy/db/test.sqlite3 +0 -0
  234. data/spec/dummy/log/development.log +0 -153
  235. data/spec/dummy/log/test.log +0 -21720
  236. data/spec/dummy/script/rails +0 -6
  237. data/spec/dummy/tmp/cache/316/980/shard%2F15 +0 -1
  238. data/spec/dummy/tmp/cache/319/A10/shard%2F72 +0 -1
  239. data/spec/dummy/tmp/cache/31A/A30/shard%2F82 +0 -0
  240. data/spec/dummy/tmp/cache/31B/A40/shard%2F83 +0 -0
  241. data/spec/dummy/tmp/cache/31C/A10/shard%2F48 +0 -1
  242. data/spec/dummy/tmp/cache/31C/A50/shard%2F84 +0 -1
  243. data/spec/dummy/tmp/cache/344/D90/shard%2F121 +0 -1
  244. data/spec/dummy/tmp/cache/344/DB0/shard%2F220 +0 -0
  245. data/spec/dummy/tmp/cache/345/DC0/shard%2F221 +0 -0
  246. data/spec/dummy/tmp/cache/346/DE0/shard%2F231 +0 -1
  247. data/spec/dummy/tmp/cache/346/E10/shard%2F501 +0 -1
  248. data/spec/dummy/tmp/cache/347/DE0/shard%2F142 +0 -1
  249. data/spec/dummy/tmp/cache/347/DF0/shard%2F151 +0 -1
  250. data/spec/dummy/tmp/cache/348/E30/shard%2F422 +0 -1
  251. data/spec/dummy/tmp/cache/349/E20/shard%2F243 +0 -0
  252. data/spec/dummy/tmp/cache/349/E40/shard%2F423 +0 -1
  253. data/spec/dummy/tmp/cache/34A/E00/shard%2F217 +0 -1
  254. data/spec/dummy/tmp/cache/34A/E20/shard%2F316 +0 -1
  255. data/spec/dummy/tmp/cache/34A/E30/shard%2F244 +0 -0
  256. data/spec/dummy/tmp/cache/34A/E30/shard%2F325 +0 -1
  257. data/spec/dummy/tmp/cache/34A/E90/shard%2F460 +0 -0
  258. data/spec/dummy/tmp/cache/34A/EC0/shard%2F730 +0 -1
  259. data/spec/dummy/tmp/cache/34B/E40/shard%2F245 +0 -1
  260. data/spec/dummy/tmp/cache/34B/E60/shard%2F344 +0 -1
  261. data/spec/dummy/tmp/cache/34B/E60/shard%2F425 +0 -1
  262. data/spec/dummy/tmp/cache/34B/E70/shard%2F434 +0 -1
  263. data/spec/dummy/tmp/cache/34C/E40/shard%2F156 +0 -1
  264. data/spec/dummy/tmp/cache/34C/E80/shard%2F354 +0 -1
  265. data/spec/dummy/tmp/cache/34C/EA0/shard%2F453 +0 -1
  266. data/spec/dummy/tmp/cache/34C/EF0/shard%2F822 +0 -0
  267. data/spec/dummy/tmp/cache/34D/E60/shard%2F409 +0 -1
  268. data/spec/dummy/tmp/cache/34D/EC0/shard%2F382 +0 -1
  269. data/spec/dummy/tmp/cache/34D/EE0/shard%2F724 +0 -1
  270. data/spec/dummy/tmp/cache/34E/EA0/shard%2F437 +0 -1
  271. data/spec/dummy/tmp/cache/34E/EF0/shard%2F806 +0 -1
  272. data/spec/dummy/tmp/cache/34F/EB0/shard%2F438 +0 -1
  273. data/spec/dummy/tmp/cache/34F/EC0/shard%2F285 +0 -1
  274. data/spec/dummy/tmp/cache/34F/F20/shard%2F744 +0 -0
  275. data/spec/dummy/tmp/cache/350/EF0/shard%2F466 +0 -1
  276. data/spec/dummy/tmp/cache/350/F30/shard%2F907 +0 -1
  277. data/spec/dummy/tmp/cache/351/EC0/shard%2F188 +0 -1
  278. data/spec/dummy/tmp/cache/351/EE0/shard%2F368 +0 -1
  279. data/spec/dummy/tmp/cache/351/F50/shard%2F917 +0 -0
  280. data/spec/dummy/tmp/cache/351/F60/shard%2F926 +0 -0
  281. data/spec/dummy/tmp/cache/351/F70/shard%2F935 +0 -1
  282. data/spec/dummy/tmp/cache/351/FB0/shard%2F971 +0 -1
  283. data/spec/dummy/tmp/cache/352/EF0/shard%2F369 +0 -1
  284. data/spec/dummy/tmp/cache/352/F70/shard%2F927 +0 -0
  285. data/spec/dummy/tmp/cache/352/F80/shard%2F693 +0 -1
  286. data/spec/dummy/tmp/cache/352/F90/shard%2F864 +0 -1
  287. data/spec/dummy/tmp/cache/353/F70/shard%2F838 +0 -1
  288. data/spec/dummy/tmp/cache/354/FA0/shard%2F776 +0 -1
  289. data/spec/dummy/tmp/cache/354/FF0/shard%2F983 +0 -1
  290. data/spec/dummy/tmp/cache/355/F90/shard%2F759 +0 -1
  291. data/spec/dummy/tmp/cache/357/FF0/shard%2F878 +0 -1
  292. data/spec/dummy/tmp/cache/374/490/shard%2F1012 +0 -1
  293. data/spec/dummy/tmp/cache/374/4C0/shard%2F2011 +0 -1
  294. data/spec/dummy/tmp/cache/376/500/shard%2F1140 +0 -1
  295. data/spec/dummy/tmp/cache/376/510/shard%2F1230 +0 -0
  296. data/spec/dummy/tmp/cache/376/550/shard%2F3210 +0 -1
  297. data/spec/dummy/tmp/cache/377/510/shard%2F1222 +0 -0
  298. data/spec/dummy/tmp/cache/377/540/shard%2F2221 +0 -1
  299. data/spec/dummy/tmp/cache/377/560/shard%2F3211 +0 -1
  300. data/spec/dummy/tmp/cache/378/510/shard%2F2105 +0 -1
  301. data/spec/dummy/tmp/cache/378/570/shard%2F3050 +0 -1
  302. data/spec/dummy/tmp/cache/379/4F0/shard%2F1107 +0 -1
  303. data/spec/dummy/tmp/cache/379/540/shard%2F3015 +0 -1
  304. data/spec/dummy/tmp/cache/379/550/shard%2F3024 +0 -1
  305. data/spec/dummy/tmp/cache/379/560/shard%2F2061 +0 -1
  306. data/spec/dummy/tmp/cache/379/570/shard%2F1341 +0 -1
  307. data/spec/dummy/tmp/cache/379/580/shard%2F2160 +0 -1
  308. data/spec/dummy/tmp/cache/379/580/shard%2F2403 +0 -1
  309. data/spec/dummy/tmp/cache/379/590/shard%2F1602 +0 -0
  310. data/spec/dummy/tmp/cache/379/5C0/shard%2F1710 +0 -1
  311. data/spec/dummy/tmp/cache/37A/510/shard%2F1117 +0 -1
  312. data/spec/dummy/tmp/cache/37A/540/shard%2F1063 +0 -1
  313. data/spec/dummy/tmp/cache/37A/540/shard%2F2035 +0 -1
  314. data/spec/dummy/tmp/cache/37A/550/shard%2F1315 +0 -1
  315. data/spec/dummy/tmp/cache/37A/570/shard%2F1252 +0 -1
  316. data/spec/dummy/tmp/cache/37A/570/shard%2F1414 +0 -1
  317. data/spec/dummy/tmp/cache/37A/5A0/shard%2F1360 +0 -1
  318. data/spec/dummy/tmp/cache/37A/5A0/shard%2F1603 +0 -0
  319. data/spec/dummy/tmp/cache/37A/5B0/shard%2F3151 +0 -1
  320. data/spec/dummy/tmp/cache/37A/5C0/shard%2F3322 +0 -1
  321. data/spec/dummy/tmp/cache/37A/5E0/shard%2F2611 +0 -1
  322. data/spec/dummy/tmp/cache/37B/520/shard%2F1118 +0 -1
  323. data/spec/dummy/tmp/cache/37B/540/shard%2F1217 +0 -1
  324. data/spec/dummy/tmp/cache/37B/550/shard%2F1064 +0 -1
  325. data/spec/dummy/tmp/cache/37B/560/shard%2F1154 +0 -1
  326. data/spec/dummy/tmp/cache/37B/5A0/shard%2F2081 +0 -1
  327. data/spec/dummy/tmp/cache/37B/5A0/shard%2F2324 +0 -1
  328. data/spec/dummy/tmp/cache/37B/5B0/shard%2F1361 +0 -1
  329. data/spec/dummy/tmp/cache/37B/5B0/shard%2F3062 +0 -1
  330. data/spec/dummy/tmp/cache/37B/5C0/shard%2F3152 +0 -1
  331. data/spec/dummy/tmp/cache/37B/5D0/shard%2F3161 +0 -1
  332. data/spec/dummy/tmp/cache/37B/5D0/shard%2F3323 +0 -1
  333. data/spec/dummy/tmp/cache/37C/570/shard%2F2127 +0 -1
  334. data/spec/dummy/tmp/cache/37C/5C0/shard%2F1524 +0 -1
  335. data/spec/dummy/tmp/cache/37C/5D0/shard%2F2343 +0 -1
  336. data/spec/dummy/tmp/cache/37C/5E0/shard%2F2352 +0 -1
  337. data/spec/dummy/tmp/cache/37C/5E0/shard%2F3081 +0 -1
  338. data/spec/dummy/tmp/cache/37C/5F0/shard%2F3090 +0 -1
  339. data/spec/dummy/tmp/cache/37D/560/shard%2F1057 +0 -1
  340. data/spec/dummy/tmp/cache/37D/570/shard%2F2038 +0 -1
  341. data/spec/dummy/tmp/cache/37D/5C0/shard%2F1273 +0 -1
  342. data/spec/dummy/tmp/cache/37D/5D0/shard%2F2092 +0 -1
  343. data/spec/dummy/tmp/cache/37D/5D0/shard%2F3145 +0 -1
  344. data/spec/dummy/tmp/cache/37D/5D0/shard%2F3226 +0 -1
  345. data/spec/dummy/tmp/cache/37D/5E0/shard%2F2344 +0 -1
  346. data/spec/dummy/tmp/cache/37D/5F0/shard%2F1624 +0 -1
  347. data/spec/dummy/tmp/cache/37D/5F0/shard%2F3082 +0 -2
  348. data/spec/dummy/tmp/cache/37D/5F0/shard%2F3406 +0 -1
  349. data/spec/dummy/tmp/cache/37D/600/shard%2F3091 +0 -1
  350. data/spec/dummy/tmp/cache/37D/610/shard%2F1723 +0 -1
  351. data/spec/dummy/tmp/cache/37D/630/shard%2F1903 +0 -1
  352. data/spec/dummy/tmp/cache/37D/640/shard%2F1750 +0 -1
  353. data/spec/dummy/tmp/cache/37D/650/shard%2F2812 +0 -1
  354. data/spec/dummy/tmp/cache/37D/650/shard%2F3622 +0 -1
  355. data/spec/dummy/tmp/cache/37D/660/shard%2F2740 +0 -2
  356. data/spec/dummy/tmp/cache/37E/580/shard%2F2039 +0 -1
  357. data/spec/dummy/tmp/cache/37E/590/shard%2F1238 +0 -1
  358. data/spec/dummy/tmp/cache/37E/5B0/shard%2F1418 +0 -1
  359. data/spec/dummy/tmp/cache/37E/5B0/shard%2F3119 +0 -1
  360. data/spec/dummy/tmp/cache/37E/5D0/shard%2F1193 +0 -1
  361. data/spec/dummy/tmp/cache/37E/5E0/shard%2F3146 +0 -1
  362. data/spec/dummy/tmp/cache/37E/630/shard%2F1490 +0 -1
  363. data/spec/dummy/tmp/cache/37E/640/shard%2F1904 +0 -1
  364. data/spec/dummy/tmp/cache/37E/640/shard%2F2390 +0 -1
  365. data/spec/dummy/tmp/cache/37E/660/shard%2F1922 +0 -1
  366. data/spec/dummy/tmp/cache/37F/610/shard%2F3084 +0 -1
  367. data/spec/dummy/tmp/cache/37F/640/shard%2F1491 +0 -1
  368. data/spec/dummy/tmp/cache/37F/640/shard%2F1815 +0 -1
  369. data/spec/dummy/tmp/cache/37F/660/shard%2F2562 +0 -1
  370. data/spec/dummy/tmp/cache/37F/680/shard%2F2823 +0 -1
  371. data/spec/dummy/tmp/cache/37F/6A0/shard%2F3570 +0 -1
  372. data/spec/dummy/tmp/cache/37F/6A0/shard%2F3813 +0 -1
  373. data/spec/dummy/tmp/cache/37F/6B0/shard%2F2931 +0 -1
  374. data/spec/dummy/tmp/cache/380/5F0/shard%2F1357 +0 -1
  375. data/spec/dummy/tmp/cache/380/600/shard%2F3148 +0 -1
  376. data/spec/dummy/tmp/cache/380/620/shard%2F1384 +0 -1
  377. data/spec/dummy/tmp/cache/380/620/shard%2F3085 +0 -1
  378. data/spec/dummy/tmp/cache/380/630/shard%2F1636 +0 -1
  379. data/spec/dummy/tmp/cache/380/630/shard%2F2527 +0 -1
  380. data/spec/dummy/tmp/cache/380/640/shard%2F3508 +0 -1
  381. data/spec/dummy/tmp/cache/380/670/shard%2F2644 +0 -1
  382. data/spec/dummy/tmp/cache/380/670/shard%2F3292 +0 -1
  383. data/spec/dummy/tmp/cache/380/690/shard%2F2824 +0 -1
  384. data/spec/dummy/tmp/cache/380/6B0/shard%2F3571 +0 -1
  385. data/spec/dummy/tmp/cache/380/6B0/shard%2F3814 +0 -1
  386. data/spec/dummy/tmp/cache/380/6E0/shard%2F2950 +0 -1
  387. data/spec/dummy/tmp/cache/380/6E0/shard%2F3841 +0 -1
  388. data/spec/dummy/tmp/cache/380/6F0/shard%2F3850 +0 -2
  389. data/spec/dummy/tmp/cache/381/5C0/shard%2F1079 +0 -1
  390. data/spec/dummy/tmp/cache/381/610/shard%2F3149 +0 -1
  391. data/spec/dummy/tmp/cache/381/640/shard%2F3338 +0 -1
  392. data/spec/dummy/tmp/cache/381/660/shard%2F3437 +0 -1
  393. data/spec/dummy/tmp/cache/381/690/shard%2F3707 +0 -1
  394. data/spec/dummy/tmp/cache/382/630/shard%2F2187 +0 -1
  395. data/spec/dummy/tmp/cache/382/630/shard%2F3078 +0 -1
  396. data/spec/dummy/tmp/cache/382/640/shard%2F1629 +0 -1
  397. data/spec/dummy/tmp/cache/382/640/shard%2F2277 +0 -1
  398. data/spec/dummy/tmp/cache/382/640/shard%2F3087 +0 -1
  399. data/spec/dummy/tmp/cache/382/650/shard%2F1395 +0 -1
  400. data/spec/dummy/tmp/cache/382/650/shard%2F2448 +0 -1
  401. data/spec/dummy/tmp/cache/382/660/shard%2F2295 +0 -1
  402. data/spec/dummy/tmp/cache/382/670/shard%2F1656 +0 -1
  403. data/spec/dummy/tmp/cache/382/690/shard%2F1836 +0 -1
  404. data/spec/dummy/tmp/cache/382/6A0/shard%2F3384 +0 -1
  405. data/spec/dummy/tmp/cache/382/6B0/shard%2F3636 +0 -1
  406. data/spec/dummy/tmp/cache/382/6D0/shard%2F3654 +0 -1
  407. data/spec/dummy/tmp/cache/382/6F0/shard%2F2781 +0 -1
  408. data/spec/dummy/tmp/cache/382/700/shard%2F2871 +0 -1
  409. data/spec/dummy/tmp/cache/383/640/shard%2F1297 +0 -1
  410. data/spec/dummy/tmp/cache/383/640/shard%2F1459 +0 -1
  411. data/spec/dummy/tmp/cache/383/640/shard%2F3079 +0 -1
  412. data/spec/dummy/tmp/cache/383/650/shard%2F3088 +0 -1
  413. data/spec/dummy/tmp/cache/383/6B0/shard%2F2494 +0 -1
  414. data/spec/dummy/tmp/cache/383/6B0/shard%2F2575 +0 -2
  415. data/spec/dummy/tmp/cache/383/6E0/shard%2F1792 +0 -1
  416. data/spec/dummy/tmp/cache/383/6E0/shard%2F3574 +0 -1
  417. data/spec/dummy/tmp/cache/383/6F0/shard%2F2935 +0 -1
  418. data/spec/dummy/tmp/cache/383/6F0/shard%2F3745 +0 -1
  419. data/spec/dummy/tmp/cache/383/710/shard%2F3682 +0 -1
  420. data/spec/dummy/tmp/cache/384/6B0/shard%2F3458 +0 -1
  421. data/spec/dummy/tmp/cache/384/6B0/shard%2F3539 +0 -1
  422. data/spec/dummy/tmp/cache/384/6E0/shard%2F3566 +0 -1
  423. data/spec/dummy/tmp/cache/384/700/shard%2F2693 +0 -1
  424. data/spec/dummy/tmp/cache/384/700/shard%2F2936 +0 -1
  425. data/spec/dummy/tmp/cache/384/710/shard%2F3836 +0 -1
  426. data/spec/dummy/tmp/cache/384/720/shard%2F3683 +0 -1
  427. data/spec/dummy/tmp/cache/385/6C0/shard%2F1677 +0 -1
  428. data/spec/dummy/tmp/cache/385/6D0/shard%2F2739 +0 -2
  429. data/spec/dummy/tmp/cache/385/6E0/shard%2F1695 +0 -1
  430. data/spec/dummy/tmp/cache/385/6E0/shard%2F1938 +0 -1
  431. data/spec/dummy/tmp/cache/385/6E0/shard%2F2586 +0 -1
  432. data/spec/dummy/tmp/cache/385/760/shard%2F2982 +0 -1
  433. data/spec/dummy/tmp/cache/386/6C0/shard%2F2479 +0 -1
  434. data/spec/dummy/tmp/cache/386/6E0/shard%2F3469 +0 -1
  435. data/spec/dummy/tmp/cache/386/710/shard%2F2767 +0 -2
  436. data/spec/dummy/tmp/cache/386/710/shard%2F2848 +0 -1
  437. data/spec/dummy/tmp/cache/386/740/shard%2F3847 +0 -1
  438. data/spec/dummy/tmp/cache/387/700/shard%2F2669 +0 -1
  439. data/spec/dummy/tmp/cache/387/710/shard%2F2759 +0 -1
  440. data/spec/dummy/tmp/cache/387/770/shard%2F3785 +0 -1
  441. data/spec/dummy/tmp/cache/387/780/shard%2F3875 +0 -1
  442. data/spec/dummy/tmp/cache/388/720/shard%2F1869 +0 -1
  443. data/spec/dummy/tmp/cache/388/770/shard%2F2886 +0 -1
  444. data/spec/dummy/tmp/cache/389/750/shard%2F1969 +0 -1
  445. data/spec/dummy/tmp/cache/389/760/shard%2F3598 +0 -1
  446. data/spec/dummy/tmp/cache/389/760/shard%2F3679 +0 -1
  447. data/spec/dummy/tmp/cache/38A/770/shard%2F3599 +0 -1
  448. data/spec/dummy/tmp/cache/38A/780/shard%2F1988 +0 -1
  449. data/spec/dummy/tmp/cache/38B/780/shard%2F1899 +0 -1
  450. data/spec/dummy/tmp/cache/38B/7B0/shard%2F3789 +0 -1
  451. data/spec/dummy/tmp/cache/38C/7E0/shard%2F3889 +0 -1
  452. data/spec/dummy/tmp/cache/3A4/EA0/shard%2F10012 +0 -1
  453. data/spec/dummy/tmp/cache/3A4/EE0/shard%2F11101 +0 -1
  454. data/spec/dummy/tmp/cache/3A4/F20/shard%2F13000 +0 -1
  455. data/spec/dummy/tmp/cache/3A5/EA0/shard%2F10004 +0 -1
  456. data/spec/dummy/tmp/cache/3A6/F10/shard%2F10221 +0 -1
  457. data/spec/dummy/tmp/cache/3A6/F20/shard%2F12012 +0 -1
  458. data/spec/dummy/tmp/cache/3A6/F40/shard%2F10410 +0 -1
  459. data/spec/dummy/tmp/cache/3A6/F50/shard%2F12120 +0 -1
  460. data/spec/dummy/tmp/cache/3A6/F50/shard%2F12201 +0 -1
  461. data/spec/dummy/tmp/cache/3A7/EF0/shard%2F11005 +0 -1
  462. data/spec/dummy/tmp/cache/3A7/F20/shard%2F10060 +0 -1
  463. data/spec/dummy/tmp/cache/3A7/F20/shard%2F11032 +0 -1
  464. data/spec/dummy/tmp/cache/3A7/F30/shard%2F10231 +0 -1
  465. data/spec/dummy/tmp/cache/3A7/FA0/shard%2F12400 +0 -1
  466. data/spec/dummy/tmp/cache/3A8/EF0/shard%2F10106 +0 -1
  467. data/spec/dummy/tmp/cache/3A8/F50/shard%2F10322 +0 -1
  468. data/spec/dummy/tmp/cache/3A8/F70/shard%2F11312 +0 -1
  469. data/spec/dummy/tmp/cache/3A8/F90/shard%2F10520 +0 -1
  470. data/spec/dummy/tmp/cache/3A8/FB0/shard%2F13211 +0 -1
  471. data/spec/dummy/tmp/cache/3A9/F40/shard%2F10062 +0 -1
  472. data/spec/dummy/tmp/cache/3A9/F50/shard%2F10152 +0 -1
  473. data/spec/dummy/tmp/cache/3A9/F50/shard%2F11124 +0 -1
  474. data/spec/dummy/tmp/cache/3A9/F80/shard%2F10341 +0 -1
  475. data/spec/dummy/tmp/cache/3A9/F90/shard%2F13023 +0 -1
  476. data/spec/dummy/tmp/cache/3AA/F10/shard%2F10027 +0 -1
  477. data/spec/dummy/tmp/cache/3AA/F10/shard%2F10108 +0 -1
  478. data/spec/dummy/tmp/cache/3AA/F30/shard%2F10045 +0 -1
  479. data/spec/dummy/tmp/cache/3AA/F90/shard%2F10423 +0 -1
  480. data/spec/dummy/tmp/cache/3AA/FB0/shard%2F10441 +0 -1
  481. data/spec/dummy/tmp/cache/3AA/FB0/shard%2F11170 +0 -1
  482. data/spec/dummy/tmp/cache/3AA/FC0/shard%2F10612 +0 -1
  483. data/spec/dummy/tmp/cache/3AA/FC0/shard%2F11260 +0 -1
  484. data/spec/dummy/tmp/cache/3AA/FC0/shard%2F11503 +0 -1
  485. data/spec/dummy/tmp/cache/3AA/FC0/shard%2F12313 +0 -1
  486. data/spec/dummy/tmp/cache/3AA/FD0/shard%2F13051 +0 -1
  487. data/spec/dummy/tmp/cache/3AB/000/shard%2F11450 +0 -1
  488. data/spec/dummy/tmp/cache/3AB/010/shard%2F10730 +0 -1
  489. data/spec/dummy/tmp/cache/3AB/010/shard%2F12512 +0 -1
  490. data/spec/dummy/tmp/cache/3AB/010/shard%2F13403 +0 -1
  491. data/spec/dummy/tmp/cache/3AB/020/shard%2F10901 +0 -1
  492. data/spec/dummy/tmp/cache/3AB/020/shard%2F11630 +0 -1
  493. data/spec/dummy/tmp/cache/3AB/020/shard%2F11711 +0 -1
  494. data/spec/dummy/tmp/cache/3AB/F30/shard%2F11009 +0 -1
  495. data/spec/dummy/tmp/cache/3AB/F70/shard%2F10154 +0 -1
  496. data/spec/dummy/tmp/cache/3AB/F80/shard%2F10244 +0 -1
  497. data/spec/dummy/tmp/cache/3AB/FD0/shard%2F11342 +0 -1
  498. data/spec/dummy/tmp/cache/3AB/FF0/shard%2F11603 +0 -1
  499. data/spec/dummy/tmp/cache/3AC/000/shard%2F11280 +0 -1
  500. data/spec/dummy/tmp/cache/3AC/000/shard%2F11361 +0 -1
  501. data/spec/dummy/tmp/cache/3AC/010/shard%2F13152 +0 -1
  502. data/spec/dummy/tmp/cache/3AC/020/shard%2F10650 +0 -1
  503. data/spec/dummy/tmp/cache/3AC/050/shard%2F13431 +0 -1
  504. data/spec/dummy/tmp/cache/3AC/F60/shard%2F10137 +0 -1
  505. data/spec/dummy/tmp/cache/3AC/F70/shard%2F11037 +0 -1
  506. data/spec/dummy/tmp/cache/3AC/F70/shard%2F11118 +0 -1
  507. data/spec/dummy/tmp/cache/3AC/F90/shard%2F10083 +0 -1
  508. data/spec/dummy/tmp/cache/3AC/F90/shard%2F11055 +0 -1
  509. data/spec/dummy/tmp/cache/3AC/FA0/shard%2F11064 +0 -1
  510. data/spec/dummy/tmp/cache/3AC/FA0/shard%2F11145 +0 -1
  511. data/spec/dummy/tmp/cache/3AC/FA0/shard%2F11226 +0 -1
  512. data/spec/dummy/tmp/cache/3AC/FA0/shard%2F11307 +0 -1
  513. data/spec/dummy/tmp/cache/3AC/FC0/shard%2F10272 +0 -1
  514. data/spec/dummy/tmp/cache/3AC/FD0/shard%2F11091 +0 -1
  515. data/spec/dummy/tmp/cache/3AC/FD0/shard%2F11172 +0 -1
  516. data/spec/dummy/tmp/cache/3AC/FD0/shard%2F11253 +0 -1
  517. data/spec/dummy/tmp/cache/3AC/FD0/shard%2F11415 +0 -1
  518. data/spec/dummy/tmp/cache/3AC/FF0/shard%2F10461 +0 -1
  519. data/spec/dummy/tmp/cache/3AC/FF0/shard%2F11514 +0 -1
  520. data/spec/dummy/tmp/cache/3AD/000/shard%2F10543 +0 -1
  521. data/spec/dummy/tmp/cache/3AD/010/shard%2F12253 +0 -1
  522. data/spec/dummy/tmp/cache/3AD/060/shard%2F11650 +0 -1
  523. data/spec/dummy/tmp/cache/3AD/F50/shard%2F10039 +0 -1
  524. data/spec/dummy/tmp/cache/3AD/F90/shard%2F10318 +0 -1
  525. data/spec/dummy/tmp/cache/3AD/FA0/shard%2F10246 +0 -1
  526. data/spec/dummy/tmp/cache/3AD/FC0/shard%2F10345 +0 -1
  527. data/spec/dummy/tmp/cache/3AE/030/shard%2F12344 +0 -1
  528. data/spec/dummy/tmp/cache/3AE/050/shard%2F10823 +0 -1
  529. data/spec/dummy/tmp/cache/3AE/060/shard%2F10751 +0 -1
  530. data/spec/dummy/tmp/cache/3AE/060/shard%2F11480 +0 -1
  531. data/spec/dummy/tmp/cache/3AE/090/shard%2F10940 +0 -1
  532. data/spec/dummy/tmp/cache/3AE/0B0/shard%2F12740 +0 -1
  533. data/spec/dummy/tmp/cache/3AE/FC0/shard%2F10175 +0 -1
  534. data/spec/dummy/tmp/cache/3AE/FD0/shard%2F11237 +0 -1
  535. data/spec/dummy/tmp/cache/3AE/FF0/shard%2F10364 +0 -1
  536. data/spec/dummy/tmp/cache/3AF/000/shard%2F12066 +0 -1
  537. data/spec/dummy/tmp/cache/3AF/000/shard%2F12147 +0 -1
  538. data/spec/dummy/tmp/cache/3AF/010/shard%2F11427 +0 -1
  539. data/spec/dummy/tmp/cache/3AF/020/shard%2F11193 +0 -1
  540. data/spec/dummy/tmp/cache/3AF/030/shard%2F10392 +0 -1
  541. data/spec/dummy/tmp/cache/3AF/030/shard%2F10635 +0 -1
  542. data/spec/dummy/tmp/cache/3AF/030/shard%2F11283 +0 -1
  543. data/spec/dummy/tmp/cache/3AF/030/shard%2F11526 +0 -1
  544. data/spec/dummy/tmp/cache/3AF/030/shard%2F12093 +0 -1
  545. data/spec/dummy/tmp/cache/3AF/030/shard%2F12174 +0 -1
  546. data/spec/dummy/tmp/cache/3AF/070/shard%2F12372 +0 -1
  547. data/spec/dummy/tmp/cache/3AF/080/shard%2F12624 +0 -1
  548. data/spec/dummy/tmp/cache/3AF/080/shard%2F13515 +0 -1
  549. data/spec/dummy/tmp/cache/3AF/090/shard%2F11823 +0 -1
  550. data/spec/dummy/tmp/cache/3AF/090/shard%2F11904 +0 -1
  551. data/spec/dummy/tmp/cache/3AF/0C0/shard%2F11850 +0 -1
  552. data/spec/dummy/tmp/cache/3AF/0C0/shard%2F11931 +0 -1
  553. data/spec/dummy/tmp/cache/3AF/0C0/shard%2F13551 +0 -1
  554. data/spec/dummy/tmp/cache/3AF/0F0/shard%2F13740 +0 -1
  555. data/spec/dummy/tmp/cache/3AF/FD0/shard%2F12039 +0 -1
  556. data/spec/dummy/tmp/cache/3B0/000/shard%2F10438 +0 -1
  557. data/spec/dummy/tmp/cache/3B0/040/shard%2F11365 +0 -1
  558. data/spec/dummy/tmp/cache/3B0/060/shard%2F11626 +0 -1
  559. data/spec/dummy/tmp/cache/3B0/060/shard%2F12436 +0 -1
  560. data/spec/dummy/tmp/cache/3B0/090/shard%2F10681 +0 -1
  561. data/spec/dummy/tmp/cache/3B0/090/shard%2F11491 +0 -1
  562. data/spec/dummy/tmp/cache/3B0/090/shard%2F11572 +0 -1
  563. data/spec/dummy/tmp/cache/3B0/0A0/shard%2F10771 +0 -1
  564. data/spec/dummy/tmp/cache/3B0/0C0/shard%2F12652 +0 -1
  565. data/spec/dummy/tmp/cache/3B0/FE0/shard%2F10177 +0 -1
  566. data/spec/dummy/tmp/cache/3B0/FE0/shard%2F11149 +0 -1
  567. data/spec/dummy/tmp/cache/3B0/FF0/shard%2F10267 +0 -1
  568. data/spec/dummy/tmp/cache/3B1/000/shard%2F11078 +0 -1
  569. data/spec/dummy/tmp/cache/3B1/030/shard%2F10295 +0 -1
  570. data/spec/dummy/tmp/cache/3B1/040/shard%2F10466 +0 -1
  571. data/spec/dummy/tmp/cache/3B1/070/shard%2F13328 +0 -1
  572. data/spec/dummy/tmp/cache/3B1/080/shard%2F10745 +0 -1
  573. data/spec/dummy/tmp/cache/3B1/080/shard%2F13094 +0 -1
  574. data/spec/dummy/tmp/cache/3B1/090/shard%2F10673 +0 -1
  575. data/spec/dummy/tmp/cache/3B1/090/shard%2F12293 +0 -1
  576. data/spec/dummy/tmp/cache/3B1/0B0/shard%2F11744 +0 -1
  577. data/spec/dummy/tmp/cache/3B1/0E0/shard%2F12824 +0 -1
  578. data/spec/dummy/tmp/cache/3B1/100/shard%2F12680 +0 -1
  579. data/spec/dummy/tmp/cache/3B1/100/shard%2F13571 +0 -1
  580. data/spec/dummy/tmp/cache/3B1/100/shard%2F13814 +0 -1
  581. data/spec/dummy/tmp/cache/3B2/060/shard%2F10719 +0 -1
  582. data/spec/dummy/tmp/cache/3B2/070/shard%2F10566 +0 -1
  583. data/spec/dummy/tmp/cache/3B2/070/shard%2F11538 +0 -1
  584. data/spec/dummy/tmp/cache/3B2/0A0/shard%2F10917 +0 -1
  585. data/spec/dummy/tmp/cache/3B2/0A0/shard%2F12456 +0 -1
  586. data/spec/dummy/tmp/cache/3B2/0D0/shard%2F11673 +0 -1
  587. data/spec/dummy/tmp/cache/3B2/0E0/shard%2F10953 +0 -1
  588. data/spec/dummy/tmp/cache/3B2/120/shard%2F12852 +0 -1
  589. data/spec/dummy/tmp/cache/3B2/150/shard%2F13851 +0 -1
  590. data/spec/dummy/tmp/cache/3B3/030/shard%2F10198 +0 -1
  591. data/spec/dummy/tmp/cache/3B3/040/shard%2F10369 +0 -1
  592. data/spec/dummy/tmp/cache/3B3/060/shard%2F10387 +0 -1
  593. data/spec/dummy/tmp/cache/3B3/0A0/shard%2F11719 +0 -1
  594. data/spec/dummy/tmp/cache/3B3/0C0/shard%2F10927 +0 -1
  595. data/spec/dummy/tmp/cache/3B3/0E0/shard%2F12484 +0 -1
  596. data/spec/dummy/tmp/cache/3B3/0E0/shard%2F13375 +0 -1
  597. data/spec/dummy/tmp/cache/3B3/0F0/shard%2F13627 +0 -1
  598. data/spec/dummy/tmp/cache/3B3/100/shard%2F10963 +0 -1
  599. data/spec/dummy/tmp/cache/3B3/100/shard%2F11692 +0 -1
  600. data/spec/dummy/tmp/cache/3B3/160/shard%2F12880 +0 -1
  601. data/spec/dummy/tmp/cache/3B4/090/shard%2F10487 +0 -1
  602. data/spec/dummy/tmp/cache/3B4/0A0/shard%2F11468 +0 -1
  603. data/spec/dummy/tmp/cache/3B4/0A0/shard%2F11549 +0 -1
  604. data/spec/dummy/tmp/cache/3B4/0D0/shard%2F11657 +0 -1
  605. data/spec/dummy/tmp/cache/3B4/0D0/shard%2F11738 +0 -1
  606. data/spec/dummy/tmp/cache/3B4/0D0/shard%2F12548 +0 -1
  607. data/spec/dummy/tmp/cache/3B4/0E0/shard%2F13286 +0 -1
  608. data/spec/dummy/tmp/cache/3B4/110/shard%2F12908 +0 -1
  609. data/spec/dummy/tmp/cache/3B4/130/shard%2F13655 +0 -1
  610. data/spec/dummy/tmp/cache/3B5/070/shard%2F10299 +0 -1
  611. data/spec/dummy/tmp/cache/3B5/080/shard%2F11199 +0 -1
  612. data/spec/dummy/tmp/cache/3B5/0B0/shard%2F10497 +0 -1
  613. data/spec/dummy/tmp/cache/3B5/0B0/shard%2F11388 +0 -1
  614. data/spec/dummy/tmp/cache/3B5/100/shard%2F11595 +0 -1
  615. data/spec/dummy/tmp/cache/3B5/110/shard%2F10875 +0 -1
  616. data/spec/dummy/tmp/cache/3B5/110/shard%2F12576 +0 -1
  617. data/spec/dummy/tmp/cache/3B5/150/shard%2F12936 +0 -1
  618. data/spec/dummy/tmp/cache/3B5/170/shard%2F13683 +0 -1
  619. data/spec/dummy/tmp/cache/3B6/0F0/shard%2F10849 +0 -1
  620. data/spec/dummy/tmp/cache/3B6/100/shard%2F10696 +0 -1
  621. data/spec/dummy/tmp/cache/3B6/110/shard%2F13459 +0 -1
  622. data/spec/dummy/tmp/cache/3B6/190/shard%2F12964 +0 -1
  623. data/spec/dummy/tmp/cache/3B7/0E0/shard%2F10589 +0 -1
  624. data/spec/dummy/tmp/cache/3B7/140/shard%2F11696 +0 -1
  625. data/spec/dummy/tmp/cache/3B7/150/shard%2F12596 +0 -1
  626. data/spec/dummy/tmp/cache/3B7/150/shard%2F13487 +0 -1
  627. data/spec/dummy/tmp/cache/3B8/140/shard%2F10797 +0 -1
  628. data/spec/dummy/tmp/cache/3B8/140/shard%2F11769 +0 -1
  629. data/spec/dummy/tmp/cache/3B8/170/shard%2F10986 +0 -1
  630. data/spec/dummy/tmp/cache/3B8/170/shard%2F11796 +0 -1
  631. data/spec/dummy/tmp/cache/3B8/170/shard%2F11877 +0 -1
  632. data/spec/dummy/tmp/cache/3B8/170/shard%2F11958 +0 -1
  633. data/spec/dummy/tmp/cache/3B8/170/shard%2F12768 +0 -1
  634. data/spec/dummy/tmp/cache/3B9/1B0/shard%2F12796 +0 -1
  635. data/spec/dummy/tmp/cache/3B9/1D0/shard%2F13786 +0 -1
  636. data/spec/dummy/tmp/cache/3BA/160/shard%2F10799 +0 -1
  637. data/spec/dummy/tmp/cache/3BA/180/shard%2F10979 +0 -1
  638. data/spec/dummy/tmp/cache/3BA/1C0/shard%2F11987 +0 -1
  639. data/spec/dummy/tmp/cache/3BB/1C0/shard%2F13599 +0 -1
  640. data/spec/dummy/tmp/cache/3BB/210/shard%2F13887 +0 -1
  641. data/spec/lib/action_controller/caching_spec.rb +0 -49
  642. data/spec/lib/active_record/abstract_adapter_spec.rb +0 -16
  643. data/spec/lib/active_record/association_spec.rb +0 -444
  644. data/spec/lib/active_record/attribute_methods_spec.rb +0 -122
  645. data/spec/lib/active_record/base_spec.rb +0 -130
  646. data/spec/lib/active_record/calculations_spec.rb +0 -282
  647. data/spec/lib/active_record/connection_handler_spec.rb +0 -45
  648. data/spec/lib/active_record/connection_pool_spec.rb +0 -83
  649. data/spec/lib/active_record/finder_methods_spec.rb +0 -58
  650. data/spec/lib/active_record/model_schema_spec.rb +0 -25
  651. data/spec/lib/active_record/persistence_spec.rb +0 -34
  652. data/spec/lib/active_record/postgresql_adapter_spec.rb +0 -40
  653. data/spec/lib/active_record/query_cache_spec.rb +0 -346
  654. data/spec/lib/active_record/query_methods_spec.rb +0 -166
  655. data/spec/lib/active_record/relation_spec.rb +0 -56
  656. data/spec/lib/active_record/spawn_methods_spec.rb +0 -44
  657. data/spec/lib/connection_pool_proxy_spec.rb +0 -45
  658. data/spec/lib/database_server_spec.rb +0 -231
  659. data/spec/lib/default_shard_spec.rb +0 -18
  660. data/spec/lib/engine_spec.rb +0 -14
  661. data/spec/lib/environment_spec.rb +0 -25
  662. data/spec/lib/r_spec_helper_spec.rb +0 -77
  663. data/spec/lib/rails_spec.rb +0 -31
  664. data/spec/lib/rake_spec.rb +0 -100
  665. data/spec/lib/shackles_spec.rb +0 -210
  666. data/spec/models/shard_spec.rb +0 -596
  667. data/spec/spec_helper.rb +0 -66
@@ -0,0 +1,658 @@
1
+ require 'switchman/database_server'
2
+ require 'switchman/default_shard'
3
+ require 'switchman/environment'
4
+
5
+ module Switchman
6
+ class Shard < ::ActiveRecord::Base
7
+ # ten trillion possible ids per shard. yup.
8
+ IDS_PER_SHARD = 10_000_000_000_000
9
+
10
+ CATEGORIES =
11
+ {
12
+ # special cased to mean all other models
13
+ :default => nil,
14
+ # special cased to not allow activating a shard other than the default
15
+ :unsharded => [Shard]
16
+ }
17
+ private_constant :CATEGORIES
18
+ @shard_category = :unsharded
19
+
20
+ if defined?(::ProtectedAttributes)
21
+ attr_accessible :default, :name, :database_server
22
+ end
23
+
24
+ # only allow one default
25
+ validates_uniqueness_of :default, :if => lambda { |s| s.default? }
26
+
27
+ after_save :clear_cache
28
+
29
+ scope :primary, -> { where(name: nil).order(:database_server_id, :id).distinct_on(:database_server_id) }
30
+
31
+ class << self
32
+ def categories
33
+ CATEGORIES.keys
34
+ end
35
+
36
+ def default(reload_deprecated = false, reload: false, with_fallback: false)
37
+ reload = reload_deprecated if reload_deprecated
38
+ if !@default || reload
39
+ # Have to create a dummy object so that several key methods still work
40
+ # (it's easier to do this in one place here, and just assume that sharding
41
+ # is up and running everywhere else). This includes for looking up the
42
+ # default shard itself. This also needs to be a local so that this method
43
+ # can be re-entrant
44
+ default = DefaultShard.instance
45
+
46
+ # if we already have a default shard in place, and the caller wants
47
+ # to use it as a fallback, use that instead of the dummy instance
48
+ if with_fallback && @default
49
+ default = @default
50
+ end
51
+
52
+ # the first time we need a dummy dummy for re-entrancy to avoid looping on ourselves
53
+ @default ||= default
54
+
55
+ # Now find the actual record, if it exists; rescue the fake default if the table doesn't exist
56
+ @default = begin
57
+ Shard.where(default: true).first || default
58
+ rescue
59
+ default
60
+ end
61
+
62
+ # rebuild current shard activations - it might have "another" default shard serialized there
63
+ active_shards.replace(active_shards.map do |category, shard|
64
+ shard = Shard.lookup((!shard || shard.default?) ? 'default' : shard.id)
65
+ [category, shard]
66
+ end.to_h)
67
+
68
+ activate!(default: @default) if active_shards.empty?
69
+ end
70
+ @default
71
+ end
72
+
73
+ def current(category = :default)
74
+ active_shards[category] || Shard.default
75
+ end
76
+
77
+ def activate(shards)
78
+ old_shards = activate!(shards)
79
+ yield
80
+ ensure
81
+ active_shards.merge!(old_shards) if old_shards
82
+ end
83
+
84
+ def activate!(shards)
85
+ old_shards = nil
86
+ currently_active_shards = active_shards
87
+ shards.each do |category, shard|
88
+ next if category == :unsharded
89
+ unless currently_active_shards[category] == shard
90
+ old_shards ||= {}
91
+ old_shards[category] = currently_active_shards[category]
92
+ currently_active_shards[category] = shard
93
+ end
94
+ end
95
+ old_shards
96
+ end
97
+
98
+ def lookup(id)
99
+ id_i = id.to_i
100
+ return current if id_i == current.id || id == 'self'
101
+ return default if id_i == default.id || id.nil? || id == 'default'
102
+ id = id_i
103
+ raise ArgumentError if id == 0
104
+
105
+ unless cached_shards.has_key?(id)
106
+ cached_shards[id] = Shard.default.activate do
107
+ # can't simply cache the AR object since Shard has a custom serializer
108
+ # that calls this method
109
+ attributes = Switchman.cache.fetch(['shard', id].join('/')) do
110
+ shard = find_by_id(id)
111
+ if shard
112
+ attributes = shard.attributes
113
+ if ::Rails.version < '4.2'
114
+ attributes.each_key do |key|
115
+ attributes[key] = attributes[key].unserialize if attributes[key].is_a?(::ActiveRecord::AttributeMethods::Serialization::Attribute)
116
+ end
117
+ end
118
+ attributes
119
+ else
120
+ :nil
121
+ end
122
+ end
123
+ if attributes == :nil
124
+ nil
125
+ else
126
+ shard = Shard.new
127
+ attributes.each do |attr, value|
128
+ shard.send(:"#{attr}=", value)
129
+ end
130
+ shard.instance_variable_set(:@new_record, false)
131
+ # connection info doesn't exist in database.yml;
132
+ # pretend the shard doesn't exist either
133
+ shard = nil unless shard.database_server
134
+ shard
135
+ end
136
+ end
137
+ end
138
+ cached_shards[id]
139
+ end
140
+
141
+ def clear_cache
142
+ cached_shards.clear
143
+ end
144
+
145
+ # ==== Parameters
146
+ #
147
+ # * +shards+ - an array or relation of Shards to iterate over
148
+ # * +categories+ - an array of categories to activate
149
+ # * +options+ -
150
+ # :parallel - true/false to execute in parallel, or a integer of how many
151
+ # sub-processes per database server. Note that parallel
152
+ # invocation currently uses forking, so should be used sparingly
153
+ # because errors are not raised, and you cannot get results back
154
+ # :exception - :ignore, :raise, :defer (wait until the end and raise the first
155
+ # error), or a proc
156
+ def with_each_shard(*args)
157
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 0...3)" if args.length > 3
158
+
159
+ unless default.is_a?(Shard)
160
+ return Array.wrap(yield)
161
+ end
162
+
163
+ options = args.extract_options!
164
+ if args.length == 1
165
+ if Array === args.first && args.first.first.is_a?(Symbol)
166
+ categories = args.first
167
+ else
168
+ scope = args.first
169
+ end
170
+ else
171
+ scope, categories = args
172
+ end
173
+
174
+ parallel = case options[:parallel]
175
+ when true
176
+ 1
177
+ when false, nil
178
+ 0
179
+ else
180
+ options[:parallel]
181
+ end
182
+ options.delete(:parallel)
183
+
184
+ scope ||= Shard.all
185
+ if ::ActiveRecord::Relation === scope && scope.order_values.empty?
186
+ scope = scope.order("database_server_id IS NOT NULL, database_server_id, id")
187
+ end
188
+
189
+ if parallel > 0
190
+ max_procs = determine_max_procs(options.delete(:max_procs), parallel)
191
+ if ::ActiveRecord::Relation === scope
192
+ # still need a post-uniq, cause the default database server could be NULL or Rails.env in the db
193
+ database_servers = scope.reorder('database_server_id').select(:database_server_id).uniq.
194
+ map(&:database_server).compact.uniq
195
+ parallel = [(max_procs.to_f / database_servers.count).ceil, parallel].min if max_procs
196
+
197
+ scopes = Hash[database_servers.map do |server|
198
+ server_scope = server.shards.merge(scope)
199
+ if parallel == 1
200
+ subscopes = [server_scope]
201
+ else
202
+ subscopes = []
203
+ total = server_scope.count
204
+ ranges = []
205
+ server_scope.find_ids_in_ranges(:batch_size => (total.to_f / parallel).ceil) do |min, max|
206
+ ranges << [min, max]
207
+ end
208
+ # create a half-open range on the last one
209
+ ranges.last[1] = nil
210
+ ranges.each do |min, max|
211
+ subscope = server_scope.where("id>=?", min)
212
+ subscope = subscope.where("id<=?", max) if max
213
+ subscopes << subscope
214
+ end
215
+ end
216
+ [server, subscopes]
217
+ end]
218
+ else
219
+ scopes = scope.group_by(&:database_server)
220
+ if parallel > 1
221
+ parallel = [(max_procs.to_f / scopes.count).ceil, parallel].min if max_procs
222
+ scopes = Hash[scopes.map do |(server, shards)|
223
+ [server, shards.in_groups(parallel, false).compact]
224
+ end]
225
+ end
226
+ end
227
+
228
+ fd_to_name_map = {}
229
+ out_fds = []
230
+ err_fds = []
231
+ pids = []
232
+
233
+ wait_for_output = lambda do |out_fds, err_fds, fd_to_name_map|
234
+ ready, _ = IO.select(out_fds + err_fds)
235
+ ready.each do |fd|
236
+ if fd.eof?
237
+ fd.close
238
+ out_fds.delete(fd)
239
+ err_fds.delete(fd)
240
+ next
241
+ end
242
+ line = fd.readline
243
+ puts "#{fd_to_name_map[fd]}: #{line}"
244
+ end
245
+ end
246
+
247
+ exception_pipe = IO.pipe
248
+ scopes.each do |server, subscopes|
249
+ if !(::ActiveRecord::Relation === subscopes.first) && subscopes.first.class != Array
250
+ subscopes = [subscopes]
251
+ end
252
+ # only one process; don't bother forking
253
+ if scopes.length == 1 && subscopes.length == 1
254
+ exception_pipe.first.close
255
+ exception_pipe.last.close
256
+ return with_each_shard(subscopes.first, categories, options) { yield }
257
+ end
258
+
259
+ subscopes.each_with_index do |subscope, idx|
260
+ if subscopes.length > 1
261
+ name = "#{server.id} #{idx + 1}"
262
+ else
263
+ name = server.id
264
+ end
265
+
266
+ details = Open4.pfork4(lambda do
267
+ begin
268
+ ::ActiveRecord::Base.clear_all_connections!
269
+ Switchman.config[:on_fork_proc].try(:call)
270
+ $0 = [$0, ARGV, name].flatten.join(' ')
271
+ with_each_shard(subscope, categories, options) { yield }
272
+ rescue Exception => e
273
+ exception_pipe.last.write(Marshal.dump(e))
274
+ exception_pipe.last.flush
275
+ exit 1
276
+ end
277
+ end)
278
+ # don't care about writing to stdin
279
+ details[1].close
280
+ out_fds << details[2]
281
+ err_fds << details[3]
282
+ pids << details[0]
283
+ fd_to_name_map[details[2]] = name
284
+ fd_to_name_map[details[3]] = name
285
+
286
+ while max_procs && pids.count >= max_procs
287
+ while max_procs && out_fds.count >= max_procs
288
+ # wait for output if we've hit the max_procs limit
289
+ wait_for_output.call(out_fds, err_fds, fd_to_name_map)
290
+ end
291
+ pids.delete(Process.wait) # we've gotten all the output from one fd so wait for its child process to exit
292
+ end
293
+ end
294
+ end
295
+
296
+ exception_pipe.last.close
297
+
298
+ while out_fds.any? || err_fds.any?
299
+ wait_for_output.call(out_fds, err_fds, fd_to_name_map)
300
+ end
301
+ pids.each { |pid| Process.waitpid2(pid) }
302
+
303
+ # I'm not sure why, but we have to do this
304
+ ::ActiveRecord::Base.clear_all_connections!
305
+ # check for an exception; we only re-raise the first one
306
+ # (all the sub-processes shared the same pipe, so we only
307
+ # have to check the one)
308
+ begin
309
+ exception = Marshal.load exception_pipe.first
310
+ raise exception
311
+ rescue EOFError
312
+ # No exceptions
313
+ ensure
314
+ exception_pipe.first.close
315
+ end
316
+ return
317
+ end
318
+
319
+ categories ||= []
320
+
321
+ previous_shard = nil
322
+ close_connections_if_needed = lambda do |shard|
323
+ # prune the prior connection unless it happened to be the same
324
+ if previous_shard && shard != previous_shard &&
325
+ (shard.database_server != previous_shard.database_server || !previous_shard.database_server.shareable?)
326
+ previous_shard.activate do
327
+ ::Shackles.activated_environments.each do |env|
328
+ ::Shackles.activate(env) do
329
+ if ::ActiveRecord::Base.connected? && ::ActiveRecord::Base.connection.open_transactions == 0
330
+ ::ActiveRecord::Base.connection_pool.current_pool.disconnect!
331
+ end
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
337
+
338
+ result = []
339
+ exception = nil
340
+ scope.each do |shard|
341
+ # shard references a database server that isn't configured in this environment
342
+ next unless shard.database_server
343
+ close_connections_if_needed.call(shard)
344
+ shard.activate(*categories) do
345
+ begin
346
+ result.concat Array.wrap(yield)
347
+ rescue
348
+ case options[:exception]
349
+ when :ignore
350
+ when :defer
351
+ exception ||= $!
352
+ when Proc
353
+ options[:exception].call
354
+ when :raise
355
+ raise
356
+ else
357
+ raise
358
+ end
359
+ end
360
+ end
361
+ previous_shard = shard
362
+ end
363
+ close_connections_if_needed.call(Shard.current)
364
+ raise exception if exception
365
+ result
366
+ end
367
+
368
+ def partition_by_shard(array, partition_proc = nil)
369
+ shard_arrays = {}
370
+ array.each do |object|
371
+ partition_object = partition_proc ? partition_proc.call(object) : object
372
+ case partition_object
373
+ when Shard
374
+ shard = partition_object
375
+ when ::ActiveRecord::Base
376
+ if partition_object.respond_to?(:associated_shards)
377
+ partition_object.associated_shards.each do |a_shard|
378
+ shard_arrays[a_shard] ||= []
379
+ shard_arrays[a_shard] << object
380
+ end
381
+ next
382
+ else
383
+ shard = partition_object.shard
384
+ end
385
+ when Integer, /^\d+$/, /^(\d+)~(\d+)$/
386
+ local_id, shard = Shard.local_id_for(partition_object)
387
+ local_id ||= partition_object
388
+ object = local_id if !partition_proc
389
+ end
390
+ shard ||= Shard.current
391
+ shard_arrays[shard] ||= []
392
+ shard_arrays[shard] << object
393
+ end
394
+ # TODO: use with_each_shard (or vice versa) to get
395
+ # connection management and parallelism benefits
396
+ shard_arrays.inject([]) do |results, (shard, objects)|
397
+ results.concat shard.activate { Array.wrap(yield objects) }
398
+ end
399
+ end
400
+
401
+ # converts an AR object, integral id, string id, or string short-global-id to a
402
+ # integral id. nil if it can't be interpreted
403
+ def integral_id_for(any_id)
404
+ if ::Rails.version >= '4.2' && any_id.is_a?(::Arel::Nodes::Casted)
405
+ any_id = any_id.val
406
+ end
407
+
408
+ case any_id
409
+ when ::ActiveRecord::Base
410
+ any_id.id
411
+ when /^(\d+)~(\d+)$/
412
+ local_id = $2.to_i
413
+ # doesn't make sense to have a double-global id
414
+ return nil if local_id > IDS_PER_SHARD
415
+ $1.to_i * IDS_PER_SHARD + local_id
416
+ when Integer, /^\d+$/
417
+ any_id.to_i
418
+ else
419
+ nil
420
+ end
421
+ end
422
+
423
+ # takes an id-ish, and returns a local id and the shard it's
424
+ # local to. [nil, nil] if it can't be interpreted. [id, nil]
425
+ # if it's already a local ID
426
+ NIL_NIL_ID = [nil, nil].freeze
427
+ def local_id_for(any_id)
428
+ id = integral_id_for(any_id)
429
+ return NIL_NIL_ID unless id
430
+ if id < IDS_PER_SHARD
431
+ [id, nil]
432
+ elsif shard = lookup(id / IDS_PER_SHARD)
433
+ [id % IDS_PER_SHARD, shard]
434
+ else
435
+ NIL_NIL_ID
436
+ end
437
+ end
438
+
439
+ # takes an id-ish, and returns an integral id relative to
440
+ # target_shard. returns any_id itself if it can't be interpreted
441
+ def relative_id_for(any_id, source_shard, target_shard)
442
+ local_id, shard = local_id_for(any_id)
443
+ return any_id unless local_id
444
+ shard ||= source_shard
445
+ return local_id if shard == target_shard
446
+ shard.global_id_for(local_id)
447
+ end
448
+
449
+ # takes an id-ish, and returns a shortened global
450
+ # string id if global, and itself if local.
451
+ # returns any_id itself if it can't be interpreted
452
+ def short_id_for(any_id)
453
+ local_id, shard = local_id_for(any_id)
454
+ return any_id unless local_id
455
+ return local_id unless shard
456
+ "#{shard.id}~#{local_id}"
457
+ end
458
+
459
+ # takes an id-ish, and returns an integral global id.
460
+ # returns nil if it can't be interpreted
461
+ def global_id_for(any_id, source_shard = nil)
462
+ id = integral_id_for(any_id)
463
+ return any_id unless id
464
+ if id >= IDS_PER_SHARD
465
+ id
466
+ else
467
+ source_shard ||= Shard.current
468
+ source_shard.global_id_for(id)
469
+ end
470
+ end
471
+
472
+ def shard_for(any_id, source_shard = nil)
473
+ _, shard = local_id_for(any_id)
474
+ shard || source_shard || Shard.current
475
+ end
476
+
477
+ # given the provided option, determines whether we need to (and whether
478
+ # it's possible) to determine a reasonable default.
479
+ def determine_max_procs(max_procs_input, parallel_input=2)
480
+ max_procs = nil
481
+ if max_procs_input
482
+ max_procs = max_procs_input.to_i
483
+ max_procs = nil if max_procs == 0
484
+ else
485
+ return 1 if parallel_input.nil? || parallel_input < 1
486
+ cpus = Environment.cpu_count
487
+ if cpus && cpus > 0
488
+ max_procs = cpus * parallel_input
489
+ end
490
+ end
491
+
492
+ return max_procs
493
+ end
494
+
495
+ private
496
+ # in-process caching
497
+ def cached_shards
498
+ @cached_shards ||= {}.compare_by_identity
499
+ end
500
+
501
+ def add_to_cache(shard)
502
+ cached_shards[shard.id] = shard
503
+ end
504
+
505
+ def remove_from_cache(shard)
506
+ cached_shards.delete(shard.id)
507
+ end
508
+
509
+ def active_shards
510
+ Thread.current[:active_shards] ||= {}.compare_by_identity
511
+ end
512
+ end
513
+
514
+ def name
515
+ unless instance_variable_defined?(:@name)
516
+ # protect against re-entrancy
517
+ @name = nil
518
+ @name = read_attribute(:name) || default_name
519
+ end
520
+ @name
521
+ end
522
+
523
+ def name=(name)
524
+ write_attribute(:name, @name = name)
525
+ remove_instance_variable(:@name) if name == nil
526
+ end
527
+
528
+ def database_server
529
+ @database_server ||= DatabaseServer.find(self.database_server_id)
530
+ end
531
+
532
+ def database_server=(database_server)
533
+ self.database_server_id = database_server.id
534
+ @database_server = database_server
535
+ end
536
+
537
+ def primary?
538
+ self == database_server.primary_shard
539
+ end
540
+
541
+ def description
542
+ [database_server.id, name].compact.join(':')
543
+ end
544
+
545
+ # Shards are always on the default shard
546
+ def shard
547
+ Shard.default
548
+ end
549
+
550
+ def activate(*categories)
551
+ shards = hashify_categories(categories)
552
+ Shard.activate(shards) do
553
+ yield
554
+ end
555
+ end
556
+
557
+ # for use from console ONLY
558
+ def activate!(*categories)
559
+ shards = hashify_categories(categories)
560
+ Shard.activate!(shards)
561
+ nil
562
+ end
563
+
564
+ # custom serialization, since shard is self-referential
565
+ def _dump(depth)
566
+ self.id.to_s
567
+ end
568
+
569
+ def self._load(str)
570
+ lookup(str.to_i)
571
+ end
572
+
573
+ def drop_database
574
+ raise("Cannot drop the database of the default shard") if self.default?
575
+ return unless read_attribute(:name)
576
+
577
+ begin
578
+ adapter = self.database_server.config[:adapter]
579
+ sharding_config = Switchman.config || {}
580
+ drop_statement = sharding_config[adapter].try(:[], :drop_statement)
581
+ drop_statement ||= sharding_config[:drop_statement]
582
+ if drop_statement
583
+ drop_statement = Array(drop_statement).dup.
584
+ map { |statement| statement.gsub('%{name}', self.name) }
585
+ end
586
+
587
+ case adapter
588
+ when 'mysql', 'mysql2'
589
+ self.activate do
590
+ ::Shackles.activate(:deploy) do
591
+ drop_statement ||= "DROP DATABASE #{self.name}"
592
+ Array(drop_statement).each do |stmt|
593
+ ::ActiveRecord::Base.connection.execute(stmt)
594
+ end
595
+ end
596
+ end
597
+ when 'postgresql'
598
+ self.activate do
599
+ ::Shackles.activate(:deploy) do
600
+ # Shut up, Postgres!
601
+ conn = ::ActiveRecord::Base.connection
602
+ old_proc = conn.raw_connection.set_notice_processor {}
603
+ begin
604
+ drop_statement ||= "DROP SCHEMA #{self.name} CASCADE"
605
+ Array(drop_statement).each do |stmt|
606
+ ::ActiveRecord::Base.connection.execute(stmt)
607
+ end
608
+ ensure
609
+ conn.raw_connection.set_notice_processor(&old_proc) if old_proc
610
+ end
611
+ end
612
+ end
613
+ when 'sqlite3'
614
+ File.delete(self.name) unless self.name == ':memory:'
615
+ end
616
+ rescue
617
+ logger.info "Drop failed: #{$!}"
618
+ end
619
+ end
620
+
621
+ # takes an id local to this shard, and returns a global id
622
+ def global_id_for(local_id)
623
+ return nil unless local_id
624
+ local_id + self.id * IDS_PER_SHARD
625
+ end
626
+
627
+ # skip global_id.hash
628
+ def hash
629
+ id.hash
630
+ end
631
+
632
+ def destroy
633
+ raise("Cannot destroy the default shard") if self.default?
634
+ super
635
+ end
636
+
637
+ private
638
+
639
+ def clear_cache
640
+ Shard.default.activate do
641
+ Switchman.cache.delete(['shard', id].join('/'))
642
+ end
643
+ end
644
+
645
+ def default_name
646
+ database_server.shard_name(self)
647
+ end
648
+
649
+ def hashify_categories(categories)
650
+ if categories.empty?
651
+ { :default => self }
652
+ else
653
+ categories.inject({}) { |h, category| h[category] = self; h }
654
+ end
655
+ end
656
+
657
+ end
658
+ end
@@ -1,5 +1,4 @@
1
1
  require 'switchman/connection_pool_proxy'
2
- require 'switchman/shard'
3
2
 
4
3
  module Switchman
5
4
  module ActiveRecord
@@ -58,9 +58,6 @@ module Switchman
58
58
  # cache map, but between now and then, Rails.cache should return the
59
59
  # Rails.env entry in the cache map.
60
60
  ::Rails.cache = Switchman.config[:cache_map][::Rails.env]
61
-
62
- require "switchman/rails"
63
- ::Rails.singleton_class.prepend(Rails::ClassMethods)
64
61
  end
65
62
 
66
63
  initializer 'switchman.extend_ar', :before => "active_record.initialize_database" do
@@ -85,7 +82,9 @@ module Switchman
85
82
  require "switchman/active_record/where_clause_factory"
86
83
  require "switchman/active_record/type_caster"
87
84
  require "switchman/arel"
85
+ require "switchman/rails"
88
86
  require "switchman/shackles/relation"
87
+ require "switchman/shard_internal"
89
88
 
90
89
  include ActiveRecord::Base
91
90
  include ActiveRecord::AttributeMethods
@@ -99,6 +98,9 @@ module Switchman
99
98
  ::ActiveRecord::StatementCache::Substitute.send(:attr_accessor, :primary, :sharded)
100
99
 
101
100
  ::ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecord::CollectionAssociation)
101
+ end
102
+
103
+ if ::Rails.version >= '4.1.15'
102
104
  ::ActiveRecord::PredicateBuilder.singleton_class.prepend(ActiveRecord::PredicateBuilder)
103
105
  end
104
106
 
@@ -140,6 +142,8 @@ module Switchman
140
142
  ::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
141
143
  end
142
144
 
145
+ ::Rails.singleton_class.prepend(Rails::ClassMethods)
146
+
143
147
  ::Arel::Table.prepend(Arel::Table)
144
148
  ::Arel::Visitors::ToSql.prepend(Arel::Visitors::ToSql)
145
149
  ::Arel::Visitors::PostgreSQL.include(Arel::Visitors::PostgreSQL) if ::Rails.version < '4.2'
@@ -1,3 +1,3 @@
1
1
  module Switchman
2
- VERSION = "1.5.0"
2
+ VERSION = "1.5.3"
3
3
  end