couchbase 3.1.1-universal-darwin-20 → 3.2.0-universal-darwin-20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/CMakeLists.txt +3 -1
  4. data/ext/build_version.hxx.in +1 -1
  5. data/ext/cmake/Testing.cmake +1 -0
  6. data/ext/cmake/ThirdPartyDependencies.cmake +6 -0
  7. data/ext/cmake/VersionInfo.cmake +3 -0
  8. data/ext/couchbase/bucket.hxx +47 -28
  9. data/ext/couchbase/cbsasl/client.h +1 -1
  10. data/ext/couchbase/cbsasl/context.cc +1 -1
  11. data/ext/couchbase/cbsasl/context.h +3 -3
  12. data/ext/couchbase/cbsasl/mechanism.cc +5 -8
  13. data/ext/couchbase/cbsasl/mechanism.h +1 -4
  14. data/ext/couchbase/cbsasl/plain/plain.cc +1 -1
  15. data/ext/couchbase/cbsasl/scram-sha/scram-sha.cc +30 -36
  16. data/ext/couchbase/cluster.hxx +40 -22
  17. data/ext/couchbase/cluster_options.hxx +7 -1
  18. data/ext/couchbase/configuration.hxx +37 -16
  19. data/ext/couchbase/couchbase.cxx +1145 -291
  20. data/ext/couchbase/error_map.hxx +1 -1
  21. data/ext/couchbase/errors.hxx +25 -17
  22. data/ext/couchbase/io/dns_client.hxx +3 -3
  23. data/ext/couchbase/io/dns_codec.hxx +4 -5
  24. data/ext/couchbase/io/dns_config.hxx +5 -6
  25. data/ext/couchbase/io/dns_message.hxx +3 -3
  26. data/ext/couchbase/io/http_command.hxx +70 -35
  27. data/ext/couchbase/io/http_session.hxx +4 -3
  28. data/ext/couchbase/io/http_session_manager.hxx +28 -19
  29. data/ext/couchbase/io/mcbp_command.hxx +51 -19
  30. data/ext/couchbase/io/mcbp_context.hxx +1 -1
  31. data/ext/couchbase/io/mcbp_parser.hxx +4 -4
  32. data/ext/couchbase/io/mcbp_session.hxx +91 -101
  33. data/ext/couchbase/io/query_cache.hxx +2 -2
  34. data/ext/couchbase/io/retry_orchestrator.hxx +2 -4
  35. data/ext/couchbase/io/retry_reason.hxx +2 -2
  36. data/ext/couchbase/io/retry_strategy.hxx +1 -6
  37. data/ext/couchbase/io/streams.hxx +7 -7
  38. data/ext/couchbase/metrics/logging_meter.hxx +228 -0
  39. data/ext/couchbase/metrics/logging_meter_options.hxx +28 -0
  40. data/ext/couchbase/metrics/meter.hxx +49 -0
  41. data/ext/couchbase/metrics/noop_meter.hxx +43 -0
  42. data/ext/couchbase/operations.hxx +4 -0
  43. data/ext/couchbase/operations/analytics_dataset_create.hxx +16 -12
  44. data/ext/couchbase/operations/analytics_dataset_drop.hxx +11 -11
  45. data/ext/couchbase/operations/analytics_dataset_get_all.hxx +6 -6
  46. data/ext/couchbase/operations/analytics_dataverse_create.hxx +10 -11
  47. data/ext/couchbase/operations/analytics_dataverse_drop.hxx +10 -11
  48. data/ext/couchbase/operations/analytics_get_pending_mutations.hxx +9 -11
  49. data/ext/couchbase/operations/analytics_index_create.hxx +14 -13
  50. data/ext/couchbase/operations/analytics_index_drop.hxx +18 -12
  51. data/ext/couchbase/operations/analytics_index_get_all.hxx +8 -6
  52. data/ext/couchbase/operations/analytics_link.hxx +39 -0
  53. data/ext/couchbase/operations/analytics_link_azure_blob_external.hxx +145 -0
  54. data/ext/couchbase/operations/analytics_link_connect.hxx +14 -12
  55. data/ext/couchbase/operations/analytics_link_couchbase_remote.hxx +220 -0
  56. data/ext/couchbase/operations/analytics_link_create.hxx +128 -0
  57. data/ext/couchbase/operations/analytics_link_disconnect.hxx +11 -12
  58. data/ext/couchbase/operations/analytics_link_drop.hxx +130 -0
  59. data/ext/couchbase/operations/analytics_link_get_all.hxx +160 -0
  60. data/ext/couchbase/operations/analytics_link_replace.hxx +128 -0
  61. data/ext/couchbase/operations/analytics_link_s3_external.hxx +122 -0
  62. data/ext/couchbase/operations/bucket_create.hxx +8 -8
  63. data/ext/couchbase/operations/bucket_drop.hxx +5 -5
  64. data/ext/couchbase/operations/bucket_flush.hxx +5 -5
  65. data/ext/couchbase/operations/bucket_get.hxx +7 -7
  66. data/ext/couchbase/operations/bucket_get_all.hxx +7 -5
  67. data/ext/couchbase/operations/bucket_settings.hxx +40 -49
  68. data/ext/couchbase/operations/bucket_update.hxx +8 -8
  69. data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +7 -7
  70. data/ext/couchbase/operations/collection_create.hxx +11 -11
  71. data/ext/couchbase/operations/collection_drop.hxx +12 -10
  72. data/ext/couchbase/operations/collections_manifest_get.hxx +3 -3
  73. data/ext/couchbase/operations/design_document.hxx +2 -2
  74. data/ext/couchbase/operations/document_analytics.hxx +29 -36
  75. data/ext/couchbase/operations/document_append.hxx +3 -3
  76. data/ext/couchbase/operations/document_decrement.hxx +3 -3
  77. data/ext/couchbase/operations/document_exists.hxx +2 -2
  78. data/ext/couchbase/operations/document_get.hxx +3 -3
  79. data/ext/couchbase/operations/document_get_and_lock.hxx +5 -3
  80. data/ext/couchbase/operations/document_get_and_touch.hxx +5 -3
  81. data/ext/couchbase/operations/document_get_projected.hxx +10 -11
  82. data/ext/couchbase/operations/document_increment.hxx +3 -3
  83. data/ext/couchbase/operations/document_insert.hxx +3 -3
  84. data/ext/couchbase/operations/document_lookup_in.hxx +12 -18
  85. data/ext/couchbase/operations/document_mutate_in.hxx +13 -18
  86. data/ext/couchbase/operations/document_prepend.hxx +3 -3
  87. data/ext/couchbase/operations/document_query.hxx +39 -41
  88. data/ext/couchbase/operations/document_remove.hxx +3 -3
  89. data/ext/couchbase/operations/document_replace.hxx +3 -3
  90. data/ext/couchbase/operations/document_search.hxx +56 -61
  91. data/ext/couchbase/operations/document_touch.hxx +3 -3
  92. data/ext/couchbase/operations/document_unlock.hxx +3 -3
  93. data/ext/couchbase/operations/document_upsert.hxx +3 -3
  94. data/ext/couchbase/operations/document_view.hxx +23 -23
  95. data/ext/couchbase/operations/group_drop.hxx +5 -5
  96. data/ext/couchbase/operations/group_get.hxx +7 -7
  97. data/ext/couchbase/operations/group_get_all.hxx +6 -6
  98. data/ext/couchbase/operations/group_upsert.hxx +11 -11
  99. data/ext/couchbase/operations/http_noop.hxx +6 -6
  100. data/ext/couchbase/operations/mcbp_noop.hxx +3 -3
  101. data/ext/couchbase/operations/query_index_build_deferred.hxx +6 -6
  102. data/ext/couchbase/operations/query_index_create.hxx +10 -8
  103. data/ext/couchbase/operations/query_index_drop.hxx +8 -8
  104. data/ext/couchbase/operations/query_index_get_all.hxx +43 -39
  105. data/ext/couchbase/operations/rbac.hxx +40 -63
  106. data/ext/couchbase/operations/role_get_all.hxx +6 -6
  107. data/ext/couchbase/operations/scope_create.hxx +10 -10
  108. data/ext/couchbase/operations/scope_drop.hxx +9 -9
  109. data/ext/couchbase/operations/scope_get_all.hxx +8 -8
  110. data/ext/couchbase/operations/search_get_stats.hxx +5 -3
  111. data/ext/couchbase/operations/search_index.hxx +6 -15
  112. data/ext/couchbase/operations/search_index_analyze_document.hxx +11 -11
  113. data/ext/couchbase/operations/search_index_control_ingest.hxx +9 -9
  114. data/ext/couchbase/operations/search_index_control_plan_freeze.hxx +9 -9
  115. data/ext/couchbase/operations/search_index_control_query.hxx +9 -9
  116. data/ext/couchbase/operations/search_index_drop.hxx +11 -9
  117. data/ext/couchbase/operations/search_index_get.hxx +11 -9
  118. data/ext/couchbase/operations/search_index_get_all.hxx +11 -11
  119. data/ext/couchbase/operations/search_index_get_documents_count.hxx +10 -10
  120. data/ext/couchbase/operations/search_index_get_stats.hxx +10 -8
  121. data/ext/couchbase/operations/search_index_upsert.hxx +12 -10
  122. data/ext/couchbase/operations/user_drop.hxx +5 -5
  123. data/ext/couchbase/operations/user_get.hxx +7 -7
  124. data/ext/couchbase/operations/user_get_all.hxx +6 -6
  125. data/ext/couchbase/operations/user_upsert.hxx +9 -9
  126. data/ext/couchbase/operations/view_index_drop.hxx +10 -10
  127. data/ext/couchbase/operations/view_index_get.hxx +13 -15
  128. data/ext/couchbase/operations/view_index_get_all.hxx +17 -20
  129. data/ext/couchbase/operations/view_index_upsert.hxx +9 -7
  130. data/ext/couchbase/origin.hxx +14 -10
  131. data/ext/couchbase/platform/backtrace.c +1 -1
  132. data/ext/couchbase/platform/base64.cc +5 -5
  133. data/ext/couchbase/platform/base64.h +2 -5
  134. data/ext/couchbase/protocol/client_opcode.hxx +7 -4
  135. data/ext/couchbase/protocol/client_request.hxx +2 -2
  136. data/ext/couchbase/protocol/client_response.hxx +41 -16
  137. data/ext/couchbase/protocol/cmd_append.hxx +17 -16
  138. data/ext/couchbase/protocol/cmd_cluster_map_change_notification.hxx +4 -4
  139. data/ext/couchbase/protocol/cmd_decrement.hxx +10 -11
  140. data/ext/couchbase/protocol/cmd_exists.hxx +12 -15
  141. data/ext/couchbase/protocol/cmd_get.hxx +11 -14
  142. data/ext/couchbase/protocol/cmd_get_and_lock.hxx +10 -12
  143. data/ext/couchbase/protocol/cmd_get_and_touch.hxx +10 -12
  144. data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +13 -18
  145. data/ext/couchbase/protocol/cmd_get_collection_id.hxx +12 -15
  146. data/ext/couchbase/protocol/cmd_get_collections_manifest.hxx +12 -16
  147. data/ext/couchbase/protocol/cmd_get_error_map.hxx +14 -17
  148. data/ext/couchbase/protocol/cmd_hello.hxx +8 -10
  149. data/ext/couchbase/protocol/cmd_increment.hxx +9 -10
  150. data/ext/couchbase/protocol/cmd_insert.hxx +9 -9
  151. data/ext/couchbase/protocol/cmd_lookup_in.hxx +12 -13
  152. data/ext/couchbase/protocol/cmd_mutate_in.hxx +11 -11
  153. data/ext/couchbase/protocol/cmd_noop.hxx +16 -20
  154. data/ext/couchbase/protocol/cmd_prepend.hxx +9 -10
  155. data/ext/couchbase/protocol/cmd_remove.hxx +10 -13
  156. data/ext/couchbase/protocol/cmd_replace.hxx +7 -7
  157. data/ext/couchbase/protocol/cmd_sasl_auth.hxx +8 -10
  158. data/ext/couchbase/protocol/cmd_sasl_list_mechs.hxx +10 -15
  159. data/ext/couchbase/protocol/cmd_sasl_step.hxx +10 -12
  160. data/ext/couchbase/protocol/cmd_select_bucket.hxx +14 -18
  161. data/ext/couchbase/protocol/cmd_touch.hxx +8 -11
  162. data/ext/couchbase/protocol/cmd_unlock.hxx +10 -14
  163. data/ext/couchbase/protocol/cmd_upsert.hxx +8 -8
  164. data/ext/couchbase/protocol/datatype.hxx +3 -3
  165. data/ext/couchbase/protocol/durability_level.hxx +2 -2
  166. data/ext/couchbase/protocol/frame_info_id.hxx +4 -4
  167. data/ext/couchbase/protocol/hello_feature.hxx +2 -2
  168. data/ext/couchbase/protocol/magic.hxx +2 -2
  169. data/ext/couchbase/protocol/server_opcode.hxx +2 -2
  170. data/ext/couchbase/protocol/server_request.hxx +1 -1
  171. data/ext/couchbase/protocol/status.hxx +4 -7
  172. data/ext/couchbase/protocol/unsigned_leb128.h +5 -20
  173. data/ext/couchbase/service_type.hxx +4 -4
  174. data/ext/couchbase/tracing/constants.hxx +261 -0
  175. data/ext/couchbase/tracing/noop_tracer.hxx +50 -0
  176. data/ext/couchbase/tracing/request_tracer.hxx +77 -0
  177. data/ext/couchbase/tracing/threshold_logging_options.hxx +64 -0
  178. data/ext/couchbase/tracing/threshold_logging_tracer.hxx +366 -0
  179. data/ext/couchbase/utils/byteswap.hxx +1 -1
  180. data/ext/couchbase/utils/connection_string.hxx +21 -1
  181. data/ext/couchbase/utils/name_codec.hxx +41 -0
  182. data/ext/couchbase/utils/url_codec.hxx +236 -0
  183. data/ext/couchbase/version.hxx +1 -1
  184. data/ext/test/CMakeLists.txt +1 -0
  185. data/ext/test/test_native_trivial_query.cxx +60 -0
  186. data/ext/third_party/hdr_histogram_c/CMakeLists.txt +84 -0
  187. data/ext/third_party/hdr_histogram_c/COPYING.txt +121 -0
  188. data/ext/third_party/hdr_histogram_c/LICENSE.txt +41 -0
  189. data/ext/third_party/hdr_histogram_c/config.cmake.in +6 -0
  190. data/ext/third_party/hdr_histogram_c/src/CMakeLists.txt +83 -0
  191. data/ext/third_party/hdr_histogram_c/src/hdr_atomic.h +146 -0
  192. data/ext/third_party/hdr_histogram_c/src/hdr_encoding.c +322 -0
  193. data/ext/third_party/hdr_histogram_c/src/hdr_encoding.h +79 -0
  194. data/ext/third_party/hdr_histogram_c/src/hdr_endian.h +116 -0
  195. data/ext/third_party/hdr_histogram_c/src/hdr_histogram.c +1196 -0
  196. data/ext/third_party/hdr_histogram_c/src/hdr_histogram.h +516 -0
  197. data/ext/third_party/hdr_histogram_c/src/hdr_histogram_log.c +1290 -0
  198. data/ext/third_party/hdr_histogram_c/src/hdr_histogram_log.h +236 -0
  199. data/ext/third_party/hdr_histogram_c/src/hdr_histogram_log_no_op.c +171 -0
  200. data/ext/third_party/hdr_histogram_c/src/hdr_interval_recorder.c +227 -0
  201. data/ext/third_party/hdr_histogram_c/src/hdr_interval_recorder.h +109 -0
  202. data/ext/third_party/hdr_histogram_c/src/hdr_malloc.h +19 -0
  203. data/ext/third_party/hdr_histogram_c/src/hdr_tests.h +22 -0
  204. data/ext/third_party/hdr_histogram_c/src/hdr_thread.c +108 -0
  205. data/ext/third_party/hdr_histogram_c/src/hdr_thread.h +55 -0
  206. data/ext/third_party/hdr_histogram_c/src/hdr_time.c +98 -0
  207. data/ext/third_party/hdr_histogram_c/src/hdr_time.h +49 -0
  208. data/ext/third_party/hdr_histogram_c/src/hdr_writer_reader_phaser.c +143 -0
  209. data/ext/third_party/hdr_histogram_c/src/hdr_writer_reader_phaser.h +51 -0
  210. data/lib/couchbase/cluster.rb +1 -0
  211. data/lib/couchbase/errors.rb +3 -0
  212. data/lib/couchbase/libcouchbase.bundle +0 -0
  213. data/lib/couchbase/management/analytics_index_manager.rb +920 -226
  214. data/lib/couchbase/management/bucket_manager.rb +207 -69
  215. data/lib/couchbase/management/collection_manager.rb +173 -61
  216. data/lib/couchbase/management/query_index_manager.rb +357 -169
  217. data/lib/couchbase/options.rb +75 -3
  218. data/lib/couchbase/scope.rb +102 -0
  219. data/lib/couchbase/utils/time.rb +4 -0
  220. data/lib/couchbase/version.rb +6 -6
  221. metadata +48 -5
