splitclient-rb 1.0.2.wip → 8.11.1.pre.rc1-java

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 (210) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/pull_request_template.md +9 -0
  4. data/.github/workflows/ci.yml +90 -0
  5. data/.github/workflows/update-license-year.yml +45 -0
  6. data/.gitignore +20 -0
  7. data/.rubocop.yml +76 -0
  8. data/.simplecov +1 -0
  9. data/CHANGES.txt +361 -2
  10. data/CONTRIBUTORS-GUIDE.md +49 -0
  11. data/Gemfile +2 -0
  12. data/LICENSE +3 -36
  13. data/NOTICE.txt +5 -0
  14. data/README.md +59 -127
  15. data/Rakefile +27 -3
  16. data/ext/murmurhash/MurmurHash3.java +302 -0
  17. data/gemfiles/faraday_after_0.13.gemfile +7 -0
  18. data/gemfiles/faraday_before_0.13.gemfile +8 -0
  19. data/lib/murmurhash/base.rb +58 -0
  20. data/lib/murmurhash/murmurhash.jar +0 -0
  21. data/lib/murmurhash/murmurhash_mri.rb +3 -0
  22. data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +130 -0
  23. data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
  24. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +137 -0
  25. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +53 -0
  26. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +178 -0
  27. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
  28. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
  29. data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
  30. data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
  31. data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
  32. data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
  33. data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
  34. data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
  35. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +45 -0
  36. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +35 -0
  37. data/lib/splitclient-rb/cache/repositories/events_repository.rb +61 -0
  38. data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
  39. data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
  40. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +56 -0
  41. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +57 -0
  42. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +23 -0
  43. data/lib/splitclient-rb/cache/repositories/repository.rb +24 -0
  44. data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
  45. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +124 -0
  46. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +296 -0
  47. data/lib/splitclient-rb/cache/routers/impression_router.rb +60 -0
  48. data/lib/splitclient-rb/cache/senders/events_sender.rb +42 -0
  49. data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
  50. data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
  51. data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
  52. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +95 -0
  53. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +52 -0
  54. data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
  55. data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
  56. data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
  57. data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
  58. data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
  59. data/lib/splitclient-rb/clients/split_client.rb +530 -0
  60. data/lib/splitclient-rb/constants.rb +16 -0
  61. data/lib/splitclient-rb/engine/api/client.rb +87 -0
  62. data/lib/splitclient-rb/engine/api/events.rb +57 -0
  63. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +58 -0
  64. data/lib/splitclient-rb/engine/api/impressions.rb +79 -0
  65. data/lib/splitclient-rb/engine/api/segments.rb +78 -0
  66. data/lib/splitclient-rb/engine/api/splits.rb +139 -0
  67. data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
  68. data/lib/splitclient-rb/engine/auth_api_client.rb +100 -0
  69. data/lib/splitclient-rb/engine/back_off.rb +26 -0
  70. data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
  71. data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
  72. data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
  73. data/lib/{splitclient-engine → splitclient-rb/engine}/evaluator/splitter.rb +35 -22
  74. data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
  75. data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
  76. data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
  77. data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
  78. data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
  79. data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
  80. data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
  81. data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
  82. data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/all_keys_matcher.rb +10 -21
  83. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +47 -0
  84. data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
  85. data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/combiners.rb +4 -6
  86. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +80 -0
  87. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +20 -0
  88. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +16 -0
  89. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +43 -0
  90. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +26 -0
  91. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +42 -0
  92. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +37 -0
  93. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +44 -0
  94. data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
  95. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +16 -0
  96. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +43 -0
  97. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
  98. data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
  99. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +43 -0
  100. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
  101. data/lib/splitclient-rb/engine/matchers/matcher.rb +52 -0
  102. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +29 -0
  103. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +47 -0
  104. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +22 -0
  105. data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
  106. data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
  107. data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
  108. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +27 -0
  109. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +40 -0
  110. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +28 -0
  111. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
  112. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +66 -0
  113. data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
  114. data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
  115. data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
  116. data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
  117. data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
  118. data/lib/splitclient-rb/engine/models/label.rb +10 -0
  119. data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
  120. data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
  121. data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
  122. data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +16 -0
  123. data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
  124. data/lib/splitclient-rb/engine/models/split.rb +17 -0
  125. data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
  126. data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
  127. data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
  128. data/lib/splitclient-rb/engine/parser/condition.rb +271 -0
  129. data/lib/splitclient-rb/engine/parser/evaluator.rb +112 -0
  130. data/lib/{splitclient-engine → splitclient-rb/engine}/parser/partition.rb +2 -4
  131. data/lib/splitclient-rb/engine/push_manager.rb +66 -0
  132. data/lib/splitclient-rb/engine/status_manager.rb +39 -0
  133. data/lib/splitclient-rb/engine/sync_manager.rb +183 -0
  134. data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
  135. data/lib/splitclient-rb/exceptions.rb +26 -0
  136. data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
  137. data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
  138. data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
  139. data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
  140. data/lib/splitclient-rb/helpers/util.rb +26 -0
  141. data/lib/splitclient-rb/managers/split_manager.rb +121 -0
  142. data/lib/splitclient-rb/spec.rb +9 -0
  143. data/lib/splitclient-rb/split_config.rb +591 -47
  144. data/lib/splitclient-rb/split_factory.rb +284 -0
  145. data/lib/splitclient-rb/split_factory_builder.rb +7 -0
  146. data/lib/splitclient-rb/split_factory_registry.rb +63 -0
  147. data/lib/splitclient-rb/split_logger.rb +23 -0
  148. data/lib/splitclient-rb/sse/event_source/client.rb +264 -0
  149. data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
  150. data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
  151. data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
  152. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
  153. data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
  154. data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
  155. data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
  156. data/lib/splitclient-rb/sse/workers/splits_worker.rb +153 -0
  157. data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
  158. data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
  159. data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
  160. data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
  161. data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
  162. data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
  163. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
  164. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
  165. data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
  166. data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
  167. data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
  168. data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
  169. data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
  170. data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
  171. data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
  172. data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
  173. data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
  174. data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
  175. data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
  176. data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
  177. data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
  178. data/lib/splitclient-rb/utilitites.rb +49 -0
  179. data/lib/splitclient-rb/validators.rb +361 -0
  180. data/lib/splitclient-rb/version.rb +1 -1
  181. data/lib/splitclient-rb.rb +177 -25
  182. data/sonar-project.properties +6 -0
  183. data/splitclient-rb.gemspec +53 -26
  184. data/tasks/benchmark_get_treatment.rake +31 -17
  185. data/tasks/irb.rake +6 -0
  186. metadata +411 -86
  187. data/NEWS +0 -9
  188. data/lib/splitclient-cache/local_store.rb +0 -45
  189. data/lib/splitclient-engine/impressions/impressions.rb +0 -79
  190. data/lib/splitclient-engine/matchers/between_matcher.rb +0 -48
  191. data/lib/splitclient-engine/matchers/combining_matcher.rb +0 -94
  192. data/lib/splitclient-engine/matchers/equal_to_matcher.rb +0 -48
  193. data/lib/splitclient-engine/matchers/greater_than_or_equal_to_matcher.rb +0 -48
  194. data/lib/splitclient-engine/matchers/less_than_or_equal_to_matcher.rb +0 -48
  195. data/lib/splitclient-engine/matchers/negation_matcher.rb +0 -54
  196. data/lib/splitclient-engine/matchers/user_defined_segment_matcher.rb +0 -61
  197. data/lib/splitclient-engine/matchers/whitelist_matcher.rb +0 -64
  198. data/lib/splitclient-engine/metrics/binary_search_latency_tracker.rb +0 -122
  199. data/lib/splitclient-engine/metrics/metrics.rb +0 -158
  200. data/lib/splitclient-engine/parser/condition.rb +0 -143
  201. data/lib/splitclient-engine/parser/segment.rb +0 -84
  202. data/lib/splitclient-engine/parser/segment_parser.rb +0 -46
  203. data/lib/splitclient-engine/parser/split.rb +0 -68
  204. data/lib/splitclient-engine/parser/split_adapter.rb +0 -433
  205. data/lib/splitclient-engine/parser/split_parser.rb +0 -139
  206. data/lib/splitclient-engine/partitions/treatments.rb +0 -40
  207. data/lib/splitclient-rb/split_client.rb +0 -156
  208. data/lib/splitclient-rb_utilitites.rb +0 -26
  209. data/tasks/console.rake +0 -4
  210. data/tasks/rspec.rake +0 -3
