moneta 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (446) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rspec +4 -0
  4. data/.travis.yml +83 -32
  5. data/.yardopts +6 -1
  6. data/CHANGES +30 -0
  7. data/CONTRIBUTORS +4 -0
  8. data/Gemfile +28 -36
  9. data/LICENSE +1 -1
  10. data/README.md +136 -67
  11. data/SPEC.md +70 -0
  12. data/feature_matrix.yaml +235 -0
  13. data/lib/active_support/cache/moneta_store.rb +102 -6
  14. data/lib/moneta.rb +9 -2
  15. data/lib/moneta/adapters/activerecord.rb +258 -98
  16. data/lib/moneta/adapters/activesupportcache.rb +133 -0
  17. data/lib/moneta/adapters/cassandra.rb +290 -44
  18. data/lib/moneta/adapters/client.rb +11 -2
  19. data/lib/moneta/adapters/couch.rb +179 -25
  20. data/lib/moneta/adapters/datamapper.rb +1 -0
  21. data/lib/moneta/adapters/daybreak.rb +21 -4
  22. data/lib/moneta/adapters/dbm.rb +7 -7
  23. data/lib/moneta/adapters/file.rb +11 -1
  24. data/lib/moneta/adapters/gdbm.rb +7 -7
  25. data/lib/moneta/adapters/kyotocabinet.rb +66 -1
  26. data/lib/moneta/adapters/leveldb.rb +27 -1
  27. data/lib/moneta/adapters/lmdb.rb +29 -1
  28. data/lib/moneta/adapters/lruhash.rb +30 -0
  29. data/lib/moneta/adapters/memcached/dalli.rb +50 -5
  30. data/lib/moneta/adapters/memcached/native.rb +11 -4
  31. data/lib/moneta/adapters/memory.rb +2 -0
  32. data/lib/moneta/adapters/mongo/base.rb +32 -7
  33. data/lib/moneta/adapters/mongo/moped.rb +59 -2
  34. data/lib/moneta/adapters/mongo/official.rb +40 -0
  35. data/lib/moneta/adapters/pstore.rb +56 -8
  36. data/lib/moneta/adapters/redis.rb +79 -19
  37. data/lib/moneta/adapters/sdbm.rb +7 -7
  38. data/lib/moneta/adapters/sequel.rb +440 -39
  39. data/lib/moneta/adapters/sqlite.rb +74 -10
  40. data/lib/moneta/adapters/tdb.rb +16 -1
  41. data/lib/moneta/adapters/tokyocabinet.rb +7 -1
  42. data/lib/moneta/adapters/tokyotyrant.rb +22 -0
  43. data/lib/moneta/cache.rb +11 -1
  44. data/lib/moneta/expires.rb +110 -8
  45. data/lib/moneta/lock.rb +21 -2
  46. data/lib/moneta/mixins.rb +279 -3
  47. data/lib/moneta/pool.rb +15 -6
  48. data/lib/moneta/proxy.rb +46 -2
  49. data/lib/moneta/server.rb +5 -1
  50. data/lib/moneta/shared.rb +27 -11
  51. data/lib/moneta/stack.rb +1 -1
  52. data/lib/moneta/synchronize.rb +2 -8
  53. data/lib/moneta/transformer.rb +152 -2
  54. data/lib/moneta/transformer/config.rb +2 -0
  55. data/lib/moneta/transformer/helper.rb +2 -2
  56. data/lib/moneta/version.rb +1 -1
  57. data/lib/moneta/weak_each_key.rb +74 -0
  58. data/lib/moneta/wrapper.rb +25 -0
  59. data/moneta.gemspec +2 -2
  60. data/script/benchmarks +174 -62
  61. data/script/parallel-tests +58 -83
  62. data/script/start-hbase +46 -0
  63. data/script/start-services +9 -2
  64. data/script/update-feature-matrix +148 -0
  65. data/spec/active_support/cache_moneta_store_spec.rb +132 -109
  66. data/spec/features/concurrent_create.rb +21 -0
  67. data/spec/features/concurrent_increment.rb +32 -0
  68. data/spec/features/create.rb +25 -0
  69. data/spec/features/create_expires.rb +19 -0
  70. data/spec/features/default_expires.rb +15 -0
  71. data/spec/features/each_key.rb +119 -0
  72. data/spec/features/expires.rb +291 -0
  73. data/spec/features/features.rb +16 -0
  74. data/spec/features/increment.rb +98 -0
  75. data/spec/features/marshallable_key.rb +43 -0
  76. data/spec/features/marshallable_value.rb +7 -0
  77. data/spec/features/multiprocess.rb +8 -0
  78. data/spec/features/not_create.rb +7 -0
  79. data/spec/features/not_each_key.rb +7 -0
  80. data/spec/features/not_increment.rb +13 -0
  81. data/spec/features/not_persist.rb +9 -0
  82. data/spec/features/null.rb +66 -0
  83. data/spec/features/persist.rb +14 -0
  84. data/spec/features/returndifferent.rb +9 -0
  85. data/spec/features/returnsame.rb +9 -0
  86. data/spec/features/store.rb +261 -0
  87. data/spec/features/store_large.rb +13 -0
  88. data/spec/features/transform_value.rb +44 -0
  89. data/spec/features/transform_value_expires.rb +41 -0
  90. data/spec/helper.rb +391 -74
  91. data/spec/moneta/adapters/activerecord/adapter_activerecord_existing_connection_spec.rb +59 -0
  92. data/spec/moneta/adapters/activerecord/adapter_activerecord_spec.rb +118 -0
  93. data/spec/moneta/adapters/activerecord/standard_activerecord_spec.rb +18 -0
  94. data/spec/moneta/adapters/activerecord/standard_activerecord_with_expires_spec.rb +24 -0
  95. data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_spec.rb +51 -0
  96. data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_with_default_expires_spec.rb +51 -0
  97. data/spec/moneta/adapters/cassandra/adapter_cassandra_spec.rb +17 -0
  98. data/spec/moneta/adapters/cassandra/adapter_cassandra_with_default_expires_spec.rb +18 -0
  99. data/spec/moneta/adapters/cassandra/helper.rb +18 -0
  100. data/spec/moneta/adapters/cassandra/standard_cassandra_spec.rb +18 -0
  101. data/spec/moneta/adapters/client/adapter_client_spec.rb +11 -0
  102. data/spec/moneta/adapters/client/standard_client_tcp_spec.rb +23 -0
  103. data/spec/moneta/adapters/client/standard_client_unix_spec.rb +12 -0
  104. data/spec/moneta/adapters/cookie/adapter_cookie_spec.rb +7 -0
  105. data/spec/moneta/adapters/couch/adapter_couch_spec.rb +7 -0
  106. data/spec/moneta/adapters/couch/standard_couch_spec.rb +9 -0
  107. data/spec/moneta/adapters/couch/standard_couch_with_expires_spec.rb +13 -0
  108. data/spec/moneta/adapters/datamapper/adapter_datamapper_spec.rb +43 -0
  109. data/spec/moneta/adapters/datamapper/standard_datamapper_spec.rb +21 -0
  110. data/spec/moneta/adapters/datamapper/standard_datamapper_with_expires_spec.rb +26 -0
  111. data/spec/moneta/adapters/datamapper/standard_datamapper_with_repository_spec.rb +22 -0
  112. data/spec/moneta/adapters/daybreak/adapter_daybreak_spec.rb +7 -0
  113. data/spec/moneta/adapters/daybreak/standard_daybreak_spec.rb +7 -0
  114. data/spec/moneta/adapters/daybreak/standard_daybreak_with_expires_spec.rb +11 -0
  115. data/spec/moneta/adapters/dbm/adapter_dbm_spec.rb +7 -0
  116. data/spec/moneta/adapters/dbm/standard_dbm_spec.rb +7 -0
  117. data/spec/moneta/adapters/dbm/standard_dbm_with_expires_spec.rb +12 -0
  118. data/spec/moneta/adapters/file/adapter_file_spec.rb +7 -0
  119. data/spec/moneta/adapters/file/standard_file_spec.rb +7 -0
  120. data/spec/moneta/adapters/file/standard_file_with_expires_spec.rb +11 -0
  121. data/spec/moneta/adapters/fog/adapter_fog_spec.rb +16 -0
  122. data/spec/moneta/adapters/fog/standard_fog_spec.rb +15 -0
  123. data/spec/moneta/adapters/fog/standard_fog_with_expires_spec.rb +20 -0
  124. data/spec/moneta/adapters/gdbm/adapter_gdbm_spec.rb +7 -0
  125. data/spec/moneta/adapters/gdbm/standard_gdbm_spec.rb +7 -0
  126. data/spec/moneta/adapters/gdbm/standard_gdbm_with_expires_spec.rb +11 -0
  127. data/spec/moneta/adapters/hashfile/standard_hashfile_spec.rb +7 -0
  128. data/spec/moneta/adapters/hashfile/standard_hashfile_with_expires_spec.rb +12 -0
  129. data/spec/moneta/adapters/hbase/adapter_hbase_spec.rb +7 -0
  130. data/spec/moneta/adapters/hbase/standard_hbase_spec.rb +4 -0
  131. data/spec/moneta/adapters/hbase/standard_hbase_with_expires_spec.rb +8 -0
  132. data/spec/moneta/adapters/kyotocabinet/adapter_kyotocabinet_spec.rb +7 -0
  133. data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_spec.rb +7 -0
  134. data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_with_expires_spec.rb +14 -0
  135. data/spec/moneta/adapters/leveldb/adapter_leveldb_spec.rb +7 -0
  136. data/spec/moneta/adapters/leveldb/standard_leveldb_spec.rb +7 -0
  137. data/spec/moneta/adapters/leveldb/standard_leveldb_with_expires_spec.rb +11 -0
  138. data/spec/moneta/adapters/lmdb/adapter_lmdb_spec.rb +7 -0
  139. data/spec/moneta/adapters/lmdb/adapter_lmdb_with_db_spec.rb +7 -0
  140. data/spec/moneta/adapters/lmdb/standard_lmdb_spec.rb +7 -0
  141. data/spec/moneta/adapters/lmdb/standard_lmdb_with_expires_spec.rb +11 -0
  142. data/spec/moneta/adapters/localmemcache/adapter_localmemcache_spec.rb +7 -0
  143. data/spec/moneta/adapters/localmemcache/standard_localmemcache_spec.rb +7 -0
  144. data/spec/moneta/adapters/localmemcache/standard_localmemcache_with_expires_spec.rb +11 -0
  145. data/spec/moneta/{adapter_lruhash_spec.rb → adapters/lruhash/adapter_lruhash_spec.rb} +3 -25
  146. data/spec/moneta/adapters/lruhash/standard_lruhash_spec.rb +4 -0
  147. data/spec/moneta/adapters/lruhash/standard_lruhash_with_expires_spec.rb +8 -0
  148. data/spec/moneta/adapters/memcached/adapter_memcached_spec.rb +13 -0
  149. data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_spec.rb +15 -0
  150. data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_with_default_expires_spec.rb +15 -0
  151. data/spec/moneta/adapters/memcached/dalli/standard_memcached_dalli_spec.rb +11 -0
  152. data/spec/moneta/adapters/memcached/helper.rb +20 -0
  153. data/spec/moneta/adapters/memcached/native/adapter_memcached_native_spec.rb +15 -0
  154. data/spec/moneta/adapters/memcached/native/adapter_memcached_native_with_default_expires_spec.rb +15 -0
  155. data/spec/moneta/adapters/memcached/native/standard_memcached_native_spec.rb +11 -0
  156. data/spec/moneta/adapters/memcached/standard_memcached_spec.rb +17 -0
  157. data/spec/moneta/adapters/memory/adapter_memory_spec.rb +7 -0
  158. data/spec/moneta/adapters/memory/standard_memory_spec.rb +4 -0
  159. data/spec/moneta/adapters/memory/standard_memory_with_compress_spec.rb +9 -0
  160. data/spec/moneta/adapters/memory/standard_memory_with_expires_spec.rb +8 -0
  161. data/spec/moneta/adapters/memory/standard_memory_with_json_key_serializer_spec.rb +4 -0
  162. data/spec/moneta/adapters/memory/standard_memory_with_json_serializer_spec.rb +9 -0
  163. data/spec/moneta/adapters/memory/standard_memory_with_json_value_serializer_spec.rb +9 -0
  164. data/spec/moneta/adapters/memory/standard_memory_with_prefix_spec.rb +4 -0
  165. data/spec/moneta/adapters/memory/standard_memory_with_snappy_compress_spec.rb +9 -0
  166. data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +25 -0
  167. data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +12 -0
  168. data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +25 -0
  169. data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +12 -0
  170. data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +11 -0
  171. data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +12 -0
  172. data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +7 -0
  173. data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +7 -0
  174. data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +7 -0
  175. data/spec/moneta/adapters/null/null_adapter_spec.rb +7 -0
  176. data/spec/moneta/adapters/null/standard_null_spec.rb +4 -0
  177. data/spec/moneta/adapters/pstore/adapter_pstore_spec.rb +7 -0
  178. data/spec/moneta/adapters/pstore/standard_pstore_spec.rb +9 -0
  179. data/spec/moneta/adapters/pstore/standard_pstore_with_expires_spec.rb +13 -0
  180. data/spec/moneta/adapters/redis/adapter_redis_spec.rb +10 -0
  181. data/spec/moneta/adapters/redis/adapter_redis_with_default_expires_spec.rb +10 -0
  182. data/spec/moneta/adapters/redis/standard_redis_spec.rb +7 -0
  183. data/spec/moneta/adapters/restclient/adapter_restclient_spec.rb +11 -0
  184. data/spec/moneta/adapters/restclient/standard_restclient_spec.rb +10 -0
  185. data/spec/moneta/adapters/riak/adapter_riak_spec.rb +14 -0
  186. data/spec/moneta/adapters/riak/standard_riak_spec.rb +10 -0
  187. data/spec/moneta/adapters/riak/standard_riak_with_expires_spec.rb +10 -0
  188. data/spec/moneta/adapters/sdbm/adapter_sdbm_spec.rb +7 -0
  189. data/spec/moneta/adapters/sdbm/standard_sdbm_spec.rb +7 -0
  190. data/spec/moneta/adapters/sdbm/standard_sdbm_with_expires_spec.rb +11 -0
  191. data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +181 -0
  192. data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +14 -0
  193. data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +19 -0
  194. data/spec/moneta/adapters/sqlite/adapter_sqlite_spec.rb +7 -0
  195. data/spec/moneta/adapters/sqlite/standard_sqlite_spec.rb +7 -0
  196. data/spec/moneta/adapters/sqlite/standard_sqlite_with_expires_spec.rb +15 -0
  197. data/spec/moneta/adapters/tdb/adapter_tdb_spec.rb +7 -0
  198. data/spec/moneta/adapters/tdb/standard_tdb_spec.rb +7 -0
  199. data/spec/moneta/adapters/tdb/standard_tdb_with_expires_spec.rb +11 -0
  200. data/spec/moneta/adapters/tokyocabinet/adapter_tokyocabinet_bdb_spec.rb +7 -0
  201. data/spec/moneta/adapters/tokyocabinet/adapter_tokyocabinet_hdb_spec.rb +7 -0
  202. data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_spec.rb +7 -0
  203. data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_with_expires_spec.rb +11 -0
  204. data/spec/moneta/adapters/tokyotyrant/adapter_tokyotyrant_spec.rb +7 -0
  205. data/spec/moneta/adapters/tokyotyrant/standard_tokyotyrant_spec.rb +4 -0
  206. data/spec/moneta/adapters/tokyotyrant/standard_tokyotyrant_with_expires_spec.rb +8 -0
  207. data/spec/moneta/adapters/yaml/adapter_yaml_spec.rb +7 -0
  208. data/spec/moneta/adapters/yaml/standard_yaml_spec.rb +9 -0
  209. data/spec/moneta/adapters/yaml/standard_yaml_with_expires_spec.rb +13 -0
  210. data/spec/moneta/builder_spec.rb +0 -1
  211. data/spec/moneta/mutex_spec.rb +6 -23
  212. data/spec/moneta/proxies/cache/cache_file_memory_spec.rb +24 -0
  213. data/spec/moneta/proxies/cache/cache_memory_null_spec.rb +12 -0
  214. data/spec/moneta/proxies/expires/expires_file_spec.rb +28 -0
  215. data/spec/moneta/proxies/expires/expires_memory_spec.rb +15 -0
  216. data/spec/moneta/proxies/expires/expires_memory_with_default_expires_spec.rb +16 -0
  217. data/spec/moneta/proxies/lock/lock_spec.rb +10 -0
  218. data/spec/moneta/{optionmerger_spec.rb → proxies/optionmerger/optionmerger_spec.rb} +2 -18
  219. data/spec/moneta/proxies/pool/pool_spec.rb +12 -0
  220. data/spec/moneta/proxies/proxy/proxy_expires_memory_spec.rb +16 -0
  221. data/spec/moneta/proxies/proxy/proxy_redis_spec.rb +13 -0
  222. data/spec/moneta/proxies/shared/shared_tcp_spec.rb +49 -0
  223. data/spec/moneta/proxies/shared/shared_unix_spec.rb +48 -0
  224. data/spec/moneta/proxies/transformer/transformer_bencode_spec.rb +19 -0
  225. data/spec/moneta/proxies/transformer/transformer_bert_spec.rb +19 -0
  226. data/spec/moneta/proxies/transformer/transformer_bson_spec.rb +23 -0
  227. data/spec/moneta/proxies/transformer/transformer_bzip2_spec.rb +19 -0
  228. data/spec/moneta/proxies/transformer/transformer_json_spec.rb +19 -0
  229. data/spec/moneta/proxies/transformer/transformer_key_inspect_spec.rb +17 -0
  230. data/spec/moneta/proxies/transformer/transformer_key_marshal_spec.rb +17 -0
  231. data/spec/moneta/proxies/transformer/transformer_key_to_s_spec.rb +17 -0
  232. data/spec/moneta/proxies/transformer/transformer_key_yaml_spec.rb +17 -0
  233. data/spec/moneta/proxies/transformer/transformer_lz4_spec.rb +19 -0
  234. data/spec/moneta/proxies/transformer/transformer_lzma_spec.rb +19 -0
  235. data/spec/moneta/proxies/transformer/transformer_lzo_spec.rb +19 -0
  236. data/spec/moneta/proxies/transformer/transformer_marshal_base64_spec.rb +20 -0
  237. data/spec/moneta/proxies/transformer/transformer_marshal_city128_spec.rb +15 -0
  238. data/spec/moneta/proxies/transformer/transformer_marshal_city32_spec.rb +15 -0
  239. data/spec/moneta/proxies/transformer/transformer_marshal_city64_spec.rb +15 -0
  240. data/spec/moneta/proxies/transformer/transformer_marshal_escape_spec.rb +15 -0
  241. data/spec/moneta/proxies/transformer/transformer_marshal_hex_spec.rb +20 -0
  242. data/spec/moneta/proxies/transformer/transformer_marshal_hmac_spec.rb +19 -0
  243. data/spec/moneta/proxies/transformer/transformer_marshal_md5_spec.rb +15 -0
  244. data/spec/moneta/proxies/transformer/transformer_marshal_md5_spread_spec.rb +15 -0
  245. data/spec/moneta/proxies/transformer/transformer_marshal_prefix_spec.rb +15 -0
  246. data/spec/moneta/proxies/transformer/transformer_marshal_qp_spec.rb +20 -0
  247. data/spec/moneta/proxies/transformer/transformer_marshal_rmd160_spec.rb +15 -0
  248. data/spec/moneta/proxies/transformer/transformer_marshal_sha1_spec.rb +15 -0
  249. data/spec/moneta/proxies/transformer/transformer_marshal_sha256_spec.rb +15 -0
  250. data/spec/moneta/proxies/transformer/transformer_marshal_sha384_spec.rb +15 -0
  251. data/spec/moneta/proxies/transformer/transformer_marshal_sha512_spec.rb +15 -0
  252. data/spec/moneta/proxies/transformer/transformer_marshal_spec.rb +19 -0
  253. data/spec/moneta/proxies/transformer/transformer_marshal_truncate_spec.rb +15 -0
  254. data/spec/moneta/proxies/transformer/transformer_marshal_urlsafe_base64_spec.rb +20 -0
  255. data/spec/moneta/proxies/transformer/transformer_marshal_uuencode_spec.rb +19 -0
  256. data/spec/moneta/proxies/transformer/transformer_msgpack_spec.rb +19 -0
  257. data/spec/moneta/proxies/transformer/transformer_ox_spec.rb +19 -0
  258. data/spec/moneta/proxies/transformer/transformer_php_spec.rb +19 -0
  259. data/spec/moneta/proxies/transformer/transformer_quicklz_spec.rb +19 -0
  260. data/spec/moneta/proxies/transformer/transformer_snappy_spec.rb +19 -0
  261. data/spec/moneta/proxies/transformer/transformer_tnet_spec.rb +19 -0
  262. data/spec/moneta/proxies/transformer/transformer_value_marshal_spec.rb +19 -0
  263. data/spec/moneta/proxies/transformer/transformer_value_yaml_spec.rb +19 -0
  264. data/spec/moneta/proxies/transformer/transformer_yaml_spec.rb +19 -0
  265. data/spec/moneta/proxies/transformer/transformer_zlib_spec.rb +19 -0
  266. data/spec/moneta/proxies/weak_create/weak_create_spec.rb +21 -0
  267. data/spec/moneta/proxies/weak_each_key/weak_each_key_spec.rb +24 -0
  268. data/spec/moneta/proxies/weak_increment/weak_increment_spec.rb +21 -0
  269. data/spec/moneta/semaphore_spec.rb +6 -23
  270. data/spec/moneta/stack_file_memory_spec.rb +5 -29
  271. data/spec/moneta/stack_memory_file_spec.rb +5 -31
  272. data/spec/quality_spec.rb +1 -1
  273. data/{spec → test}/action_dispatch/fixtures/session_autoload_test/foo.rb +0 -0
  274. data/{spec/action_dispatch/session_moneta_store_spec.rb → test/action_dispatch/session_moneta_store_test.rb} +13 -5
  275. metadata +415 -355
  276. data/script/generate-specs +0 -2696
  277. data/spec/moneta/adapter_activerecord_exisiting_connection_spec.rb +0 -36
  278. data/spec/moneta/adapter_activerecord_spec.rb +0 -65
  279. data/spec/moneta/adapter_cassandra_spec.rb +0 -33
  280. data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +0 -34
  281. data/spec/moneta/adapter_client_spec.rb +0 -35
  282. data/spec/moneta/adapter_cookie_spec.rb +0 -30
  283. data/spec/moneta/adapter_couch_spec.rb +0 -36
  284. data/spec/moneta/adapter_datamapper_spec.rb +0 -64
  285. data/spec/moneta/adapter_daybreak_spec.rb +0 -31
  286. data/spec/moneta/adapter_dbm_spec.rb +0 -31
  287. data/spec/moneta/adapter_file_spec.rb +0 -34
  288. data/spec/moneta/adapter_fog_spec.rb +0 -37
  289. data/spec/moneta/adapter_gdbm_spec.rb +0 -31
  290. data/spec/moneta/adapter_hbase_spec.rb +0 -33
  291. data/spec/moneta/adapter_kyotocabinet_spec.rb +0 -31
  292. data/spec/moneta/adapter_leveldb_spec.rb +0 -31
  293. data/spec/moneta/adapter_lmdb_spec.rb +0 -32
  294. data/spec/moneta/adapter_lmdb_with_db_spec.rb +0 -32
  295. data/spec/moneta/adapter_localmemcache_spec.rb +0 -32
  296. data/spec/moneta/adapter_memcached_dalli_spec.rb +0 -36
  297. data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +0 -37
  298. data/spec/moneta/adapter_memcached_native_spec.rb +0 -36
  299. data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +0 -37
  300. data/spec/moneta/adapter_memcached_spec.rb +0 -36
  301. data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +0 -37
  302. data/spec/moneta/adapter_memory_spec.rb +0 -184
  303. data/spec/moneta/adapter_mongo_moped_spec.rb +0 -64
  304. data/spec/moneta/adapter_mongo_moped_with_default_expires_spec.rb +0 -53
  305. data/spec/moneta/adapter_mongo_official_spec.rb +0 -64
  306. data/spec/moneta/adapter_mongo_official_with_default_expires_spec.rb +0 -53
  307. data/spec/moneta/adapter_mongo_spec.rb +0 -51
  308. data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +0 -53
  309. data/spec/moneta/adapter_pstore_spec.rb +0 -250
  310. data/spec/moneta/adapter_redis_spec.rb +0 -36
  311. data/spec/moneta/adapter_redis_with_default_expires_spec.rb +0 -37
  312. data/spec/moneta/adapter_restclient_spec.rb +0 -33
  313. data/spec/moneta/adapter_riak_spec.rb +0 -36
  314. data/spec/moneta/adapter_sdbm_spec.rb +0 -30
  315. data/spec/moneta/adapter_sequel_spec.rb +0 -34
  316. data/spec/moneta/adapter_sqlite_spec.rb +0 -32
  317. data/spec/moneta/adapter_tdb_spec.rb +0 -31
  318. data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +0 -31
  319. data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +0 -31
  320. data/spec/moneta/adapter_tokyotyrant_spec.rb +0 -34
  321. data/spec/moneta/adapter_yaml_spec.rb +0 -57
  322. data/spec/moneta/cache_file_memory_spec.rb +0 -50
  323. data/spec/moneta/cache_memory_null_spec.rb +0 -35
  324. data/spec/moneta/expires_file_spec.rb +0 -78
  325. data/spec/moneta/expires_memory_spec.rb +0 -189
  326. data/spec/moneta/expires_memory_with_default_expires_spec.rb +0 -190
  327. data/spec/moneta/lock_spec.rb +0 -187
  328. data/spec/moneta/null_adapter_spec.rb +0 -86
  329. data/spec/moneta/pool_spec.rb +0 -38
  330. data/spec/moneta/proxy_expires_memory_spec.rb +0 -191
  331. data/spec/moneta/proxy_redis_spec.rb +0 -40
  332. data/spec/moneta/shared_tcp_spec.rb +0 -46
  333. data/spec/moneta/shared_unix_spec.rb +0 -46
  334. data/spec/moneta/standard_activerecord_spec.rb +0 -253
  335. data/spec/moneta/standard_activerecord_with_expires_spec.rb +0 -255
  336. data/spec/moneta/standard_cassandra_spec.rb +0 -252
  337. data/spec/moneta/standard_client_tcp_spec.rb +0 -269
  338. data/spec/moneta/standard_client_unix_spec.rb +0 -254
  339. data/spec/moneta/standard_couch_spec.rb +0 -252
  340. data/spec/moneta/standard_couch_with_expires_spec.rb +0 -254
  341. data/spec/moneta/standard_datamapper_spec.rb +0 -254
  342. data/spec/moneta/standard_datamapper_with_expires_spec.rb +0 -256
  343. data/spec/moneta/standard_datamapper_with_repository_spec.rb +0 -254
  344. data/spec/moneta/standard_daybreak_spec.rb +0 -250
  345. data/spec/moneta/standard_daybreak_with_expires_spec.rb +0 -252
  346. data/spec/moneta/standard_dbm_spec.rb +0 -250
  347. data/spec/moneta/standard_dbm_with_expires_spec.rb +0 -252
  348. data/spec/moneta/standard_file_spec.rb +0 -253
  349. data/spec/moneta/standard_file_with_expires_spec.rb +0 -255
  350. data/spec/moneta/standard_fog_spec.rb +0 -256
  351. data/spec/moneta/standard_fog_with_expires_spec.rb +0 -258
  352. data/spec/moneta/standard_gdbm_spec.rb +0 -250
  353. data/spec/moneta/standard_gdbm_with_expires_spec.rb +0 -252
  354. data/spec/moneta/standard_hashfile_spec.rb +0 -253
  355. data/spec/moneta/standard_hashfile_with_expires_spec.rb +0 -255
  356. data/spec/moneta/standard_hbase_spec.rb +0 -252
  357. data/spec/moneta/standard_hbase_with_expires_spec.rb +0 -255
  358. data/spec/moneta/standard_kyotocabinet_spec.rb +0 -250
  359. data/spec/moneta/standard_kyotocabinet_with_expires_spec.rb +0 -252
  360. data/spec/moneta/standard_leveldb_spec.rb +0 -250
  361. data/spec/moneta/standard_leveldb_with_expires_spec.rb +0 -252
  362. data/spec/moneta/standard_lmdb_spec.rb +0 -251
  363. data/spec/moneta/standard_lmdb_with_expires_spec.rb +0 -253
  364. data/spec/moneta/standard_localmemcache_spec.rb +0 -251
  365. data/spec/moneta/standard_localmemcache_with_expires_spec.rb +0 -252
  366. data/spec/moneta/standard_lruhash_spec.rb +0 -187
  367. data/spec/moneta/standard_lruhash_with_expires_spec.rb +0 -189
  368. data/spec/moneta/standard_memcached_dalli_spec.rb +0 -255
  369. data/spec/moneta/standard_memcached_native_spec.rb +0 -255
  370. data/spec/moneta/standard_memcached_spec.rb +0 -255
  371. data/spec/moneta/standard_memory_spec.rb +0 -187
  372. data/spec/moneta/standard_memory_with_compress_spec.rb +0 -187
  373. data/spec/moneta/standard_memory_with_expires_spec.rb +0 -189
  374. data/spec/moneta/standard_memory_with_json_key_serializer_spec.rb +0 -86
  375. data/spec/moneta/standard_memory_with_json_serializer_spec.rb +0 -49
  376. data/spec/moneta/standard_memory_with_json_value_serializer_spec.rb +0 -90
  377. data/spec/moneta/standard_memory_with_prefix_spec.rb +0 -187
  378. data/spec/moneta/standard_memory_with_snappy_compress_spec.rb +0 -187
  379. data/spec/moneta/standard_mongo_moped_spec.rb +0 -255
  380. data/spec/moneta/standard_mongo_official_spec.rb +0 -255
  381. data/spec/moneta/standard_mongo_spec.rb +0 -255
  382. data/spec/moneta/standard_null_spec.rb +0 -120
  383. data/spec/moneta/standard_pstore_spec.rb +0 -253
  384. data/spec/moneta/standard_pstore_with_expires_spec.rb +0 -255
  385. data/spec/moneta/standard_redis_spec.rb +0 -255
  386. data/spec/moneta/standard_restclient_spec.rb +0 -252
  387. data/spec/moneta/standard_riak_spec.rb +0 -255
  388. data/spec/moneta/standard_riak_with_expires_spec.rb +0 -256
  389. data/spec/moneta/standard_sdbm_spec.rb +0 -249
  390. data/spec/moneta/standard_sdbm_with_expires_spec.rb +0 -251
  391. data/spec/moneta/standard_sequel_spec.rb +0 -253
  392. data/spec/moneta/standard_sequel_with_expires_spec.rb +0 -255
  393. data/spec/moneta/standard_sqlite_spec.rb +0 -251
  394. data/spec/moneta/standard_sqlite_with_expires_spec.rb +0 -253
  395. data/spec/moneta/standard_tdb_spec.rb +0 -250
  396. data/spec/moneta/standard_tdb_with_expires_spec.rb +0 -252
  397. data/spec/moneta/standard_tokyocabinet_spec.rb +0 -250
  398. data/spec/moneta/standard_tokyocabinet_with_expires_spec.rb +0 -252
  399. data/spec/moneta/standard_tokyotyrant_spec.rb +0 -253
  400. data/spec/moneta/standard_tokyotyrant_with_expires_spec.rb +0 -255
  401. data/spec/moneta/standard_yaml_spec.rb +0 -250
  402. data/spec/moneta/standard_yaml_with_expires_spec.rb +0 -252
  403. data/spec/moneta/transformer_bencode_spec.rb +0 -55
  404. data/spec/moneta/transformer_bert_spec.rb +0 -55
  405. data/spec/moneta/transformer_bson_spec.rb +0 -60
  406. data/spec/moneta/transformer_bzip2_spec.rb +0 -55
  407. data/spec/moneta/transformer_json_spec.rb +0 -55
  408. data/spec/moneta/transformer_key_inspect_spec.rb +0 -91
  409. data/spec/moneta/transformer_key_marshal_spec.rb +0 -191
  410. data/spec/moneta/transformer_key_to_s_spec.rb +0 -91
  411. data/spec/moneta/transformer_key_yaml_spec.rb +0 -191
  412. data/spec/moneta/transformer_lz4_spec.rb +0 -55
  413. data/spec/moneta/transformer_lzma_spec.rb +0 -55
  414. data/spec/moneta/transformer_lzo_spec.rb +0 -55
  415. data/spec/moneta/transformer_marshal_base64_spec.rb +0 -194
  416. data/spec/moneta/transformer_marshal_city128_spec.rb +0 -194
  417. data/spec/moneta/transformer_marshal_city32_spec.rb +0 -194
  418. data/spec/moneta/transformer_marshal_city64_spec.rb +0 -194
  419. data/spec/moneta/transformer_marshal_escape_spec.rb +0 -194
  420. data/spec/moneta/transformer_marshal_hex_spec.rb +0 -194
  421. data/spec/moneta/transformer_marshal_hmac_spec.rb +0 -194
  422. data/spec/moneta/transformer_marshal_md5_spec.rb +0 -194
  423. data/spec/moneta/transformer_marshal_md5_spread_spec.rb +0 -194
  424. data/spec/moneta/transformer_marshal_prefix_spec.rb +0 -194
  425. data/spec/moneta/transformer_marshal_qp_spec.rb +0 -194
  426. data/spec/moneta/transformer_marshal_rmd160_spec.rb +0 -194
  427. data/spec/moneta/transformer_marshal_sha1_spec.rb +0 -194
  428. data/spec/moneta/transformer_marshal_sha256_spec.rb +0 -194
  429. data/spec/moneta/transformer_marshal_sha384_spec.rb +0 -194
  430. data/spec/moneta/transformer_marshal_sha512_spec.rb +0 -194
  431. data/spec/moneta/transformer_marshal_spec.rb +0 -191
  432. data/spec/moneta/transformer_marshal_truncate_spec.rb +0 -194
  433. data/spec/moneta/transformer_marshal_uuencode_spec.rb +0 -194
  434. data/spec/moneta/transformer_msgpack_spec.rb +0 -55
  435. data/spec/moneta/transformer_ox_spec.rb +0 -191
  436. data/spec/moneta/transformer_php_spec.rb +0 -55
  437. data/spec/moneta/transformer_quicklz_spec.rb +0 -55
  438. data/spec/moneta/transformer_snappy_spec.rb +0 -55
  439. data/spec/moneta/transformer_tnet_spec.rb +0 -55
  440. data/spec/moneta/transformer_value_marshal_spec.rb +0 -191
  441. data/spec/moneta/transformer_value_yaml_spec.rb +0 -191
  442. data/spec/moneta/transformer_yaml_spec.rb +0 -191
  443. data/spec/moneta/transformer_zlib_spec.rb +0 -55
  444. data/spec/moneta/weak_create_spec.rb +0 -41
  445. data/spec/moneta/weak_increment_spec.rb +0 -41
  446. data/spec/monetaspecs.rb +0 -51267