@@ -0,0 +1,79 @@
1
+ /**
2
+ * hdr_encoding.h
3
+ * Written by Michael Barker and released to the public domain,
4
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/
5
+ */
6
+
7
+ #ifndef HDR_ENCODING_H
8
+ #define HDR_ENCODING_H
9
+
10
+ #include <stdint.h>
11
+
12
+ #define MAX_BYTES_LEB128 9
13
+
14
+ #ifdef __cplusplus
15
+ extern "C" {
16
+ #endif
17
+
18
+ /**
19
+ * Writes a int64_t value to the given buffer in LEB128 ZigZag encoded format
20
+ *
21
+ * @param buffer the buffer to write to
22
+ * @param signed_value the value to write to the buffer
23
+ * @return the number of bytes written to the buffer
24
+ */
25
+ int zig_zag_encode_i64(uint8_t* buffer, int64_t signed_value);
26
+
27
+ /**
28
+ * Read an LEB128 ZigZag encoded long value from the given buffer
29
+ *
30
+ * @param buffer the buffer to read from
31
+ * @param retVal out value to capture the read value
32
+ * @return the number of bytes read from the buffer
33
+ */
34
+ int zig_zag_decode_i64(const uint8_t* buffer, int64_t* signed_value);
35
+
36
+ /**
37
+ * Gets the length in bytes of base64 data, given the input size.
38
+ *
39
+ * @param decoded_size the size of the unencoded values.
40
+ * @return the encoded size
41
+ */
42
+ size_t hdr_base64_encoded_len(size_t decoded_size);
43
+
44
+ /**
45
+ * Encode into base64.
46
+ *
47
+ * @param input the data to encode
48
+ * @param input_len the length of the data to encode
49
+ * @param output the buffer to write the output to
50
+ * @param output_len the number of bytes to write to the output
51
+ */
52
+ int hdr_base64_encode(
53
+ const uint8_t* input, size_t input_len, char* output, size_t output_len);
54
+
55
+ /**
56
+ * Gets the length in bytes of decoded base64 data, given the size of the base64 encoded
57
+ * data.
58
+ *
59
+ * @param encoded_size the size of the encoded value.
60
+ * @return the decoded size
61
+ */
62
+ size_t hdr_base64_decoded_len(size_t encoded_size);
63
+
64
+ /**
65
+ * Decode from base64.
66
+ *
67
+ * @param input the base64 encoded data
68
+ * @param input_len the size in bytes of the endcoded data
69
+ * @param output the buffer to write the decoded data to
70
+ * @param output_len the number of bytes to write to the output data
71
+ */
72
+ int hdr_base64_decode(
73
+ const char* input, size_t input_len, uint8_t* output, size_t output_len);
74
+
75
+ #ifdef __cplusplus
76
+ }
77
+ #endif
78
+
79
+ #endif /* HDR_HISTOGRAM_HDR_ENCODING_H */
@@ -0,0 +1,116 @@
1
+ /**
2
+ * hdr_time.h
3
+ * Released to the public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/
4
+ */
5
+
6
+ #ifndef HDR_ENDIAN_H__
7
+ #define HDR_ENDIAN_H__
8
+
9
+ #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
10
+
11
+ # define __WINDOWS__
12
+
13
+ #endif
14
+
15
+ #if defined(__linux__) || defined(__CYGWIN__)
16
+
17
+ # include <endian.h>
18
+
19
+ #elif defined(__APPLE__)
20
+
21
+ # include <libkern/OSByteOrder.h>
22
+
23
+ # define htobe16(x) OSSwapHostToBigInt16(x)
24
+ # define htole16(x) OSSwapHostToLittleInt16(x)
25
+ # define be16toh(x) OSSwapBigToHostInt16(x)
26
+ # define le16toh(x) OSSwapLittleToHostInt16(x)
27
+
28
+ # define htobe32(x) OSSwapHostToBigInt32(x)
29
+ # define htole32(x) OSSwapHostToLittleInt32(x)
30
+ # define be32toh(x) OSSwapBigToHostInt32(x)
31
+ # define le32toh(x) OSSwapLittleToHostInt32(x)
32
+
33
+ # define htobe64(x) OSSwapHostToBigInt64(x)
34
+ # define htole64(x) OSSwapHostToLittleInt64(x)
35
+ # define be64toh(x) OSSwapBigToHostInt64(x)
36
+ # define le64toh(x) OSSwapLittleToHostInt64(x)
37
+
38
+ # define __BYTE_ORDER BYTE_ORDER
39
+ # define __BIG_ENDIAN BIG_ENDIAN
40
+ # define __LITTLE_ENDIAN LITTLE_ENDIAN
41
+ # define __PDP_ENDIAN PDP_ENDIAN
42
+
43
+ #elif defined(__OpenBSD__)
44
+
45
+ # include <sys/endian.h>
46
+
47
+ #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
48
+
49
+ # include <sys/endian.h>
50
+
51
+ # define be16toh(x) betoh16(x)
52
+ # define le16toh(x) letoh16(x)
53
+
54
+ # define be32toh(x) betoh32(x)
55
+ # define le32toh(x) letoh32(x)
56
+
57
+ # define be64toh(x) betoh64(x)
58
+ # define le64toh(x) letoh64(x)
59
+
60
+ #elif defined(__WINDOWS__)
61
+
62
+ # include <winsock2.h>
63
+
64
+ # if BYTE_ORDER == LITTLE_ENDIAN
65
+
66
+ # define htobe16(x) htons(x)
67
+ # define htole16(x) (x)
68
+ # define be16toh(x) ntohs(x)
69
+ # define le16toh(x) (x)
70
+
71
+ # define htobe32(x) htonl(x)
72
+ # define htole32(x) (x)
73
+ # define be32toh(x) ntohl(x)
74
+ # define le32toh(x) (x)
75
+
76
+ # define htobe64(x) htonll(x)
77
+ # define htole64(x) (x)
78
+ # define be64toh(x) ntohll(x)
79
+ # define le64toh(x) (x)
80
+
81
+ # elif BYTE_ORDER == BIG_ENDIAN
82
+
83
+ /* that would be xbox 360 */
84
+ # define htobe16(x) (x)
85
+ # define htole16(x) __builtin_bswap16(x)
86
+ # define be16toh(x) (x)
87
+ # define le16toh(x) __builtin_bswap16(x)
88
+
89
+ # define htobe32(x) (x)
90
+ # define htole32(x) __builtin_bswap32(x)
91
+ # define be32toh(x) (x)
92
+ # define le32toh(x) __builtin_bswap32(x)
93
+
94
+ # define htobe64(x) (x)
95
+ # define htole64(x) __builtin_bswap64(x)
96
+ # define be64toh(x) (x)
97
+ # define le64toh(x) __builtin_bswap64(x)
98
+
99
+ # else
100
+
101
+ # error byte order not supported
102
+
103
+ # endif
104
+
105
+ # define __BYTE_ORDER BYTE_ORDER
106
+ # define __BIG_ENDIAN BIG_ENDIAN
107
+ # define __LITTLE_ENDIAN LITTLE_ENDIAN
108
+ # define __PDP_ENDIAN PDP_ENDIAN
109
+
110
+ #else
111
+
112
+ # error platform not supported
113
+
114
+ #endif
115
+
116
+ #endif
@@ -0,0 +1,1196 @@
1
+ /**
2
+ * hdr_histogram.c
3
+ * Written by Michael Barker and released to the public domain,
4
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/
5
+ */
6
+
7
+ #include <stdlib.h>
8
+ #include <stdbool.h>
9
+ #include <math.h>
10
+ #include <stdio.h>
11
+ #include <string.h>
12
+ #include <stdint.h>
13
+ #include <errno.h>
14
+ #include <inttypes.h>
15
+
16
+ #include "hdr_histogram.h"
17
+ #include "hdr_tests.h"
18
+ #include "hdr_atomic.h"
19
+
20
+ #ifndef HDR_MALLOC_INCLUDE
21
+ #define HDR_MALLOC_INCLUDE "hdr_malloc.h"
22
+ #endif
23
+
24
+ #include HDR_MALLOC_INCLUDE
25
+
26
+ /* ###### ####### ## ## ## ## ######## ###### */
27
+ /* ## ## ## ## ## ## ### ## ## ## ## */
28
+ /* ## ## ## ## ## #### ## ## ## */
29
+ /* ## ## ## ## ## ## ## ## ## ###### */
30
+ /* ## ## ## ## ## ## #### ## ## */
31
+ /* ## ## ## ## ## ## ## ### ## ## ## */
32
+ /* ###### ####### ####### ## ## ## ###### */
33
+
34
+ static int32_t normalize_index(const struct hdr_histogram* h, int32_t index)
35
+ {
36
+ int32_t normalized_index;
37
+ int32_t adjustment = 0;
38
+ if (h->normalizing_index_offset == 0)
39
+ {
40
+ return index;
41
+ }
42
+
43
+ normalized_index = index - h->normalizing_index_offset;
44
+
45
+ if (normalized_index < 0)
46
+ {
47
+ adjustment = h->counts_len;
48
+ }
49
+ else if (normalized_index >= h->counts_len)
50
+ {
51
+ adjustment = -h->counts_len;
52
+ }
53
+
54
+ return normalized_index + adjustment;
55
+ }
56
+
57
+ static int64_t counts_get_direct(const struct hdr_histogram* h, int32_t index)
58
+ {
59
+ return h->counts[index];
60
+ }
61
+
62
+ static int64_t counts_get_normalised(const struct hdr_histogram* h, int32_t index)
63
+ {
64
+ return counts_get_direct(h, normalize_index(h, index));
65
+ }
66
+
67
+ static void counts_inc_normalised(
68
+ struct hdr_histogram* h, int32_t index, int64_t value)
69
+ {
70
+ int32_t normalised_index = normalize_index(h, index);
71
+ h->counts[normalised_index] += value;
72
+ h->total_count += value;
73
+ }
74
+
75
+ static void counts_inc_normalised_atomic(
76
+ struct hdr_histogram* h, int32_t index, int64_t value)
77
+ {
78
+ int32_t normalised_index = normalize_index(h, index);
79
+
80
+ hdr_atomic_add_fetch_64(&h->counts[normalised_index], value);
81
+ hdr_atomic_add_fetch_64(&h->total_count, value);
82
+ }
83
+
84
+ static void update_min_max(struct hdr_histogram* h, int64_t value)
85
+ {
86
+ h->min_value = (value < h->min_value && value != 0) ? value : h->min_value;
87
+ h->max_value = (value > h->max_value) ? value : h->max_value;
88
+ }
89
+
90
+ static void update_min_max_atomic(struct hdr_histogram* h, int64_t value)
91
+ {
92
+ int64_t current_min_value;
93
+ int64_t current_max_value;
94
+ do
95
+ {
96
+ current_min_value = hdr_atomic_load_64(&h->min_value);
97
+
98
+ if (0 == value || current_min_value <= value)
99
+ {
100
+ break;
101
+ }
102
+ }
103
+ while (!hdr_atomic_compare_exchange_64(&h->min_value, &current_min_value, value));
104
+
105
+ do
106
+ {
107
+ current_max_value = hdr_atomic_load_64(&h->max_value);
108
+
109
+ if (value <= current_max_value)
110
+ {
111
+ break;
112
+ }
113
+ }
114
+ while (!hdr_atomic_compare_exchange_64(&h->max_value, &current_max_value, value));
115
+ }
116
+
117
+
118
+ /* ## ## ######## #### ## #### ######## ## ## */
119
+ /* ## ## ## ## ## ## ## ## ## */
120
+ /* ## ## ## ## ## ## ## #### */
121
+ /* ## ## ## ## ## ## ## ## */
122
+ /* ## ## ## ## ## ## ## ## */
123
+ /* ## ## ## ## ## ## ## ## */
124
+ /* ####### ## #### ######## #### ## ## */
125
+
126
+ static int64_t power(int64_t base, int64_t exp)
127
+ {
128
+ int64_t result = 1;
129
+ while(exp)
130
+ {
131
+ result *= base; exp--;
132
+ }
133
+ return result;
134
+ }
135
+
136
+ #if defined(_MSC_VER)
137
+ # if defined(_WIN64)
138
+ # pragma intrinsic(_BitScanReverse64)
139
+ # else
140
+ # pragma intrinsic(_BitScanReverse)
141
+ # endif
142
+ #endif
143
+
144
+ static int32_t count_leading_zeros_64(int64_t value)
145
+ {
146
+ #if defined(_MSC_VER)
147
+ uint32_t leading_zero = 0;
148
+ #if defined(_WIN64)
149
+ _BitScanReverse64(&leading_zero, value);
150
+ #else
151
+ uint32_t high = value >> 32;
152
+ if (_BitScanReverse(&leading_zero, high))
153
+ {
154
+ leading_zero += 32;
155
+ }
156
+ else
157
+ {
158
+ uint32_t low = value & 0x00000000FFFFFFFF;
159
+ _BitScanReverse(&leading_zero, low);
160
+ }
161
+ #endif
162
+ return 63 - leading_zero; /* smallest power of 2 containing value */
163
+ #else
164
+ return __builtin_clzll(value); /* smallest power of 2 containing value */
165
+ #endif
166
+ }
167
+
168
+ static int32_t get_bucket_index(const struct hdr_histogram* h, int64_t value)
169
+ {
170
+ int32_t pow2ceiling = 64 - count_leading_zeros_64(value | h->sub_bucket_mask); /* smallest power of 2 containing value */
171
+ return pow2ceiling - h->unit_magnitude - (h->sub_bucket_half_count_magnitude + 1);
172
+ }
173
+
174
+ static int32_t get_sub_bucket_index(int64_t value, int32_t bucket_index, int32_t unit_magnitude)
175
+ {
176
+ return (int32_t)(value >> (bucket_index + unit_magnitude));
177
+ }
178
+
179
+ static int32_t counts_index(const struct hdr_histogram* h, int32_t bucket_index, int32_t sub_bucket_index)
180
+ {
181
+ /* Calculate the index for the first entry in the bucket: */
182
+ /* (The following is the equivalent of ((bucket_index + 1) * subBucketHalfCount) ): */
183
+ int32_t bucket_base_index = (bucket_index + 1) << h->sub_bucket_half_count_magnitude;
184
+ /* Calculate the offset in the bucket: */
185
+ int32_t offset_in_bucket = sub_bucket_index - h->sub_bucket_half_count;
186
+ /* The following is the equivalent of ((sub_bucket_index - subBucketHalfCount) + bucketBaseIndex; */
187
+ return bucket_base_index + offset_in_bucket;
188
+ }
189
+
190
+ static int64_t value_from_index(int32_t bucket_index, int32_t sub_bucket_index, int32_t unit_magnitude)
191
+ {
192
+ return ((int64_t) sub_bucket_index) << (bucket_index + unit_magnitude);
193
+ }
194
+
195
+ int32_t counts_index_for(const struct hdr_histogram* h, int64_t value)
196
+ {
197
+ int32_t bucket_index = get_bucket_index(h, value);
198
+ int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, h->unit_magnitude);
199
+
200
+ return counts_index(h, bucket_index, sub_bucket_index);
201
+ }
202
+
203
+ int64_t hdr_value_at_index(const struct hdr_histogram *h, int32_t index)
204
+ {
205
+ int32_t bucket_index = (index >> h->sub_bucket_half_count_magnitude) - 1;
206
+ int32_t sub_bucket_index = (index & (h->sub_bucket_half_count - 1)) + h->sub_bucket_half_count;
207
+
208
+ if (bucket_index < 0)
209
+ {
210
+ sub_bucket_index -= h->sub_bucket_half_count;
211
+ bucket_index = 0;
212
+ }
213
+
214
+ return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude);
215
+ }
216
+
217
+ int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_t value)
218
+ {
219
+ int32_t bucket_index = get_bucket_index(h, value);
220
+ int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, h->unit_magnitude);
221
+ int32_t adjusted_bucket = (sub_bucket_index >= h->sub_bucket_count) ? (bucket_index + 1) : bucket_index;
222
+ return INT64_C(1) << (h->unit_magnitude + adjusted_bucket);
223
+ }
224
+
225
+ static int64_t lowest_equivalent_value(const struct hdr_histogram* h, int64_t value)
226
+ {
227
+ int32_t bucket_index = get_bucket_index(h, value);
228
+ int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, h->unit_magnitude);
229
+ return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude);
230
+ }
231
+
232
+ int64_t hdr_next_non_equivalent_value(const struct hdr_histogram *h, int64_t value)
233
+ {
234
+ return lowest_equivalent_value(h, value) + hdr_size_of_equivalent_value_range(h, value);
235
+ }
236
+
237
+ static int64_t highest_equivalent_value(const struct hdr_histogram* h, int64_t value)
238
+ {
239
+ return hdr_next_non_equivalent_value(h, value) - 1;
240
+ }
241
+
242
+ int64_t hdr_median_equivalent_value(const struct hdr_histogram *h, int64_t value)
243
+ {
244
+ return lowest_equivalent_value(h, value) + (hdr_size_of_equivalent_value_range(h, value) >> 1);
245
+ }
246
+
247
+ static int64_t non_zero_min(const struct hdr_histogram* h)
248
+ {
249
+ if (INT64_MAX == h->min_value)
250
+ {
251
+ return INT64_MAX;
252
+ }
253
+
254
+ return lowest_equivalent_value(h, h->min_value);
255
+ }
256
+
257
+ void hdr_reset_internal_counters(struct hdr_histogram* h)
258
+ {
259
+ int min_non_zero_index = -1;
260
+ int max_index = -1;
261
+ int64_t observed_total_count = 0;
262
+ int i;
263
+
264
+ for (i = 0; i < h->counts_len; i++)
265
+ {
266
+ int64_t count_at_index;
267
+
268
+ if ((count_at_index = counts_get_direct(h, i)) > 0)
269
+ {
270
+ observed_total_count += count_at_index;
271
+ max_index = i;
272
+ if (min_non_zero_index == -1 && i != 0)
273
+ {
274
+ min_non_zero_index = i;
275
+ }
276
+ }
277
+ }
278
+
279
+ if (max_index == -1)
280
+ {
281
+ h->max_value = 0;
282
+ }
283
+ else
284
+ {
285
+ int64_t max_value = hdr_value_at_index(h, max_index);
286
+ h->max_value = highest_equivalent_value(h, max_value);
287
+ }
288
+
289
+ if (min_non_zero_index == -1)
290
+ {
291
+ h->min_value = INT64_MAX;
292
+ }
293
+ else
294
+ {
295
+ h->min_value = hdr_value_at_index(h, min_non_zero_index);
296
+ }
297
+
298
+ h->total_count = observed_total_count;
299
+ }
300
+
301
+ static int32_t buckets_needed_to_cover_value(int64_t value, int32_t sub_bucket_count, int32_t unit_magnitude)
302
+ {
303
+ int64_t smallest_untrackable_value = ((int64_t) sub_bucket_count) << unit_magnitude;
304
+ int32_t buckets_needed = 1;
305
+ while (smallest_untrackable_value <= value)
306
+ {
307
+ if (smallest_untrackable_value > INT64_MAX / 2)
308
+ {
309
+ return buckets_needed + 1;
310
+ }
311
+ smallest_untrackable_value <<= 1;
312
+ buckets_needed++;
313
+ }
314
+
315
+ return buckets_needed;
316
+ }
317
+
318
+ /* ## ## ######## ## ## ####### ######## ## ## */
319
+ /* ### ### ## ### ### ## ## ## ## ## ## */
320
+ /* #### #### ## #### #### ## ## ## ## #### */
321
+ /* ## ### ## ###### ## ### ## ## ## ######## ## */
322
+ /* ## ## ## ## ## ## ## ## ## ## */
323
+ /* ## ## ## ## ## ## ## ## ## ## */
324
+ /* ## ## ######## ## ## ####### ## ## ## */
325
+
326
+ int hdr_calculate_bucket_config(
327
+ int64_t lowest_discernible_value,
328
+ int64_t highest_trackable_value,
329
+ int significant_figures,
330
+ struct hdr_histogram_bucket_config* cfg)
331
+ {
332
+ int32_t sub_bucket_count_magnitude;
333
+ int64_t largest_value_with_single_unit_resolution;
334
+
335
+ if (lowest_discernible_value < 1 ||
336
+ significant_figures < 1 || 5 < significant_figures ||
337
+ lowest_discernible_value * 2 > highest_trackable_value)
338
+ {
339
+ return EINVAL;
340
+ }
341
+
342
+ cfg->lowest_discernible_value = lowest_discernible_value;
343
+ cfg->significant_figures = significant_figures;
344
+ cfg->highest_trackable_value = highest_trackable_value;
345
+
346
+ largest_value_with_single_unit_resolution = 2 * power(10, significant_figures);
347
+ sub_bucket_count_magnitude = (int32_t) ceil(log((double)largest_value_with_single_unit_resolution) / log(2));
348
+ cfg->sub_bucket_half_count_magnitude = ((sub_bucket_count_magnitude > 1) ? sub_bucket_count_magnitude : 1) - 1;
349
+
350
+ double unit_magnitude = log((double)lowest_discernible_value) / log(2);
351
+ if (INT32_MAX < unit_magnitude)
352
+ {
353
+ return EINVAL;
354
+ }
355
+
356
+ cfg->unit_magnitude = (int32_t) unit_magnitude;
357
+ cfg->sub_bucket_count = (int32_t) pow(2, (cfg->sub_bucket_half_count_magnitude + 1));
358
+ cfg->sub_bucket_half_count = cfg->sub_bucket_count / 2;
359
+ cfg->sub_bucket_mask = ((int64_t) cfg->sub_bucket_count - 1) << cfg->unit_magnitude;
360
+
361
+ if (cfg->unit_magnitude + cfg->sub_bucket_half_count_magnitude > 61)
362
+ {
363
+ return EINVAL;
364
+ }
365
+
366
+ cfg->bucket_count = buckets_needed_to_cover_value(highest_trackable_value, cfg->sub_bucket_count, (int32_t)cfg->unit_magnitude);
367
+ cfg->counts_len = (cfg->bucket_count + 1) * (cfg->sub_bucket_count / 2);
368
+
369
+ return 0;
370
+ }
371
+
372
+ void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg)
373
+ {
374
+ h->lowest_discernible_value = cfg->lowest_discernible_value;
375
+ h->highest_trackable_value = cfg->highest_trackable_value;
376
+ h->unit_magnitude = (int32_t)cfg->unit_magnitude;
377
+ h->significant_figures = (int32_t)cfg->significant_figures;
378
+ h->sub_bucket_half_count_magnitude = cfg->sub_bucket_half_count_magnitude;
379
+ h->sub_bucket_half_count = cfg->sub_bucket_half_count;
380
+ h->sub_bucket_mask = cfg->sub_bucket_mask;
381
+ h->sub_bucket_count = cfg->sub_bucket_count;
382
+ h->min_value = INT64_MAX;
383
+ h->max_value = 0;
384
+ h->normalizing_index_offset = 0;
385
+ h->conversion_ratio = 1.0;
386
+ h->bucket_count = cfg->bucket_count;
387
+ h->counts_len = cfg->counts_len;
388
+ h->total_count = 0;
389
+ }
390
+
391
+ int hdr_init(
392
+ int64_t lowest_discernible_value,
393
+ int64_t highest_trackable_value,
394
+ int significant_figures,
395
+ struct hdr_histogram** result)
396
+ {
397
+ int64_t* counts;
398
+ struct hdr_histogram_bucket_config cfg;
399
+ struct hdr_histogram* histogram;
400
+
401
+ int r = hdr_calculate_bucket_config(lowest_discernible_value, highest_trackable_value, significant_figures, &cfg);
402
+ if (r)
403
+ {
404
+ return r;
405
+ }
406
+
407
+ counts = (int64_t*) hdr_calloc((size_t) cfg.counts_len, sizeof(int64_t));
408
+ if (!counts)
409
+ {
410
+ return ENOMEM;
411
+ }
412
+
413
+ histogram = (struct hdr_histogram*) hdr_calloc(1, sizeof(struct hdr_histogram));
414
+ if (!histogram)
415
+ {
416
+ hdr_free(counts);
417
+ return ENOMEM;
418
+ }
419
+
420
+ histogram->counts = counts;
421
+
422
+ hdr_init_preallocated(histogram, &cfg);
423
+ *result = histogram;
424
+
425
+ return 0;
426
+ }
427
+
428
+ void hdr_close(struct hdr_histogram* h)
429
+ {
430
+ if (h) {
431
+ hdr_free(h->counts);
432
+ hdr_free(h);
433
+ }
434
+ }
435
+
436
+ int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result)
437
+ {
438
+ return hdr_init(1, highest_trackable_value, significant_figures, result);
439
+ }
440
+
441
+ /* reset a histogram to zero. */
442
+ void hdr_reset(struct hdr_histogram *h)
443
+ {
444
+ h->total_count=0;
445
+ h->min_value = INT64_MAX;
446
+ h->max_value = 0;
447
+ memset(h->counts, 0, (sizeof(int64_t) * h->counts_len));
448
+ }
449
+
450
+ size_t hdr_get_memory_size(struct hdr_histogram *h)
451
+ {
452
+ return sizeof(struct hdr_histogram) + h->counts_len * sizeof(int64_t);
453
+ }
454
+
455
+ /* ## ## ######## ######## ### ######## ######## ###### */
456
+ /* ## ## ## ## ## ## ## ## ## ## ## ## */
457
+ /* ## ## ## ## ## ## ## ## ## ## ## */
458
+ /* ## ## ######## ## ## ## ## ## ###### ###### */
459
+ /* ## ## ## ## ## ######### ## ## ## */
460
+ /* ## ## ## ## ## ## ## ## ## ## ## */
461
+ /* ####### ## ######## ## ## ## ######## ###### */
462
+
463
+
464
+ bool hdr_record_value(struct hdr_histogram* h, int64_t value)
465
+ {
466
+ return hdr_record_values(h, value, 1);
467
+ }
468
+
469
+ bool hdr_record_value_atomic(struct hdr_histogram* h, int64_t value)
470
+ {
471
+ return hdr_record_values_atomic(h, value, 1);
472
+ }
473
+
474
+ bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count)
475
+ {
476
+ int32_t counts_index;
477
+
478
+ if (value < 0)
479
+ {
480
+ return false;
481
+ }
482
+
483
+ counts_index = counts_index_for(h, value);
484
+
485
+ if (counts_index < 0 || h->counts_len <= counts_index)
486
+ {
487
+ return false;
488
+ }
489
+
490
+ counts_inc_normalised(h, counts_index, count);
491
+ update_min_max(h, value);
492
+
493
+ return true;
494
+ }
495
+
496
+ bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count)
497
+ {
498
+ int32_t counts_index;
499
+
500
+ if (value < 0)
501
+ {
502
+ return false;
503
+ }
504
+
505
+ counts_index = counts_index_for(h, value);
506
+
507
+ if (counts_index < 0 || h->counts_len <= counts_index)
508
+ {
509
+ return false;
510
+ }
511
+
512
+ counts_inc_normalised_atomic(h, counts_index, count);
513
+ update_min_max_atomic(h, value);
514
+
515
+ return true;
516
+ }
517
+
518
+ bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expected_interval)
519
+ {
520
+ return hdr_record_corrected_values(h, value, 1, expected_interval);
521
+ }
522
+
523
+ bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expected_interval)
524
+ {
525
+ return hdr_record_corrected_values_atomic(h, value, 1, expected_interval);
526
+ }
527
+
528
+ bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval)
529
+ {
530
+ int64_t missing_value;
531
+
532
+ if (!hdr_record_values(h, value, count))
533
+ {
534
+ return false;
535
+ }
536
+
537
+ if (expected_interval <= 0 || value <= expected_interval)
538
+ {
539
+ return true;
540
+ }
541
+
542
+ missing_value = value - expected_interval;
543
+ for (; missing_value >= expected_interval; missing_value -= expected_interval)
544
+ {
545
+ if (!hdr_record_values(h, missing_value, count))
546
+ {
547
+ return false;
548
+ }
549
+ }
550
+
551
+ return true;
552
+ }
553
+
554
+ bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval)
555
+ {
556
+ int64_t missing_value;
557
+
558
+ if (!hdr_record_values_atomic(h, value, count))
559
+ {
560
+ return false;
561
+ }
562
+
563
+ if (expected_interval <= 0 || value <= expected_interval)
564
+ {
565
+ return true;
566
+ }
567
+
568
+ missing_value = value - expected_interval;
569
+ for (; missing_value >= expected_interval; missing_value -= expected_interval)
570
+ {
571
+ if (!hdr_record_values_atomic(h, missing_value, count))
572
+ {
573
+ return false;
574
+ }
575
+ }
576
+
577
+ return true;
578
+ }
579
+
580
+ int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from)
581
+ {
582
+ struct hdr_iter iter;
583
+ int64_t dropped = 0;
584
+ hdr_iter_recorded_init(&iter, from);
585
+
586
+ while (hdr_iter_next(&iter))
587
+ {
588
+ int64_t value = iter.value;
589
+ int64_t count = iter.count;
590
+
591
+ if (!hdr_record_values(h, value, count))
592
+ {
593
+ dropped += count;
594
+ }
595
+ }
596
+
597
+ return dropped;
598
+ }
599
+
600
+ int64_t hdr_add_while_correcting_for_coordinated_omission(
601
+ struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval)
602
+ {
603
+ struct hdr_iter iter;
604
+ int64_t dropped = 0;
605
+ hdr_iter_recorded_init(&iter, from);
606
+
607
+ while (hdr_iter_next(&iter))
608
+ {
609
+ int64_t value = iter.value;
610
+ int64_t count = iter.count;
611
+
612
+ if (!hdr_record_corrected_values(h, value, count, expected_interval))
613
+ {
614
+ dropped += count;
615
+ }
616
+ }
617
+
618
+ return dropped;
619
+ }
620
+
621
+
622
+
623
+ /* ## ## ### ## ## ## ######## ###### */
624
+ /* ## ## ## ## ## ## ## ## ## ## */
625
+ /* ## ## ## ## ## ## ## ## ## */
626
+ /* ## ## ## ## ## ## ## ###### ###### */
627
+ /* ## ## ######### ## ## ## ## ## */
628
+ /* ## ## ## ## ## ## ## ## ## ## */
629
+ /* ### ## ## ######## ####### ######## ###### */
630
+
631
+
632
+ int64_t hdr_max(const struct hdr_histogram* h)
633
+ {
634
+ if (0 == h->max_value)
635
+ {
636
+ return 0;
637
+ }
638
+
639
+ return highest_equivalent_value(h, h->max_value);
640
+ }
641
+
642
+ int64_t hdr_min(const struct hdr_histogram* h)
643
+ {
644
+ if (0 < hdr_count_at_index(h, 0))
645
+ {
646
+ return 0;
647
+ }
648
+
649
+ return non_zero_min(h);
650
+ }
651
+
652
+ int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile)
653
+ {
654
+ struct hdr_iter iter;
655
+ int64_t total = 0;
656
+ double requested_percentile = percentile < 100.0 ? percentile : 100.0;
657
+ int64_t count_at_percentile =
658
+ (int64_t) (((requested_percentile / 100) * h->total_count) + 0.5);
659
+ count_at_percentile = count_at_percentile > 1 ? count_at_percentile : 1;
660
+
661
+ hdr_iter_init(&iter, h);
662
+
663
+ while (hdr_iter_next(&iter))
664
+ {
665
+ total += iter.count;
666
+
667
+ if (total >= count_at_percentile)
668
+ {
669
+ int64_t value_from_index = iter.value;
670
+ return highest_equivalent_value(h, value_from_index);
671
+ }
672
+ }
673
+
674
+ return 0;
675
+ }
676
+
677
+ int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length)
678
+ {
679
+ if (NULL == percentiles || NULL == values)
680
+ {
681
+ return EINVAL;
682
+ }
683
+
684
+ struct hdr_iter iter;
685
+ const int64_t total_count = h->total_count;
686
+ // to avoid allocations we use the values array for intermediate computation
687
+ // i.e. to store the expected cumulative count at each percentile
688
+ for (size_t i = 0; i < length; i++)
689
+ {
690
+ const double requested_percentile = percentiles[i] < 100.0 ? percentiles[i] : 100.0;
691
+ const int64_t count_at_percentile =
692
+ (int64_t) (((requested_percentile / 100) * total_count) + 0.5);
693
+ values[i] = count_at_percentile > 1 ? count_at_percentile : 1;
694
+ }
695
+
696
+ hdr_iter_init(&iter, h);
697
+ int64_t total = 0;
698
+ size_t at_pos = 0;
699
+ while (hdr_iter_next(&iter) && at_pos < length)
700
+ {
701
+ total += iter.count;
702
+ while (total >= values[at_pos] && at_pos < length)
703
+ {
704
+ values[at_pos] = highest_equivalent_value(h, iter.value);
705
+ at_pos++;
706
+ }
707
+ }
708
+ return 0;
709
+ }
710
+
711
+ double hdr_mean(const struct hdr_histogram* h)
712
+ {
713
+ struct hdr_iter iter;
714
+ int64_t total = 0;
715
+
716
+ hdr_iter_init(&iter, h);
717
+
718
+ while (hdr_iter_next(&iter))
719
+ {
720
+ if (0 != iter.count)
721
+ {
722
+ total += iter.count * hdr_median_equivalent_value(h, iter.value);
723
+ }
724
+ }
725
+
726
+ return (total * 1.0) / h->total_count;
727
+ }
728
+
729
+ double hdr_stddev(const struct hdr_histogram* h)
730
+ {
731
+ double mean = hdr_mean(h);
732
+ double geometric_dev_total = 0.0;
733
+
734
+ struct hdr_iter iter;
735
+ hdr_iter_init(&iter, h);
736
+
737
+ while (hdr_iter_next(&iter))
738
+ {
739
+ if (0 != iter.count)
740
+ {
741
+ double dev = (hdr_median_equivalent_value(h, iter.value) * 1.0) - mean;
742
+ geometric_dev_total += (dev * dev) * iter.count;
743
+ }
744
+ }
745
+
746
+ return sqrt(geometric_dev_total / h->total_count);
747
+ }
748
+
749
+ bool hdr_values_are_equivalent(const struct hdr_histogram* h, int64_t a, int64_t b)
750
+ {
751
+ return lowest_equivalent_value(h, a) == lowest_equivalent_value(h, b);
752
+ }
753
+
754
+ int64_t hdr_lowest_equivalent_value(const struct hdr_histogram* h, int64_t value)
755
+ {
756
+ return lowest_equivalent_value(h, value);
757
+ }
758
+
759
+ int64_t hdr_count_at_value(const struct hdr_histogram* h, int64_t value)
760
+ {
761
+ return counts_get_normalised(h, counts_index_for(h, value));
762
+ }
763
+
764
+ int64_t hdr_count_at_index(const struct hdr_histogram* h, int32_t index)
765
+ {
766
+ return counts_get_normalised(h, index);
767
+ }
768
+
769
+
770
+ /* #### ######## ######## ######## ### ######## ####### ######## ###### */
771
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
772
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## */
773
+ /* ## ## ###### ######## ## ## ## ## ## ######## ###### */
774
+ /* ## ## ## ## ## ######### ## ## ## ## ## ## */
775
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
776
+ /* #### ## ######## ## ## ## ## ## ####### ## ## ###### */
777
+
778
+
779
+ static bool has_buckets(struct hdr_iter* iter)
780
+ {
781
+ return iter->counts_index < iter->h->counts_len;
782
+ }
783
+
784
+ static bool has_next(struct hdr_iter* iter)
785
+ {
786
+ return iter->cumulative_count < iter->total_count;
787
+ }
788
+
789
+ static bool move_next(struct hdr_iter* iter)
790
+ {
791
+ iter->counts_index++;
792
+
793
+ if (!has_buckets(iter))
794
+ {
795
+ return false;
796
+ }
797
+
798
+ iter->count = counts_get_normalised(iter->h, iter->counts_index);
799
+ iter->cumulative_count += iter->count;
800
+
801
+ iter->value = hdr_value_at_index(iter->h, iter->counts_index);
802
+ iter->highest_equivalent_value = highest_equivalent_value(iter->h, iter->value);
803
+ iter->lowest_equivalent_value = lowest_equivalent_value(iter->h, iter->value);
804
+ iter->median_equivalent_value = hdr_median_equivalent_value(iter->h, iter->value);
805
+
806
+ return true;
807
+ }
808
+
809
+ static int64_t peek_next_value_from_index(struct hdr_iter* iter)
810
+ {
811
+ return hdr_value_at_index(iter->h, iter->counts_index + 1);
812
+ }
813
+
814
+ static bool next_value_greater_than_reporting_level_upper_bound(
815
+ struct hdr_iter *iter, int64_t reporting_level_upper_bound)
816
+ {
817
+ if (iter->counts_index >= iter->h->counts_len)
818
+ {
819
+ return false;
820
+ }
821
+
822
+ return peek_next_value_from_index(iter) > reporting_level_upper_bound;
823
+ }
824
+
825
+ static bool basic_iter_next(struct hdr_iter *iter)
826
+ {
827
+ if (!has_next(iter) || iter->counts_index >= iter->h->counts_len)
828
+ {
829
+ return false;
830
+ }
831
+
832
+ move_next(iter);
833
+
834
+ return true;
835
+ }
836
+
837
+ static void update_iterated_values(struct hdr_iter* iter, int64_t new_value_iterated_to)
838
+ {
839
+ iter->value_iterated_from = iter->value_iterated_to;
840
+ iter->value_iterated_to = new_value_iterated_to;
841
+ }
842
+
843
+ static bool all_values_iter_next(struct hdr_iter* iter)
844
+ {
845
+ bool result = move_next(iter);
846
+
847
+ if (result)
848
+ {
849
+ update_iterated_values(iter, iter->value);
850
+ }
851
+
852
+ return result;
853
+ }
854
+
855
+ void hdr_iter_init(struct hdr_iter* iter, const struct hdr_histogram* h)
856
+ {
857
+ iter->h = h;
858
+
859
+ iter->counts_index = -1;
860
+ iter->total_count = h->total_count;
861
+ iter->count = 0;
862
+ iter->cumulative_count = 0;
863
+ iter->value = 0;
864
+ iter->highest_equivalent_value = 0;
865
+ iter->value_iterated_from = 0;
866
+ iter->value_iterated_to = 0;
867
+
868
+ iter->_next_fp = all_values_iter_next;
869
+ }
870
+
871
+ bool hdr_iter_next(struct hdr_iter* iter)
872
+ {
873
+ return iter->_next_fp(iter);
874
+ }
875
+
876
+ /* ######## ######## ######## ###### ######## ## ## ######## #### ## ######## ###### */
877
+ /* ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## */
878
+ /* ## ## ## ## ## ## ## #### ## ## ## ## ## ## */
879
+ /* ######## ###### ######## ## ###### ## ## ## ## ## ## ###### ###### */
880
+ /* ## ## ## ## ## ## ## #### ## ## ## ## ## */
881
+ /* ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## */
882
+ /* ## ######## ## ## ###### ######## ## ## ## #### ######## ######## ###### */
883
+
884
+ static bool percentile_iter_next(struct hdr_iter* iter)
885
+ {
886
+ int64_t temp, half_distance, percentile_reporting_ticks;
887
+
888
+ struct hdr_iter_percentiles* percentiles = &iter->specifics.percentiles;
889
+
890
+ if (!has_next(iter))
891
+ {
892
+ if (percentiles->seen_last_value)
893
+ {
894
+ return false;
895
+ }
896
+
897
+ percentiles->seen_last_value = true;
898
+ percentiles->percentile = 100.0;
899
+
900
+ return true;
901
+ }
902
+
903
+ if (iter->counts_index == -1 && !basic_iter_next(iter))
904
+ {
905
+ return false;
906
+ }
907
+
908
+ do
909
+ {
910
+ double current_percentile = (100.0 * (double) iter->cumulative_count) / iter->h->total_count;
911
+ if (iter->count != 0 &&
912
+ percentiles->percentile_to_iterate_to <= current_percentile)
913
+ {
914
+ update_iterated_values(iter, highest_equivalent_value(iter->h, iter->value));
915
+
916
+ percentiles->percentile = percentiles->percentile_to_iterate_to;
917
+ temp = (int64_t)(log(100 / (100.0 - (percentiles->percentile_to_iterate_to))) / log(2)) + 1;
918
+ half_distance = (int64_t) pow(2, (double) temp);
919
+ percentile_reporting_ticks = percentiles->ticks_per_half_distance * half_distance;
920
+ percentiles->percentile_to_iterate_to += 100.0 / percentile_reporting_ticks;
921
+
922
+ return true;
923
+ }
924
+ }
925
+ while (basic_iter_next(iter));
926
+
927
+ return true;
928
+ }
929
+
930
+ void hdr_iter_percentile_init(struct hdr_iter* iter, const struct hdr_histogram* h, int32_t ticks_per_half_distance)
931
+ {
932
+ iter->h = h;
933
+
934
+ hdr_iter_init(iter, h);
935
+
936
+ iter->specifics.percentiles.seen_last_value = false;
937
+ iter->specifics.percentiles.ticks_per_half_distance = ticks_per_half_distance;
938
+ iter->specifics.percentiles.percentile_to_iterate_to = 0.0;
939
+ iter->specifics.percentiles.percentile = 0.0;
940
+
941
+ iter->_next_fp = percentile_iter_next;
942
+ }
943
+
944
+ static void format_line_string(char* str, size_t len, int significant_figures, format_type format)
945
+ {
946
+ #if defined(_MSC_VER)
947
+ #define snprintf _snprintf
948
+ #pragma warning(push)
949
+ #pragma warning(disable: 4996)
950
+ #endif
951
+ const char* format_str = "%s%d%s";
952
+
953
+ switch (format)
954
+ {
955
+ case CSV:
956
+ snprintf(str, len, format_str, "%.", significant_figures, "f,%f,%d,%.2f\n");
957
+ break;
958
+ case CLASSIC:
959
+ snprintf(str, len, format_str, "%12.", significant_figures, "f %12f %12d %12.2f\n");
960
+ break;
961
+ default:
962
+ snprintf(str, len, format_str, "%12.", significant_figures, "f %12f %12d %12.2f\n");
963
+ }
964
+ #if defined(_MSC_VER)
965
+ #undef snprintf
966
+ #pragma warning(pop)
967
+ #endif
968
+ }
969
+
970
+
971
+ /* ######## ######## ###### ####### ######## ######## ######## ######## */
972
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
973
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## */
974
+ /* ######## ###### ## ## ## ######## ## ## ###### ## ## */
975
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## */
976
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
977
+ /* ## ## ######## ###### ####### ## ## ######## ######## ######## */
978
+
979
+
980
+ static bool recorded_iter_next(struct hdr_iter* iter)
981
+ {
982
+ while (basic_iter_next(iter))
983
+ {
984
+ if (iter->count != 0)
985
+ {
986
+ update_iterated_values(iter, iter->value);
987
+
988
+ iter->specifics.recorded.count_added_in_this_iteration_step = iter->count;
989
+ return true;
990
+ }
991
+ }
992
+
993
+ return false;
994
+ }
995
+
996
+ void hdr_iter_recorded_init(struct hdr_iter* iter, const struct hdr_histogram* h)
997
+ {
998
+ hdr_iter_init(iter, h);
999
+
1000
+ iter->specifics.recorded.count_added_in_this_iteration_step = 0;
1001
+
1002
+ iter->_next_fp = recorded_iter_next;
1003
+ }
1004
+
1005
+ /* ## #### ## ## ######## ### ######## */
1006
+ /* ## ## ### ## ## ## ## ## ## */
1007
+ /* ## ## #### ## ## ## ## ## ## */
1008
+ /* ## ## ## ## ## ###### ## ## ######## */
1009
+ /* ## ## ## #### ## ######### ## ## */
1010
+ /* ## ## ## ### ## ## ## ## ## */
1011
+ /* ######## #### ## ## ######## ## ## ## ## */
1012
+
1013
+
1014
+ static bool iter_linear_next(struct hdr_iter* iter)
1015
+ {
1016
+ struct hdr_iter_linear* linear = &iter->specifics.linear;
1017
+
1018
+ linear->count_added_in_this_iteration_step = 0;
1019
+
1020
+ if (has_next(iter) ||
1021
+ next_value_greater_than_reporting_level_upper_bound(
1022
+ iter, linear->next_value_reporting_level_lowest_equivalent))
1023
+ {
1024
+ do
1025
+ {
1026
+ if (iter->value >= linear->next_value_reporting_level_lowest_equivalent)
1027
+ {
1028
+ update_iterated_values(iter, linear->next_value_reporting_level);
1029
+
1030
+ linear->next_value_reporting_level += linear->value_units_per_bucket;
1031
+ linear->next_value_reporting_level_lowest_equivalent =
1032
+ lowest_equivalent_value(iter->h, linear->next_value_reporting_level);
1033
+
1034
+ return true;
1035
+ }
1036
+
1037
+ if (!move_next(iter))
1038
+ {
1039
+ return true;
1040
+ }
1041
+
1042
+ linear->count_added_in_this_iteration_step += iter->count;
1043
+ }
1044
+ while (true);
1045
+ }
1046
+
1047
+ return false;
1048
+ }
1049
+
1050
+
1051
+ void hdr_iter_linear_init(struct hdr_iter* iter, const struct hdr_histogram* h, int64_t value_units_per_bucket)
1052
+ {
1053
+ hdr_iter_init(iter, h);
1054
+
1055
+ iter->specifics.linear.count_added_in_this_iteration_step = 0;
1056
+ iter->specifics.linear.value_units_per_bucket = value_units_per_bucket;
1057
+ iter->specifics.linear.next_value_reporting_level = value_units_per_bucket;
1058
+ iter->specifics.linear.next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(h, value_units_per_bucket);
1059
+
1060
+ iter->_next_fp = iter_linear_next;
1061
+ }
1062
+
1063
+ /* ## ####### ###### ### ######## #### ######## ## ## ## ## #### ###### */
1064
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## ### ### ## ## ## */
1065
+ /* ## ## ## ## ## ## ## ## ## ## ## ## #### #### ## ## */
1066
+ /* ## ## ## ## #### ## ## ######## ## ## ######### ## ### ## ## ## */
1067
+ /* ## ## ## ## ## ######### ## ## ## ## ## ## ## ## ## ## */
1068
+ /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
1069
+ /* ######## ####### ###### ## ## ## ## #### ## ## ## ## ## #### ###### */
1070
+
1071
+ static bool log_iter_next(struct hdr_iter *iter)
1072
+ {
1073
+ struct hdr_iter_log* logarithmic = &iter->specifics.log;
1074
+
1075
+ logarithmic->count_added_in_this_iteration_step = 0;
1076
+
1077
+ if (has_next(iter) ||
1078
+ next_value_greater_than_reporting_level_upper_bound(
1079
+ iter, logarithmic->next_value_reporting_level_lowest_equivalent))
1080
+ {
1081
+ do
1082
+ {
1083
+ if (iter->value >= logarithmic->next_value_reporting_level_lowest_equivalent)
1084
+ {
1085
+ update_iterated_values(iter, logarithmic->next_value_reporting_level);
1086
+
1087
+ logarithmic->next_value_reporting_level *= (int64_t)logarithmic->log_base;
1088
+ logarithmic->next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(iter->h, logarithmic->next_value_reporting_level);
1089
+
1090
+ return true;
1091
+ }
1092
+
1093
+ if (!move_next(iter))
1094
+ {
1095
+ return true;
1096
+ }
1097
+
1098
+ logarithmic->count_added_in_this_iteration_step += iter->count;
1099
+ }
1100
+ while (true);
1101
+ }
1102
+
1103
+ return false;
1104
+ }
1105
+
1106
+ void hdr_iter_log_init(
1107
+ struct hdr_iter* iter,
1108
+ const struct hdr_histogram* h,
1109
+ int64_t value_units_first_bucket,
1110
+ double log_base)
1111
+ {
1112
+ hdr_iter_init(iter, h);
1113
+ iter->specifics.log.count_added_in_this_iteration_step = 0;
1114
+ iter->specifics.log.log_base = log_base;
1115
+ iter->specifics.log.next_value_reporting_level = value_units_first_bucket;
1116
+ iter->specifics.log.next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(h, value_units_first_bucket);
1117
+
1118
+ iter->_next_fp = log_iter_next;
1119
+ }
1120
+
1121
+ /* Printing. */
1122
+
1123
+ static const char* format_head_string(format_type format)
1124
+ {
1125
+ switch (format)
1126
+ {
1127
+ case CSV:
1128
+ return "%s,%s,%s,%s\n";
1129
+ case CLASSIC:
1130
+ default:
1131
+ return "%12s %12s %12s %12s\n\n";
1132
+ }
1133
+ }
1134
+
1135
+ static const char CLASSIC_FOOTER[] =
1136
+ "#[Mean = %12.3f, StdDeviation = %12.3f]\n"
1137
+ "#[Max = %12.3f, Total count = %12" PRIu64 "]\n"
1138
+ "#[Buckets = %12d, SubBuckets = %12d]\n";
1139
+
1140
+ int hdr_percentiles_print(
1141
+ struct hdr_histogram* h, FILE* stream, int32_t ticks_per_half_distance,
1142
+ double value_scale, format_type format)
1143
+ {
1144
+ char line_format[25];
1145
+ const char* head_format;
1146
+ int rc = 0;
1147
+ struct hdr_iter iter;
1148
+ struct hdr_iter_percentiles * percentiles;
1149
+
1150
+ format_line_string(line_format, 25, h->significant_figures, format);
1151
+ head_format = format_head_string(format);
1152
+
1153
+ hdr_iter_percentile_init(&iter, h, ticks_per_half_distance);
1154
+
1155
+ if (fprintf(
1156
+ stream, head_format,
1157
+ "Value", "Percentile", "TotalCount", "1/(1-Percentile)") < 0)
1158
+ {
1159
+ rc = EIO;
1160
+ goto cleanup;
1161
+ }
1162
+
1163
+ percentiles = &iter.specifics.percentiles;
1164
+ while (hdr_iter_next(&iter))
1165
+ {
1166
+ double value = iter.highest_equivalent_value / value_scale;
1167
+ double percentile = percentiles->percentile / 100.0;
1168
+ int64_t total_count = iter.cumulative_count;
1169
+ double inverted_percentile = (1.0 / (1.0 - percentile));
1170
+
1171
+ if (fprintf(
1172
+ stream, line_format, value, percentile, total_count, inverted_percentile) < 0)
1173
+ {
1174
+ rc = EIO;
1175
+ goto cleanup;
1176
+ }
1177
+ }
1178
+
1179
+ if (CLASSIC == format)
1180
+ {
1181
+ double mean = hdr_mean(h) / value_scale;
1182
+ double stddev = hdr_stddev(h) / value_scale;
1183
+ double max = hdr_max(h) / value_scale;
1184
+
1185
+ if (fprintf(
1186
+ stream, CLASSIC_FOOTER, mean, stddev, max,
1187
+ h->total_count, h->bucket_count, h->sub_bucket_count) < 0)
1188
+ {
1189
+ rc = EIO;
1190
+ goto cleanup;
1191
+ }
1192
+ }
1193
+
1194
+ cleanup:
1195
+ return rc;
1196
+ }