@@ -0,0 +1,302 @@
1
+ /**
2
+ * The MurmurHash3 algorithm was created by Austin Appleby and placed in the public domain.
3
+ * This java port was authored by Yonik Seeley and also placed into the public domain.
4
+ * The author hereby disclaims copyright to this source code.
5
+ * <p>
6
+ * This produces exactly the same hash values as the final C++
7
+ * version of MurmurHash3 and is thus suitable for producing the same hash values across
8
+ * platforms.
9
+ * <p>
10
+ * The 32 bit x86 version of this hash should be the fastest variant for relatively short keys like ids.
11
+ * murmurhash3_x64_128 is a good choice for longer strings or if you need more than 32 bits of hash.
12
+ * <p>
13
+ * Note - The x86 and x64 versions do _not_ produce the same results, as the
14
+ * algorithms are optimized for their respective platforms.
15
+ * <p>
16
+ * See http://github.com/yonik/java_util for future updates to this file.
17
+ */
18
+ public final class MurmurHash3 {
19
+
20
+ /**
21
+ * 128 bits of state
22
+ */
23
+ public static final class LongPair {
24
+ public long val1;
25
+ public long val2;
26
+ }
27
+
28
+ public static final int fmix32(int h) {
29
+ h ^= h >>> 16;
30
+ h *= 0x85ebca6b;
31
+ h ^= h >>> 13;
32
+ h *= 0xc2b2ae35;
33
+ h ^= h >>> 16;
34
+ return h;
35
+ }
36
+
37
+ public static final long fmix64(long k) {
38
+ k ^= k >>> 33;
39
+ k *= 0xff51afd7ed558ccdL;
40
+ k ^= k >>> 33;
41
+ k *= 0xc4ceb9fe1a85ec53L;
42
+ k ^= k >>> 33;
43
+ return k;
44
+ }
45
+
46
+ /**
47
+ * Gets a long from a byte buffer in little endian byte order.
48
+ */
49
+ public static final long getLongLittleEndian(byte[] buf, int offset) {
50
+ return ((long) buf[offset + 7] << 56) // no mask needed
51
+ | ((buf[offset + 6] & 0xffL) << 48)
52
+ | ((buf[offset + 5] & 0xffL) << 40)
53
+ | ((buf[offset + 4] & 0xffL) << 32)
54
+ | ((buf[offset + 3] & 0xffL) << 24)
55
+ | ((buf[offset + 2] & 0xffL) << 16)
56
+ | ((buf[offset + 1] & 0xffL) << 8)
57
+ | ((buf[offset] & 0xffL)); // no shift needed
58
+ }
59
+
60
+
61
+ /**
62
+ * Returns the MurmurHash3_x86_32 hash of the UTF-8 bytes of the String without actually encoding
63
+ * the string to a temporary buffer. This is more than 2x faster than hashing the result
64
+ * of String.getBytes().
65
+ */
66
+ public static long murmurhash3_x86_32(CharSequence data, int seed) {
67
+ final int c1 = 0xcc9e2d51;
68
+ final int c2 = 0x1b873593;
69
+
70
+ int h1 = seed;
71
+
72
+ int offset = 0;
73
+ int len = data.length();
74
+ int pos = offset;
75
+ int end = offset + len;
76
+ int k1 = 0;
77
+ int k2 = 0;
78
+ int shift = 0;
79
+ int bits = 0;
80
+ int nBytes = 0; // length in UTF8 bytes
81
+
82
+
83
+ while (pos < end) {
84
+ int code = data.charAt(pos++);
85
+ if (code < 0x80) {
86
+ k2 = code;
87
+ bits = 8;
88
+
89
+ } else if (code < 0x800) {
90
+ k2 = (0xC0 | (code >> 6))
91
+ | ((0x80 | (code & 0x3F)) << 8);
92
+ bits = 16;
93
+ } else if (code < 0xD800 || code > 0xDFFF || pos >= end) {
94
+ // we check for pos>=end to encode an unpaired surrogate as 3 bytes.
95
+ k2 = (0xE0 | (code >> 12))
96
+ | ((0x80 | ((code >> 6) & 0x3F)) << 8)
97
+ | ((0x80 | (code & 0x3F)) << 16);
98
+ bits = 24;
99
+ } else {
100
+ // surrogate pair
101
+ // int utf32 = pos < end ? (int) data.charAt(pos++) : 0;
102
+ int utf32 = (int) data.charAt(pos++);
103
+ utf32 = ((code - 0xD7C0) << 10) + (utf32 & 0x3FF);
104
+ k2 = (0xff & (0xF0 | (utf32 >> 18)))
105
+ | ((0x80 | ((utf32 >> 12) & 0x3F))) << 8
106
+ | ((0x80 | ((utf32 >> 6) & 0x3F))) << 16
107
+ | (0x80 | (utf32 & 0x3F)) << 24;
108
+ bits = 32;
109
+ }
110
+
111
+
112
+ k1 |= k2 << shift;
113
+
114
+ // int used_bits = 32 - shift; // how many bits of k2 were used in k1.
115
+ // int unused_bits = bits - used_bits; // (bits-(32-shift)) == bits+shift-32 == bits-newshift
116
+
117
+ shift += bits;
118
+ if (shift >= 32) {
119
+ // mix after we have a complete word
120
+
121
+ k1 *= c1;
122
+ k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15);
123
+ k1 *= c2;
124
+
125
+ h1 ^= k1;
126
+ h1 = (h1 << 13) | (h1 >>> 19); // ROTL32(h1,13);
127
+ h1 = h1 * 5 + 0xe6546b64;
128
+
129
+ shift -= 32;
130
+ // unfortunately, java won't let you shift 32 bits off, so we need to check for 0
131
+ if (shift != 0) {
132
+ k1 = k2 >>> (bits - shift); // bits used == bits - newshift
133
+ } else {
134
+ k1 = 0;
135
+ }
136
+ nBytes += 4;
137
+ }
138
+
139
+ } // inner
140
+
141
+ // handle tail
142
+ if (shift > 0) {
143
+ nBytes += shift >> 3;
144
+ k1 *= c1;
145
+ k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15);
146
+ k1 *= c2;
147
+ h1 ^= k1;
148
+ }
149
+
150
+ // finalization
151
+ h1 ^= nBytes;
152
+
153
+ // fmix(h1);
154
+ h1 ^= h1 >>> 16;
155
+ h1 *= 0x85ebca6b;
156
+ h1 ^= h1 >>> 13;
157
+ h1 *= 0xc2b2ae35;
158
+ h1 ^= h1 >>> 16;
159
+
160
+ return h1 & 0xFFFFFFFFL;
161
+ }
162
+
163
+ // The following set of methods and constants are borrowed from:
164
+ // `This method is borrowed from `org.apache.commons.codec.digest.MurmurHash3`
165
+
166
+ // Constants for 128-bit variant
167
+ private static final long C1 = 0x87c37b91114253d5L;
168
+ private static final long C2 = 0x4cf5ad432745937fL;
169
+ private static final int R1 = 31;
170
+ private static final int R2 = 27;
171
+ private static final int R3 = 33;
172
+ private static final int M = 5;
173
+ private static final int N1 = 0x52dce729;
174
+ private static final int N2 = 0x38495ab5;
175
+
176
+ /**
177
+ * Gets the little-endian long from 8 bytes starting at the specified index.
178
+ *
179
+ * @param data The data
180
+ * @param index The index
181
+ * @return The little-endian long
182
+ */
183
+ private static long getLittleEndianLong(final byte[] data, final int index) {
184
+ return (((long) data[index ] & 0xff) ) |
185
+ (((long) data[index + 1] & 0xff) << 8) |
186
+ (((long) data[index + 2] & 0xff) << 16) |
187
+ (((long) data[index + 3] & 0xff) << 24) |
188
+ (((long) data[index + 4] & 0xff) << 32) |
189
+ (((long) data[index + 5] & 0xff) << 40) |
190
+ (((long) data[index + 6] & 0xff) << 48) |
191
+ (((long) data[index + 7] & 0xff) << 56);
192
+ }
193
+
194
+ public static long[] hash128x64(final String data, final long seed) {
195
+ final byte[] dataBytes = data.getBytes();
196
+ return hash128x64(dataBytes, 0, dataBytes.length, seed);
197
+ }
198
+
199
+ /**
200
+ * Generates 128-bit hash from the byte array with the given offset, length and seed.
201
+ *
202
+ * <p>This is an implementation of the 128-bit hash function {@code MurmurHash3_x64_128}
203
+ * from from Austin Applyby's original MurmurHash3 {@code c++} code in SMHasher.</p>
204
+ *
205
+ * @param data The input byte array
206
+ * @param offset The first element of array
207
+ * @param length The length of array
208
+ * @param seed The initial seed value
209
+ * @return The 128-bit hash (2 longs)
210
+ */
211
+ public static long[] hash128x64(final byte[] data, final int offset, final int length, final long seed) {
212
+ long h1 = seed;
213
+ long h2 = seed;
214
+ final int nblocks = length >> 4;
215
+
216
+ // body
217
+ for (int i = 0; i < nblocks; i++) {
218
+ final int index = offset + (i << 4);
219
+ long k1 = getLittleEndianLong(data, index);
220
+ long k2 = getLittleEndianLong(data, index + 8);
221
+
222
+ // mix functions for k1
223
+ k1 *= C1;
224
+ k1 = Long.rotateLeft(k1, R1);
225
+ k1 *= C2;
226
+ h1 ^= k1;
227
+ h1 = Long.rotateLeft(h1, R2);
228
+ h1 += h2;
229
+ h1 = h1 * M + N1;
230
+
231
+ // mix functions for k2
232
+ k2 *= C2;
233
+ k2 = Long.rotateLeft(k2, R3);
234
+ k2 *= C1;
235
+ h2 ^= k2;
236
+ h2 = Long.rotateLeft(h2, R1);
237
+ h2 += h1;
238
+ h2 = h2 * M + N2;
239
+ }
240
+
241
+ // tail
242
+ long k1 = 0;
243
+ long k2 = 0;
244
+ final int index = offset + (nblocks << 4);
245
+ switch (offset + length - index) {
246
+ case 15:
247
+ k2 ^= ((long) data[index + 14] & 0xff) << 48;
248
+ case 14:
249
+ k2 ^= ((long) data[index + 13] & 0xff) << 40;
250
+ case 13:
251
+ k2 ^= ((long) data[index + 12] & 0xff) << 32;
252
+ case 12:
253
+ k2 ^= ((long) data[index + 11] & 0xff) << 24;
254
+ case 11:
255
+ k2 ^= ((long) data[index + 10] & 0xff) << 16;
256
+ case 10:
257
+ k2 ^= ((long) data[index + 9] & 0xff) << 8;
258
+ case 9:
259
+ k2 ^= data[index + 8] & 0xff;
260
+ k2 *= C2;
261
+ k2 = Long.rotateLeft(k2, R3);
262
+ k2 *= C1;
263
+ h2 ^= k2;
264
+
265
+ case 8:
266
+ k1 ^= ((long) data[index + 7] & 0xff) << 56;
267
+ case 7:
268
+ k1 ^= ((long) data[index + 6] & 0xff) << 48;
269
+ case 6:
270
+ k1 ^= ((long) data[index + 5] & 0xff) << 40;
271
+ case 5:
272
+ k1 ^= ((long) data[index + 4] & 0xff) << 32;
273
+ case 4:
274
+ k1 ^= ((long) data[index + 3] & 0xff) << 24;
275
+ case 3:
276
+ k1 ^= ((long) data[index + 2] & 0xff) << 16;
277
+ case 2:
278
+ k1 ^= ((long) data[index + 1] & 0xff) << 8;
279
+ case 1:
280
+ k1 ^= data[index] & 0xff;
281
+ k1 *= C1;
282
+ k1 = Long.rotateLeft(k1, R1);
283
+ k1 *= C2;
284
+ h1 ^= k1;
285
+ }
286
+
287
+ // finalization
288
+ h1 ^= length;
289
+ h2 ^= length;
290
+
291
+ h1 += h2;
292
+ h2 += h1;
293
+
294
+ h1 = fmix64(h1);
295
+ h2 = fmix64(h2);
296
+
297
+ h1 += h2;
298
+ h2 += h1;
299
+
300
+ return new long[] { h1, h2 };
301
+ }
302
+ }
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "faraday", "> 0.13"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "faraday", ">= 0.9", "< 0.13"
6
+ gem "net-http-persistent", "~> 3.0"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,58 @@
1
+ module Digest
2
+ ds = Struct.new(:digest_length, :seed_length)
3
+ s1 = ds.new(4, 4)
4
+ s2 = ds.new(8, 8)
5
+ s3 = ds.new(16, 4)
6
+ {
7
+ '1' => s1,
8
+ '2' => s1,
9
+ '2A' => s1,
10
+ '64A' => s2,
11
+ '64B' => s2,
12
+ 'Aligned2' => s1,
13
+ 'Neutral2' => s1,
14
+ '3_x86_32' => s1,
15
+ '3_x86_128' => s3,
16
+ '3_x64_128' => s3,
17
+ }.each do |name, s|
18
+ class_eval %Q{
19
+ class MurmurHashMRI#{name} < Digest::Class
20
+ DEFAULT_SEED = "#{"\x00" * s.seed_length}".b
21
+
22
+ def initialize
23
+ @buffer = ""
24
+ @seed = DEFAULT_SEED
25
+ end
26
+
27
+ def update(str)
28
+ @buffer << str
29
+ self
30
+ end
31
+ alias << update
32
+
33
+ def reset
34
+ @buffer.clear
35
+ @seed = DEFAULT_SEED
36
+ self
37
+ end
38
+
39
+ def seed
40
+ @seed
41
+ end
42
+
43
+ def seed=(s)
44
+ raise ArgumentError, "seed string should be #{s.seed_length} length" if #{s.seed_length} != s.length
45
+ @seed = s
46
+ end
47
+
48
+ def digest_length
49
+ #{s.digest_length}
50
+ end
51
+
52
+ def block_length
53
+ 0
54
+ end
55
+ end
56
+ }
57
+ end
58
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ require 'digest'
2
+ require 'murmurhash/base'
3
+ require 'murmurhash/murmurhash'
@@ -0,0 +1,130 @@
1
+ require 'lru_redux'
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Adapters
6
+ class CacheAdapter
7
+ extend Forwardable
8
+ def_delegators :@adapter, :initialize_set, :set_bool, :pipelined
9
+
10
+ def initialize(config)
11
+ @cache = LruRedux::TTL::ThreadSafeCache.new(config.max_cache_size, config.cache_ttl)
12
+ @adapter = config.cache_adapter
13
+ end
14
+
15
+ def delete(key)
16
+ @cache.delete(key)
17
+ @adapter.delete(key)
18
+ end
19
+
20
+ def clear(namespace_key)
21
+ @cache.clear
22
+ end
23
+
24
+ def string(key)
25
+ value = get(key)
26
+ return value if value
27
+ value = @adapter.string(key)
28
+ add(key, value)
29
+ value
30
+ end
31
+
32
+ def set_string(key, value)
33
+ add(key, value)
34
+ @adapter.set_string(key, value)
35
+ end
36
+
37
+ def multiple_strings(keys)
38
+ cached_values = keys.each_with_object({}) do |key, memo|
39
+ memo[key] = get(key)
40
+ end
41
+
42
+ non_cached_keys = []
43
+ cached_values.delete_if{ |k,v| v.nil? ? non_cached_keys << k : false }
44
+
45
+ if non_cached_keys.any?
46
+ new_values = @adapter.multiple_strings(non_cached_keys)
47
+
48
+ new_values.keys.each do |key, value|
49
+ add(key, value)
50
+ end
51
+
52
+ cached_values.merge!(new_values)
53
+ end
54
+
55
+ cached_values
56
+ end
57
+
58
+ def find_strings_by_prefix(prefix)
59
+ @adapter.find_strings_by_prefix(prefix)
60
+ end
61
+
62
+ def exists?(key)
63
+ cached_value = get(key)
64
+ if cached_value.nil?
65
+ @adapter.exists?(key)
66
+ else
67
+ true
68
+ end
69
+ end
70
+
71
+ def add_to_set(key, values)
72
+ if values.is_a? Array
73
+ values.each { |value| add_to_map(key, value, 1) }
74
+ else
75
+ add_to_map(key, values, 1)
76
+ end
77
+ @adapter.add_to_set(key, values)
78
+ end
79
+
80
+ def in_set?(key, field)
81
+ cached_value = get(key)
82
+ if cached_value.nil?
83
+ return @adapter.in_set?(key, field)
84
+ end
85
+ cached_value.key?(field)
86
+ end
87
+
88
+ def get_set(key)
89
+ cached_value = get(key)
90
+ if cached_value.nil?
91
+ return @adapter.get_set(key)
92
+ end
93
+ cached_value.keys
94
+ end
95
+
96
+ def delete_from_set(key, fields)
97
+ cached_value = get(key)
98
+ if cached_value
99
+ if fields.is_a? Array
100
+ fields.each { |field| cached_value.delete(field) }
101
+ else
102
+ cached_value.delete(fields)
103
+ end
104
+ end
105
+
106
+ @adapter.delete_from_set(key, fields)
107
+ end
108
+
109
+ def initialize_map(key)
110
+ @cache[key] = Concurrent::Map.new
111
+ end
112
+
113
+ private
114
+
115
+ def add_to_map(key, field, value)
116
+ initialize_map(key) unless get(key)
117
+ get(key).put(field.to_s, value.to_s)
118
+ end
119
+
120
+ def add(key, value)
121
+ @cache[key] = value.to_s unless value.nil?
122
+ end
123
+
124
+ def get(key)
125
+ @cache[key]
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,12 @@
1
+ require 'concurrent'
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Adapters
6
+ # Memory adapter can have different implementations, this class is used as a delegator to
7
+ # this implementations
8
+ class MemoryAdapter < SimpleDelegator
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,137 @@
1
+ require 'concurrent'
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Adapters
6
+ module MemoryAdapters
7
+ # Memory adapter implementation, which stores everything inside thread-safe Map
8
+ class MapAdapter
9
+ def initialize
10
+ @map = Concurrent::Map.new
11
+ end
12
+
13
+ def clear(_ = nil)
14
+ initialize
15
+ end
16
+
17
+ # Map
18
+ def initialize_map(key)
19
+ @map[key] = Concurrent::Map.new
20
+ end
21
+
22
+ def add_to_map(key, field, value)
23
+ initialize_map(key) unless @map[key]
24
+
25
+ @map[key].put(field, value)
26
+ end
27
+
28
+ def find_in_map(key, field)
29
+ return nil if @map[key].nil?
30
+
31
+ @map[key].get(field)
32
+ end
33
+
34
+ def delete_from_map(key, fields)
35
+ if fields.is_a? Array
36
+ fields.each { |field| @map[key].delete(field) }
37
+ else
38
+ @map[key].delete(fields)
39
+ end
40
+ end
41
+
42
+ def in_map?(key, field)
43
+ return false if @map[key].nil?
44
+
45
+ @map[key].key?(field)
46
+ end
47
+
48
+ def map_keys(key)
49
+ @map[key].keys
50
+ end
51
+
52
+ def get_map(key)
53
+ @map[key]
54
+ end
55
+
56
+ # String
57
+ def string(key)
58
+ @map[key]
59
+ end
60
+
61
+ def set_string(key, str)
62
+ @map[key] = str
63
+ end
64
+
65
+ def find_strings_by_prefix(prefix)
66
+ @map.keys.select { |str| str.start_with? prefix }
67
+ end
68
+
69
+ def multiple_strings(keys)
70
+ keys.each_with_object({}) do |key, memo|
71
+ memo[key] = string(key)
72
+ end
73
+ end
74
+
75
+ # Bool
76
+ def set_bool(key, val)
77
+ @map[key] = val
78
+ end
79
+
80
+ def bool(key)
81
+ @map[key]
82
+ end
83
+
84
+ # Set
85
+ alias_method :initialize_set, :initialize_map
86
+ alias_method :get_set, :map_keys
87
+ alias_method :delete_from_set, :delete_from_map
88
+ alias_method :in_set?, :in_map?
89
+ alias_method :find_sets_by_prefix, :find_strings_by_prefix
90
+
91
+ def add_to_set(key, values)
92
+ if values.is_a? Array
93
+ values.each { |value| add_to_map(key, value, 1) }
94
+ else
95
+ add_to_map(key, values, 1)
96
+ end
97
+ end
98
+
99
+ def get_all_from_set(key)
100
+ @map[key].keys
101
+ end
102
+
103
+ def union_sets(set_keys)
104
+ array = set_keys.each_with_object([]) do |key, memo|
105
+ memo << get_set(key)
106
+ end.flatten
107
+
108
+ Set.new(array)
109
+ end
110
+
111
+ # General
112
+ def exists?(key)
113
+ !@map[key].nil?
114
+ end
115
+
116
+ def delete(key)
117
+ if key.is_a? Array
118
+ key.each { |k| @map.delete(k) }
119
+ else
120
+ @map.delete(key)
121
+ end
122
+ end
123
+
124
+ def empty?
125
+ @map.empty?
126
+ end
127
+
128
+ # This method is used in Redis adapter
129
+ # "stubbing" it here to keep the interface
130
+ def pipelined(&block)
131
+ block.call
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end