@@ -7,8 +7,9 @@ module Moneta
7
7
  # @api public
8
8
  class PStore
9
9
  include Defaults
10
+ include NilValues
10
11
 
11
- supports :create, :increment
12
+ supports :create, :increment, :each_key
12
13
  attr_reader :backend
13
14
 
14
15
  # @param [Hash] options
@@ -21,31 +22,43 @@ module Moneta
21
22
  FileUtils.mkpath(::File.dirname(options[:file]))
22
23
  new_store(options)
23
24
  end
25
+
26
+ @id = "Moneta::Adapters::PStore(#{object_id})"
24
27
  end
25
28
 
26
29
  # (see Proxy#key?)
27
30
  def key?(key, options = {})
28
- @backend.transaction(true) { @backend.root?(key) }
31
+ transaction(true) { @backend.root?(key) }
32
+ end
33
+
34
+ # (see Proxy#each_key)
35
+ def each_key(&block)
36
+ return enum_for(:each_key) { transaction(true) { @backend.roots.size } } unless block_given?
37
+
38
+ transaction(true) do
39
+ @backend.roots.each { |k| yield(k) }
40
+ end
41
+ self
29
42
  end
30
43
 
31
44
  # (see Proxy#load)
32
45
  def load(key, options = {})
33
- @backend.transaction(true) { @backend[key] }
46
+ transaction(true) { @backend[key] }
34
47
  end
35
48
 
36
49
  # (see Proxy#store)
37
50
  def store(key, value, options = {})
38
- @backend.transaction { @backend[key] = value }
51
+ transaction {@backend[key] = value }
39
52
  end
40
53
 
41
54
  # (see Proxy#delete)
42
55
  def delete(key, options = {})
43
- @backend.transaction { @backend.delete(key) }
56
+ transaction { @backend.delete(key) }
44
57
  end
45
58
 
46
59
  # (see Proxy#increment)
47
60
  def increment(key, amount = 1, options = {})
48
- @backend.transaction do
61
+ transaction do
49
62
  value = Utils.to_int(@backend[key]) + amount
50
63
  @backend[key] = value.to_s
51
64
  value
@@ -54,7 +67,7 @@ module Moneta
54
67
 
55
68
  # (see Proxy#create)
56
69
  def create(key, value, options = {})
57
- @backend.transaction do
70
+ transaction do
58
71
  if @backend.root?(key)
59
72
  false
60
73
  else
@@ -66,7 +79,7 @@ module Moneta
66
79
 
67
80
  # (see Proxy#clear)
68
81
  def clear(options = {})
69
- @backend.transaction do
82
+ transaction do
70
83
  @backend.roots.each do |key|
71
84
  @backend.delete(key)
72
85
  end
@@ -74,11 +87,46 @@ module Moneta
74
87
  self
75
88
  end
76
89
 
90
+ # (see Proxy#values_at)
91
+ def values_at(*keys, **options)
92
+ transaction(true) { super }
93
+ end
94
+
95
+ def fetch_values(*keys, **options)
96
+ transaction(true) { super }
97
+ end
98
+
99
+ def slice(*keys, **options)
100
+ transaction(true) { super }
101
+ end
102
+
103
+ def merge!(pairs, options = {})
104
+ transaction { super }
105
+ end
106
+
77
107
  protected
78
108
 
109
+ class TransactionError < StandardError; end
110
+
79
111
  def new_store(options)
80
112
  ::PStore.new(options[:file], options[:threadsafe])
81
113
  end
114
+
115
+ def transaction(read_only = false)
116
+ case Thread.current[@id]
117
+ when read_only, false
118
+ yield
119
+ when true
120
+ raise TransactionError, "Attempt to start read-write transaction inside a read-only transaction"
121
+ else
122
+ begin
123
+ Thread.current[@id] = read_only
124
+ @backend.transaction(read_only) { yield }
125
+ ensure
126
+ Thread.current[@id] = nil
127
+ end
128
+ end
129
+ end
82
130
  end
83
131
  end
84
132
  end
@@ -8,7 +8,7 @@ module Moneta
8
8
  include Defaults
9
9
  include ExpiresSupport
10
10
 
11
- supports :create, :increment
11
+ supports :create, :increment, :each_key
12
12
  attr_reader :backend
13
13
 
14
14
  # @param [Hash] options
@@ -25,25 +25,31 @@ module Moneta
25
25
  # This method considers false and 0 as "no-expire" and every positive
26
26
  # number as a time to live in seconds.
27
27
  def key?(key, options = {})
28
- if @backend.exists(key)
29
- update_expires(key, options, nil)
30
- true
31
- else
32
- false
28
+ with_expiry_update(key, default: nil, **options) do
29
+ @backend.exists(key)
33
30
  end
34
31
  end
35
32
 
33
+ # (see Proxy#each_key)
34
+ def each_key(&block)
35
+ return enum_for(:each_key) unless block_given?
36
+
37
+ @backend.scan_each { |k| yield(k) }
38
+ self
39
+ end
40
+
36
41
  # (see Proxy#load)
37
42
  def load(key, options = {})
38
- value = @backend.get(key)
39
- update_expires(key, options, nil)
40
- value
43
+ with_expiry_update(key, default: nil, **options) do
44
+ @backend.get(key)
45
+ end
41
46
  end
42
47
 
43
48
  # (see Proxy#store)
44
49
  def store(key, value, options = {})
45
50
  if expires = expires_value(options)
46
- @backend.setex(key, expires, value)
51
+ Numeric === expires and expires = (expires * 1000).to_i
52
+ @backend.psetex(key, expires, value)
47
53
  else
48
54
  @backend.set(key, value)
49
55
  end
@@ -52,17 +58,19 @@ module Moneta
52
58
 
53
59
  # (see Proxy#delete)
54
60
  def delete(key, options = {})
55
- if value = load(key, options)
61
+ future = nil
62
+ @backend.pipelined do
63
+ future = @backend.get(key)
56
64
  @backend.del(key)
57
- value
58
65
  end
66
+ future.value
59
67
  end
60
68
 
61
69
  # (see Proxy#increment)
62
70
  def increment(key, amount = 1, options = {})
63
- value = @backend.incrby(key, amount)
64
- update_expires(key, options)
65
- value
71
+ with_expiry_update(key, **options) do
72
+ @backend.incrby(key, amount)
73
+ end
66
74
  end
67
75
 
68
76
  # (see Proxy#clear)
@@ -73,8 +81,10 @@ module Moneta
73
81
 
74
82
  # (see Defaults#create)
75
83
  def create(key, value, options = {})
84
+ expires = expires_value(options, @default_expires)
85
+
76
86
  if @backend.setnx(key, value)
77
- update_expires(key, options)
87
+ update_expires(key, expires)
78
88
  true
79
89
  else
80
90
  false
@@ -87,14 +97,64 @@ module Moneta
87
97
  nil
88
98
  end
89
99
 
100
+ # (see Defaults#values_at)
101
+ def values_at(*keys, **options)
102
+ with_expiry_update(*keys, default: nil, **options) do
103
+ @backend.mget *keys
104
+ end
105
+ end
106
+
107
+ # (see Defaults#merge!)
108
+ def merge!(pairs, options = {})
109
+ keys = pairs.map { |key, _| key }
110
+
111
+ if block_given?
112
+ old_values = @backend.mget(*keys)
113
+ updates = pairs.each_with_index.with_object({}) do |(pair, i), updates|
114
+ old_value = old_values[i]
115
+ if !old_value.nil?
116
+ key, new_value = pair
117
+ updates[key] = yield(key, old_value, new_value)
118
+ end
119
+ end
120
+ unless updates.empty?
121
+ pairs = if pairs.respond_to?(:merge)
122
+ pairs.merge(updates)
123
+ else
124
+ Hash[pairs.to_a].merge!(updates)
125
+ end
126
+ end
127
+ end
128
+
129
+ with_expiry_update(*keys, **options) do
130
+ @backend.mset(*pairs.to_a.flatten(1))
131
+ end
132
+
133
+ self
134
+ end
135
+
90
136
  protected
91
137
 
92
- def update_expires(key, options, default = @default_expires)
93
- case expires = expires_value(options, default)
138
+ def update_expires(key, expires)
139
+ case expires
94
140
  when false
95
141
  @backend.persist(key)
96
142
  when Numeric
97
- @backend.expire(key, expires)
143
+ @backend.pexpire(key, (expires * 1000).to_i)
144
+ end
145
+ end
146
+
147
+ def with_expiry_update(*keys, default: @default_expires, **options)
148
+ expires = expires_value(options, default)
149
+ if expires.nil?
150
+ yield
151
+ else
152
+ future = nil
153
+ @backend.multi do
154
+ future = yield
155
+ keys.each { |key| update_expires(key, expires) }
156
+ end
157
+ future.value
98
158
  end
99
159
  end
100
160
  end
@@ -4,7 +4,13 @@ module Moneta
4
4
  module Adapters
5
5
  # SDBM backend
6
6
  # @api public
7
- class SDBM < Memory
7
+ class SDBM
8
+ include Defaults
9
+ include DBMAdapter
10
+ include IncrementSupport
11
+ include CreateSupport
12
+ include EachKeySupport
13
+
8
14
  # @param [Hash] options
9
15
  # @option options [String] :file Database file
10
16
  # @option options [::SDBM] :backend Use existing backend instance
@@ -15,12 +21,6 @@ module Moneta
15
21
  ::SDBM.new(options[:file])
16
22
  end
17
23
  end
18
-
19
- # (see Proxy#close)
20
- def close
21
- @backend.close
22
- nil
23
- end
24
24
  end
25
25
  end
26
26
  end
@@ -11,54 +11,100 @@ module Moneta
11
11
  # older versions raise a Sequel::DatabaseError.
12
12
  UniqueConstraintViolation = defined?(::Sequel::UniqueConstraintViolation) ? ::Sequel::UniqueConstraintViolation : ::Sequel::DatabaseError
13
13
 
14
- supports :create, :increment
15
- attr_reader :backend
14
+ supports :create, :increment, :each_key
15
+ attr_reader :backend, :key_column, :value_column
16
16
 
17
17
  # @param [Hash] options
18
18
  # @option options [String] :db Sequel database
19
- # @option options [String/Symbol] :table (:moneta) Table name
19
+ # @option options [String, Symbol] :table (:moneta) Table name
20
20
  # @option options [Array] :extensions ([]) List of Sequel extensions
21
21
  # @option options [Integer] :connection_validation_timeout (nil) Sequel connection_validation_timeout
22
+ # @option options [Sequel::Database] :backend Use existing backend instance
23
+ # @option options [Boolean] :optimize (true) Set to false to prevent database-specific optimisations
24
+ # @option options [Proc, Boolean] :create_table Provide a Proc for creating the table, or
25
+ # set to false to disable table creation all together. If a Proc is given, it will be
26
+ # called regardless of whether the table exists already.
27
+ # @option options [Symbol] :key_column (:k) The name of the key column
28
+ # @option options [Symbol] :value_column (:v) The name of the value column
29
+ # @option options [String] :hstore If using Postgres, keys and values are stored in a single
30
+ # row of the table in the value_column using the hstore format. The row to use is
31
+ # the one where the value_column is equal to the value of this option, and will be created
32
+ # if it doesn't exist.
22
33
  # @option options All other options passed to `Sequel#connect`
23
- # @option options [Sequel connection] :backend Use existing backend instance
24
- def initialize(options = {})
25
- table = (options.delete(:table) || :moneta).to_sym
26
- extensions = options.delete(:extensions) || []
27
- raise ArgumentError, 'Option :extensions must be an Array' unless extensions.is_a?(Array)
34
+ def self.new(options = {})
35
+ extensions = options.delete(:extensions)
28
36
  connection_validation_timeout = options.delete(:connection_validation_timeout)
29
- @backend = options[:backend] ||
37
+ optimize = options.delete(:optimize)
38
+ backend = options.delete(:backend) ||
30
39
  begin
31
40
  raise ArgumentError, 'Option :db is required' unless db = options.delete(:db)
32
- ::Sequel.connect(db, options)
41
+ other_cols = [:table, :create_table, :key_column, :value_column, :hstore]
42
+ ::Sequel.connect(db, options.reject { |k,_| other_cols.member?(k) }).tap do |backend|
43
+ if extensions
44
+ raise ArgumentError, 'Option :extensions must be an Array' unless extensions.is_a?(Array)
45
+ extensions.map(&:to_sym).each(&backend.method(:extension))
46
+ end
47
+
48
+ if connection_validation_timeout
49
+ backend.pool.connection_validation_timeout = connection_validation_timeout
50
+ end
51
+ end
33
52
  end
34
- extensions.each do |extension|
35
- @backend.extension(extension.to_sym)
36
- end
37
- @backend.pool.connection_validation_timeout = connection_validation_timeout if connection_validation_timeout
38
- @backend.create_table?(table) do
39
- String :k, null: false, primary_key: true
40
- File :v
53
+
54
+ instance =
55
+ if optimize.nil? || optimize
56
+ case backend.database_type
57
+ when :mysql
58
+ MySQL.allocate
59
+ when :postgres
60
+ if options[:hstore]
61
+ PostgresHStore.allocate
62
+ elsif matches = backend.get(::Sequel[:version].function).match(/PostgreSQL (\d+)\.(\d+)/)
63
+ # Our optimisations only work on Postgres 9.5+
64
+ major, minor = matches[1..2].map(&:to_i)
65
+ Postgres.allocate if major > 9 || (major == 9 && minor >= 5)
66
+ end
67
+ when :sqlite
68
+ SQLite.allocate
69
+ end
70
+ end || allocate
71
+
72
+ instance.instance_variable_set(:@backend, backend)
73
+ instance.send(:initialize, options)
74
+ instance
75
+ end
76
+
77
+ # @api private
78
+ def initialize(options)
79
+ @table_name = (options.delete(:table) || :moneta).to_sym
80
+ @key_column = options.delete(:key_column) || :k
81
+ @value_column = options.delete(:value_column) || :v
82
+
83
+ create_proc = options.delete(:create_table)
84
+ if create_proc.nil?
85
+ create_table
86
+ elsif create_proc
87
+ create_proc.call(@backend)
41
88
  end
42
- @table = @backend[table]
89
+
90
+ @table = @backend[@table_name]
43
91
  end
44
92
 
45
93
  # (see Proxy#key?)
46
94
  def key?(key, options = {})
47
- @table[k: key] != nil
95
+ !@table.where(key_column => key).empty?
48
96
  end
49
97
 
50
98
  # (see Proxy#load)
51
99
  def load(key, options = {})
52
- record = @table[k: key]
53
- record && record[:v]
100
+ @table.where(key_column => key).get(value_column)
54
101
  end
55
102
 
56
103
  # (see Proxy#store)
57
104
  def store(key, value, options = {})
58
- begin
59
- @table.insert(k: key, v: blob(value))
60
- rescue UniqueConstraintViolation
61
- @table.where(k: key).update(v: blob(value))
105
+ blob_value = blob(value)
106
+ unless @table.where(key_column => key).update(value_column => blob_value) == 1
107
+ @table.insert(key_column => key, value_column => blob_value)
62
108
  end
63
109
  value
64
110
  rescue ::Sequel::DatabaseError
@@ -68,7 +114,7 @@ module Moneta
68
114
 
69
115
  # (see Proxy#store)
70
116
  def create(key, value, options = {})
71
- @table.insert(k: key, v: blob(value))
117
+ @table.insert(key_column => key, value_column => blob(value))
72
118
  true
73
119
  rescue UniqueConstraintViolation
74
120
  false
@@ -77,15 +123,15 @@ module Moneta
77
123
  # (see Proxy#increment)
78
124
  def increment(key, amount = 1, options = {})
79
125
  @backend.transaction do
80
- locked_table = @table.for_update
81
- if record = locked_table[k: key]
82
- value = Utils.to_int(record[:v]) + amount
83
- locked_table.where(k: key).update(v: blob(value.to_s))
84
- value
126
+ if existing = @table.where(key_column => key).for_update.get(value_column)
127
+ amount += Integer(existing)
128
+ raise IncrementError, "no update" unless @table.
129
+ where(key_column => key, value_column => existing).
130
+ update(value_column => blob(amount.to_s)) == 1
85
131
  else
86
- locked_table.insert(k: key, v: blob(amount.to_s))
87
- amount
132
+ @table.insert(key_column => key, value_column => blob(amount.to_s))
88
133
  end
134
+ amount
89
135
  end
90
136
  rescue ::Sequel::DatabaseError
91
137
  # Concurrent modification might throw a bunch of different errors
@@ -95,10 +141,9 @@ module Moneta
95
141
 
96
142
  # (see Proxy#delete)
97
143
  def delete(key, options = {})
98
- if value = load(key, options)
99
- @table.filter(k: key).delete
100
- value
101
- end
144
+ value = load(key, options)
145
+ @table.filter(key_column => key).delete
146
+ value
102
147
  end
103
148
 
104
149
  # (see Proxy#clear)
@@ -113,11 +158,367 @@ module Moneta
113
158
  nil
114
159
  end
115
160
 
116
- private
161
+ # (see Proxy#slice)
162
+ def slice(*keys, **options)
163
+ @table.filter(key_column => keys).as_hash(key_column, value_column)
164
+ end
165
+
166
+ # (see Proxy#values_at)
167
+ def values_at(*keys, **options)
168
+ pairs = slice(*keys, **options)
169
+ keys.map { |key| pairs[key] }
170
+ end
171
+
172
+ # (see Proxy#fetch_values)
173
+ def fetch_values(*keys, **options)
174
+ return values_at(*keys, **options) unless block_given?
175
+ existing = slice(*keys, **options)
176
+ keys.map do |key|
177
+ if existing.key? key
178
+ existing[key]
179
+ else
180
+ yield key
181
+ end
182
+ end
183
+ end
184
+
185
+ # (see Proxy#merge!)
186
+ def merge!(pairs, options = {})
187
+ @backend.transaction do
188
+ existing = existing_for_update(pairs)
189
+ update_pairs, insert_pairs = pairs.partition { |k, _| existing.key?(k) }
190
+ @table.import([key_column, value_column], blob_pairs(insert_pairs))
191
+
192
+ if block_given?
193
+ update_pairs.map! do |key, new_value|
194
+ [key, yield(key, existing[key], new_value)]
195
+ end
196
+ end
197
+
198
+ update_pairs.each do |key, value|
199
+ @table.filter(key_column => key).update(value_column => blob(value))
200
+ end
201
+ end
202
+
203
+ self
204
+ end
205
+
206
+ # (see Proxy#each_key)
207
+ def each_key
208
+ return enum_for(:each_key) { @table.count } unless block_given?
209
+ @table.select(key_column).each do |row|
210
+ yield row[key_column]
211
+ end
212
+ self
213
+ end
214
+
215
+ protected
117
216
 
118
217
  # See https://github.com/jeremyevans/sequel/issues/715
119
218
  def blob(s)
120
- s.empty? ? '' : ::Sequel.blob(s)
219
+ if s == nil
220
+ nil
221
+ elsif s.empty?
222
+ ''
223
+ else
224
+ ::Sequel.blob(s)
225
+ end
226
+ end
227
+
228
+ def blob_pairs(pairs)
229
+ pairs.map do |key, value|
230
+ [key, blob(value)]
231
+ end
232
+ end
233
+
234
+ def create_table
235
+ key_column = self.key_column
236
+ value_column = self.value_column
237
+ @backend.create_table?(@table_name) do
238
+ String key_column, null: false, primary_key: true
239
+ File value_column
240
+ end
241
+ end
242
+
243
+ def existing_for_update(pairs)
244
+ @table.
245
+ filter(key_column => pairs.map { |k, _| k }.to_a).
246
+ for_update.
247
+ as_hash(key_column, value_column)
248
+ end
249
+
250
+ def yield_merge_pairs(pairs)
251
+ existing = existing_for_update(pairs)
252
+ pairs.map do |key, new_value|
253
+ new_value = yield(key, existing[key], new_value) if existing.key?(key)
254
+ [key, new_value]
255
+ end
256
+ end
257
+
258
+ # @api private
259
+ class IncrementError < ::Sequel::DatabaseError; end
260
+
261
+ # @api private
262
+ class MySQL < Sequel
263
+ def store(key, value, options = {})
264
+ @table.
265
+ on_duplicate_key_update.
266
+ insert(key_column => key, value_column => blob(value))
267
+ value
268
+ end
269
+
270
+ def increment(key, amount = 1, options = {})
271
+ @backend.transaction do
272
+ # this creates a row-level lock even if there is no existing row (a
273
+ # "gap lock").
274
+ if existing = @table.where(key_column => key).for_update.get(value_column)
275
+ # Integer() will raise an exception if the existing value cannot be parsed
276
+ amount += Integer(existing)
277
+ @table.where(key_column => key).update(value_column => amount)
278
+ else
279
+ @table.insert(key_column => key, value_column => amount)
280
+ end
281
+ amount
282
+ end
283
+ rescue ::Sequel::SerializationFailure # Thrown on deadlock
284
+ tries ||= 0
285
+ (tries += 1) <= 3 ? retry : raise
286
+ end
287
+
288
+ def merge!(pairs, options = {}, &block)
289
+ @backend.transaction do
290
+ pairs = yield_merge_pairs(pairs, &block) if block_given?
291
+ @table.
292
+ on_duplicate_key_update.
293
+ import([key_column, value_column], blob_pairs(pairs).to_a)
294
+ end
295
+
296
+ self
297
+ end
298
+ end
299
+
300
+ # @api private
301
+ class Postgres < Sequel
302
+ def store(key, value, options = {})
303
+ @table.
304
+ insert_conflict(
305
+ target: key_column,
306
+ update: {value_column => ::Sequel[:excluded][value_column]}).
307
+ insert(key_column => key, value_column => blob(value))
308
+ value
309
+ end
310
+
311
+ def increment(key, amount = 1, options = {})
312
+ update_expr = ::Sequel[:convert_to].function(
313
+ (::Sequel[:convert_from].function(
314
+ ::Sequel[@table_name][value_column],
315
+ 'UTF8').cast(Integer) + amount).cast(String),
316
+ 'UTF8')
317
+
318
+ if row = @table.
319
+ returning(value_column).
320
+ insert_conflict(target: key_column, update: {value_column => update_expr}).
321
+ insert(key_column => key, value_column => amount.to_s).
322
+ first
323
+ then
324
+ row[value_column].to_i
325
+ end
326
+ end
327
+
328
+ def delete(key, options = {})
329
+ if row = @table.returning(value_column).where(key_column => key).delete.first
330
+ row[value_column]
331
+ end
332
+ end
333
+
334
+ def merge!(pairs, options = {}, &block)
335
+ @backend.transaction do
336
+ pairs = yield_merge_pairs(pairs, &block) if block_given?
337
+ @table.
338
+ insert_conflict(
339
+ target: key_column,
340
+ update: {value_column => ::Sequel[:excluded][value_column]}).
341
+ import([key_column, value_column], blob_pairs(pairs).to_a)
342
+ end
343
+
344
+ self
345
+ end
346
+ end
347
+
348
+ # @api private
349
+ class PostgresHStore < Sequel
350
+ def initialize(options)
351
+ @row = options.delete(:hstore).to_s
352
+ @backend.extension :pg_hstore
353
+ ::Sequel.extension :pg_hstore_ops
354
+ @backend.extension :pg_array
355
+ super
356
+ end
357
+
358
+ def key?(key, options = {})
359
+ !!@table.where(key_column => @row).get(::Sequel[value_column].hstore.key?(key))
360
+ end
361
+
362
+ def store(key, value, options = {})
363
+ create_row
364
+ @table.
365
+ where(key_column => @row).
366
+ update(value_column => ::Sequel[@table_name][value_column].hstore.merge(key => value))
367
+ value
368
+ end
369
+
370
+ def load(key, options = {})
371
+ @table.where(key_column => @row).get(::Sequel[value_column].hstore[key])
372
+ end
373
+
374
+ def delete(key, options = {})
375
+ value = load(key, options)
376
+ @table.where(key_column => @row).update(value_column => ::Sequel[value_column].hstore.delete(key))
377
+ value
378
+ end
379
+
380
+ def increment(key, amount = 1, options = {})
381
+ create_row
382
+ pair = ::Sequel[:hstore].function(
383
+ key,
384
+ (::Sequel[:coalesce].function(
385
+ ::Sequel[value_column].hstore[key].cast(Integer),
386
+ 0) + amount).cast(String))
387
+
388
+ if row = @table.
389
+ returning(::Sequel[value_column].hstore[key].as(:value)).
390
+ where(key_column => @row).
391
+ update(value_column => ::Sequel.join([value_column, pair])).
392
+ first
393
+ then
394
+ row[:value].to_i
395
+ end
396
+ end
397
+
398
+ def create(key, value, options = {})
399
+ create_row
400
+ 1 == @table.
401
+ where(key_column => @row).
402
+ exclude(::Sequel[value_column].hstore.key?(key)).
403
+ update(value_column => ::Sequel[value_column].hstore.merge(key => value))
404
+ end
405
+
406
+ def clear(options = {})
407
+ @table.where(key_column => @row).update(value_column => '')
408
+ self
409
+ end
410
+
411
+ def values_at(*keys, **options)
412
+ @table.
413
+ where(key_column => @row).
414
+ get(::Sequel[value_column].hstore[::Sequel.pg_array(keys)]).to_a
415
+ end
416
+
417
+ def slice(*keys, **options)
418
+ @table.where(key_column => @row).get(::Sequel[value_column].hstore.slice(keys)).to_h
419
+ end
420
+
421
+ def merge!(pairs, options = {}, &block)
422
+ @backend.transaction do
423
+ create_row
424
+ pairs = yield_merge_pairs(pairs, &block) if block_given?
425
+ hash = Hash === pairs ? pairs : Hash[pairs.to_a]
426
+ @table.
427
+ where(key_column => @row).
428
+ update(value_column => ::Sequel[@table_name][value_column].hstore.merge(hash))
429
+ end
430
+
431
+ self
432
+ end
433
+
434
+ def each_key
435
+ unless block_given?
436
+ return enum_for(:each_key) do
437
+ @backend.from(
438
+ @table.
439
+ where(key_column => @row).
440
+ select(::Sequel[@table_name][value_column].hstore.each)).count
441
+ end
442
+ end
443
+ first = false
444
+ @table.
445
+ where(key_column => @row).
446
+ select(::Sequel[@table_name][value_column].hstore.skeys).
447
+ each do |row|
448
+ if first
449
+ first = false
450
+ next
451
+ end
452
+ yield row[:skeys]
453
+ end
454
+ self
455
+ end
456
+
457
+ protected
458
+
459
+ def create_row
460
+ @table.
461
+ insert_ignore.
462
+ insert(key_column => @row, value_column => '')
463
+ end
464
+
465
+ def create_table
466
+ key_column = self.key_column
467
+ value_column = self.value_column
468
+
469
+ @backend.create_table?(@table_name) do
470
+ column key_column, String, null: false, primary_key: true
471
+ column value_column, :hstore
472
+ index value_column, type: :gin
473
+ end
474
+ end
475
+
476
+ def existing_for_update(pairs)
477
+ @table.where(key_column => @row).for_update.
478
+ get(::Sequel[value_column].hstore.slice(pairs.map { |k, _| k }.to_a)).to_h
479
+ end
480
+ end
481
+
482
+ # @api private
483
+ class SQLite < Sequel
484
+ def initialize(options)
485
+ @version = backend.get(::Sequel[:sqlite_version].function)
486
+ # See https://sqlite.org/lang_UPSERT.html
487
+ @can_upsert = ::Gem::Version.new(@version) >= ::Gem::Version.new('3.24.0')
488
+ super
489
+ end
490
+
491
+ def store(key, value, options = {})
492
+ @table.insert_conflict(:replace).insert(key_column => key, value_column => blob(value))
493
+ value
494
+ end
495
+
496
+ def increment(key, amount = 1, options = {})
497
+ return super unless @can_upsert
498
+ update_expr = (::Sequel[@table_name][value_column].cast(Integer) + amount).cast(:blob)
499
+
500
+ @backend.transaction do
501
+ @table.
502
+ insert_conflict(
503
+ target: key_column,
504
+ update: {value_column => update_expr},
505
+ update_where:
506
+ ::Sequel.|(
507
+ {value_column => blob("0")},
508
+ ::Sequel.~(::Sequel[@table_name][value_column].cast(Integer)) => 0)).
509
+ insert(key_column => key, value_column => blob(amount.to_s))
510
+ Integer(load(key))
511
+ end
512
+ end
513
+
514
+ def merge!(pairs, options = {}, &block)
515
+ @backend.transaction do
516
+ pairs = yield_merge_pairs(pairs, &block) if block_given?
517
+ @table.insert_conflict(:replace).import([key_column, value_column], blob_pairs(pairs).to_a)
518
+ end
519
+
520
+ self
521
+ end
121
522
  end
122
523
  end
123
524
  end