Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a12dcea2d9 | ||
|
|
9bb439d7e8 | ||
|
|
af7257c7ce | ||
|
|
cf1e8f855b | ||
|
|
5cb8658c76 | ||
|
|
57c04d8562 | ||
|
|
6c464bc68b | ||
|
|
60cbb0f1d1 | ||
|
|
ff580de3a2 | ||
|
|
4b3e23e2fb | ||
|
|
1f0679da36 | ||
|
|
2ae3dd6b0a | ||
|
|
d591df1529 | ||
|
|
cf799eae84 | ||
|
|
5c816db669 | ||
|
|
7bbd6d73c8 | ||
|
|
0d5b349744 | ||
|
|
ccf8d42e4b | ||
|
|
93a748f86b | ||
|
|
3e774999e7 | ||
|
|
83563f6bb2 | ||
|
|
875a82bdf8 | ||
|
|
1e3fe8cab3 | ||
|
|
127becc9e0 | ||
|
|
b57b1c8ff8 | ||
|
|
bb83aef1da | ||
|
|
cbb9ac38d2 | ||
|
|
6749c2bcf0 | ||
|
|
9957c11e2d | ||
|
|
b4b30dcf9d | ||
|
|
cddd3b6896 | ||
|
|
b4528b797d | ||
|
|
e070651039 | ||
|
|
7a32ec39fd | ||
|
|
50dfee2039 | ||
|
|
9e92c038b8 | ||
|
|
c167902cbf | ||
|
|
c8bd5dbb4f | ||
|
|
2c932d7b80 | ||
|
|
8dff4f3437 | ||
|
|
eec6b5142e | ||
|
|
d2c080d923 | ||
|
|
754d5a3ba1 | ||
|
|
4aaa7b7bd7 | ||
|
|
b93938914d | ||
|
|
4b6bdcbcce | ||
|
|
31c0e38d86 | ||
|
|
8f5b94c75f | ||
|
|
d1fc7b96ed | ||
|
|
b253a7aa8d | ||
|
|
1625c74a36 | ||
|
|
3c716ee33d | ||
|
|
b03eab2a06 | ||
|
|
6a0a005ff2 | ||
|
|
51216ee433 | ||
|
|
5f7ca6a2f6 | ||
|
|
79bdcf0b3d | ||
|
|
b88f06b16f | ||
|
|
e6d7e01be6 | ||
|
|
889bcd1bf1 | ||
|
|
9637887264 | ||
|
|
4930d19e70 | ||
|
|
aba9517542 | ||
|
|
7540708a61 | ||
|
|
664c7b36a5 | ||
|
|
c390972c76 | ||
|
|
73d286d523 | ||
|
|
4cbccab2bd | ||
|
|
23ed37dd87 | ||
|
|
9b25484a13 | ||
|
|
49f8f43890 | ||
|
|
c936f801c0 | ||
|
|
694a869e78 | ||
|
|
a2e8a3a241 | ||
|
|
2f8ec0e024 | ||
|
|
09c63c45dd | ||
|
|
1ed0f049fe | ||
|
|
4b04ca0b18 | ||
|
|
2f54107289 | ||
|
|
e34f06ae5d | ||
|
|
77386ae011 | ||
|
|
0c959294a8 | ||
|
|
8892b5cf9e | ||
|
|
9da232c05a | ||
|
|
1ce06604de | ||
|
|
530c70b0a9 | ||
|
|
dadc67a92e | ||
|
|
2775a3526e | ||
|
|
8f241ab3b8 | ||
|
|
3e09be56a8 | ||
|
|
757f8f771e | ||
|
|
04ba485042 | ||
|
|
b1149a49b2 | ||
|
|
a9eaf0a130 | ||
|
|
a1680fa612 | ||
|
|
d7bd4f7a1c | ||
|
|
0be40b9fd4 | ||
|
|
9e5e6c2f86 | ||
|
|
1ab19b445f | ||
|
|
ee32ed045c | ||
|
|
82ba449dd0 | ||
|
|
9b7febb538 | ||
|
|
fae6bfb80b | ||
|
|
45bb6e801f | ||
|
|
b08aa26a76 | ||
|
|
8dacbed556 | ||
|
|
b44df43fcb | ||
|
|
84af829053 | ||
|
|
f5ee64f9aa | ||
|
|
ce4891b33d | ||
|
|
ffa46b8f0b | ||
|
|
bf05c261d2 | ||
|
|
952ae9fbe3 | ||
|
|
6f2dbb0011 | ||
|
|
f77980fce8 | ||
|
|
d90c1e6eae | ||
|
|
d987f463eb | ||
|
|
89beaf2460 | ||
|
|
0c5d12b914 | ||
|
|
32ca2e8a73 | ||
|
|
d7f6bc1614 | ||
|
|
83d878f111 | ||
|
|
0fc6441c96 | ||
|
|
db09f6eb2e | ||
|
|
835d15b536 | ||
|
|
bae0512c8a | ||
|
|
8d6134952a | ||
|
|
1d7c0e5949 | ||
|
|
37b0f3617d | ||
|
|
6866117194 | ||
|
|
b622537199 | ||
|
|
355b1b6a57 | ||
|
|
d6f4273241 | ||
|
|
de1b19ea88 | ||
|
|
79fa5618f1 | ||
|
|
91bf2ab86d | ||
|
|
88655019cc | ||
|
|
fad44611dc | ||
|
|
8884971223 | ||
|
|
07e1248686 | ||
|
|
6cd84b64f0 | ||
|
|
c6b3966d02 | ||
|
|
432e056659 | ||
|
|
bbb6c2fb53 | ||
|
|
095a6e5937 | ||
|
|
56020fd821 | ||
|
|
11235c0e40 | ||
|
|
406caa5f56 | ||
|
|
8bd5e39102 | ||
|
|
c547dff650 | ||
|
|
e6df2f6210 | ||
|
|
312ccae003 | ||
|
|
ff27217639 | ||
|
|
3f4f9b6331 | ||
|
|
5b8e395174 | ||
|
|
9914b676b3 | ||
|
|
abd44c8393 | ||
|
|
f70916f8b0 | ||
|
|
81cf9979ed | ||
|
|
5be1620629 | ||
|
|
685b87e2ef | ||
|
|
72429c2106 | ||
|
|
7707fe15a9 | ||
|
|
c583ffff41 | ||
|
|
7c1ab8b8e2 | ||
|
|
570fbd0149 | ||
|
|
da1f09e9b5 | ||
|
|
9e45984a97 | ||
|
|
b2fb4f4b9b | ||
|
|
51277b17a7 | ||
|
|
32f5ef864e | ||
|
|
a8f28297ec | ||
|
|
0ae13c9731 | ||
|
|
1895dbb768 | ||
|
|
a6cbbd0f31 | ||
|
|
f1f52af9cf | ||
|
|
e3c619eca4 | ||
|
|
57e59d97db | ||
|
|
d7cada0f38 | ||
|
|
fd2ac1fcfc | ||
|
|
0181b0e7a1 | ||
|
|
2b5e5cfa4c | ||
|
|
bfb0d02622 | ||
|
|
534b70643b | ||
|
|
3d0f729572 | ||
|
|
fd4ed1e425 | ||
|
|
693450393c | ||
|
|
8ee7584cff | ||
|
|
0a56a73bd9 | ||
|
|
3a1d3090f2 | ||
|
|
0727393627 | ||
|
|
d2ef059471 | ||
|
|
2e894a512b | ||
|
|
34b0209f05 | ||
|
|
046f575632 | ||
|
|
1c77104b5e | ||
|
|
386be8990a | ||
|
|
76d9c7c82a | ||
|
|
98f08034a1 | ||
|
|
308cf77437 | ||
|
|
ce64f469f4 | ||
|
|
e632c3db1b | ||
|
|
239d22ed72 | ||
|
|
fefbe96816 | ||
|
|
ef3ad68020 | ||
|
|
f9470c9a17 | ||
|
|
e9a1438ac4 | ||
|
|
5102c0da92 | ||
|
|
d68b775df5 | ||
|
|
ed995ffa03 | ||
|
|
875a1f07d8 | ||
|
|
d070546568 | ||
|
|
511be70eba | ||
|
|
840f7f61c5 | ||
|
|
9d69d6e8fb | ||
|
|
15c078df61 | ||
|
|
b1f662d639 | ||
|
|
aa5b27b040 | ||
|
|
10d254ec1b | ||
|
|
e8a44821d0 | ||
|
|
92e48f0717 | ||
|
|
9742c44db5 | ||
|
|
5d16f51950 | ||
|
|
1ed2e8b5bc | ||
|
|
b20803b766 | ||
|
|
8cf1daf823 | ||
|
|
083b54472c | ||
|
|
1b9fea0669 | ||
|
|
d3c37c7159 | ||
|
|
807f020184 | ||
|
|
b400be68b7 | ||
|
|
e39bdb58ec | ||
|
|
83c8977033 | ||
|
|
682990eeb3 | ||
|
|
7ee766aee1 | ||
|
|
848c5ad784 | ||
|
|
a41fb1b036 | ||
|
|
915117ae7b | ||
|
|
de5fa78762 | ||
|
|
b0c8efd840 | ||
|
|
1dcd5edbf9 | ||
|
|
87d7fc8e5d | ||
|
|
100a747eab | ||
|
|
105fd03ef8 | ||
|
|
9395a9c1d9 | ||
|
|
02f7efd9d4 | ||
|
|
aea86c5977 | ||
|
|
8d81592bec | ||
|
|
93ebb31b17 | ||
|
|
bfed57e3e0 | ||
|
|
a6bbbeffcf | ||
|
|
9110747194 | ||
|
|
693b209cb4 | ||
|
|
a01564158e | ||
|
|
23647390e6 | ||
|
|
96bca72bb4 | ||
|
|
5d6da23108 | ||
|
|
b44f504ced | ||
|
|
e90e5640e7 | ||
|
|
2df6695f2b | ||
|
|
92e3b1802f | ||
|
|
0463520693 | ||
|
|
922e3bf59f | ||
|
|
42f2ad0516 | ||
|
|
1eab6202ac | ||
|
|
d30ee6c44a | ||
|
|
4f2da00e94 | ||
|
|
34b9a3fa2e | ||
|
|
5c7b869e61 | ||
|
|
6cbea7d29b | ||
|
|
8cfa37fc21 | ||
|
|
16c53085f7 | ||
|
|
2ccb926314 | ||
|
|
6384fe3414 | ||
|
|
ef64333e63 | ||
|
|
0851705304 | ||
|
|
b97a4ad7f2 | ||
|
|
d01afe885c | ||
|
|
6163e7b13a | ||
|
|
66547bd28a | ||
|
|
e6ab823473 | ||
|
|
a2c0bce4cc | ||
|
|
959d6035e5 | ||
|
|
aa730ef1ea | ||
|
|
f5ca1f9ee9 | ||
|
|
61d3fdb474 | ||
|
|
53a4d6c3b1 | ||
|
|
f40ca9cb58 | ||
|
|
7a3d1487e4 | ||
|
|
3a955d9ad4 | ||
|
|
0413fbc7d0 | ||
|
|
c0f5c678c2 | ||
|
|
a9897b0084 | ||
|
|
f4b5a4d869 | ||
|
|
a60016e061 | ||
|
|
374401d786 | ||
|
|
7d749d810b | ||
|
|
d63d02601f | ||
|
|
0a2621c673 | ||
|
|
07601b7e07 | ||
|
|
645c664fbb | ||
|
|
d7920ff9b1 | ||
|
|
c6cd1e59b1 | ||
|
|
4938052f6b | ||
|
|
b278e44376 | ||
|
|
c07e16fadd | ||
|
|
38da8d07d0 | ||
|
|
733daef127 | ||
|
|
175a9e3199 | ||
|
|
5e3a15ae1b | ||
|
|
a0e19e3cf1 | ||
|
|
cd03e293c3 | ||
|
|
d96f47cf06 | ||
|
|
4c14e8668c | ||
|
|
4de1031d8a | ||
|
|
073598ed8f | ||
|
|
808f3004f0 | ||
|
|
4724dd439e | ||
|
|
3b74b55084 | ||
|
|
2c8239f9cb | ||
|
|
a3da3e592d | ||
|
|
1cab962098 | ||
|
|
1eb85249e7 | ||
|
|
44d8b039e8 | ||
|
|
370ab4c4db | ||
|
|
843f769b96 | ||
|
|
d5935bb0a4 | ||
|
|
e5d50b236c | ||
|
|
07f39ae47b | ||
|
|
569a3f4548 | ||
|
|
636aa8de76 | ||
|
|
68ba4d43ac | ||
|
|
e9551c9e8d | ||
|
|
2c120af61e | ||
|
|
91f4f41665 | ||
|
|
6a052af890 | ||
|
|
5629dbe715 | ||
|
|
8cbd858d45 | ||
|
|
28375ff63e | ||
|
|
0ac80086bc | ||
|
|
9ab36ddc36 | ||
|
|
a6bc34c09b | ||
|
|
3bb6b16c4a | ||
|
|
1cde2442aa | ||
|
|
cd81dcf18b | ||
|
|
65311a3360 | ||
|
|
315df9ada0 | ||
|
|
036963a7da | ||
|
|
2910cee32b | ||
|
|
54fd3d4024 | ||
|
|
a79bb86856 | ||
|
|
e138698e54 | ||
|
|
db6655deb4 | ||
|
|
cf0a909e2d | ||
|
|
1976acfe3e | ||
|
|
497351ad07 | ||
|
|
4a2c4477c9 | ||
|
|
98d2e0017d | ||
|
|
7de6451818 | ||
|
|
3060de88ce | ||
|
|
f6e1a94e03 | ||
|
|
dc39b0c190 | ||
|
|
ccc39f64f8 | ||
|
|
b45b0d81bb | ||
|
|
d026647f4f | ||
|
|
a2af2a306b | ||
|
|
725762c48d | ||
|
|
6bf81eb7b1 | ||
|
|
eef45934fa | ||
|
|
c4ef1efdb7 | ||
|
|
c3df27d1ea | ||
|
|
2f717c156a | ||
|
|
a7c02b19bf | ||
|
|
0418253a9b | ||
|
|
7fefc7b245 | ||
|
|
68d213f4c9 | ||
|
|
7d9a2ce827 | ||
|
|
c6ef287452 | ||
|
|
9ae4f5c73d | ||
|
|
169be0426c | ||
|
|
6097d14d4d | ||
|
|
f657315e60 | ||
|
|
a19c4058be | ||
|
|
ec34806c1e | ||
|
|
f141329fb7 | ||
|
|
6da2bc96e2 | ||
|
|
95360c2e0c | ||
|
|
18b59f35ef | ||
|
|
40d555dbb7 | ||
|
|
df5f543b65 | ||
|
|
e1d98bca5a | ||
|
|
dba33a943d | ||
|
|
84d056d0f7 | ||
|
|
3a5905fa85 | ||
|
|
5b48d90049 | ||
|
|
3c09ce26fb | ||
|
|
a4f03bd7eb | ||
|
|
4ae1bea323 | ||
|
|
b70d81f60b | ||
|
|
c945e1126a | ||
|
|
3d0b427c30 | ||
|
|
ceb3a7a8f6 | ||
|
|
61a73de64d | ||
|
|
7778f1b4b0 | ||
|
|
62a197516b | ||
|
|
95d6297db8 | ||
|
|
53774e69fa | ||
|
|
1ccfd6a1f7 | ||
|
|
25f8d4fb41 | ||
|
|
af2175326c | ||
|
|
9b4edfdf08 | ||
|
|
817894c012 | ||
|
|
7d81f39222 | ||
|
|
e58118cda6 | ||
|
|
20377a6f3d | ||
|
|
f491eee2a1 | ||
|
|
e8e6ca6309 | ||
|
|
367ba4125f | ||
|
|
3d9c6a7ce6 | ||
|
|
55c74617d7 | ||
|
|
e6091a2b7e | ||
|
|
3c7d6a1853 | ||
|
|
f07b7393a0 | ||
|
|
ac91822952 | ||
|
|
ea1b48bd12 | ||
|
|
fba391ae66 | ||
|
|
257009afff | ||
|
|
5d180d2834 | ||
|
|
0bad00d049 | ||
|
|
92bde124ca | ||
|
|
69dc0a06bf | ||
|
|
7018ad69a2 | ||
|
|
46df4db87b | ||
|
|
c19530bc71 | ||
|
|
349ef3f6a0 | ||
|
|
a031d268b1 | ||
|
|
81a55d026f | ||
|
|
1bf02e1ca9 | ||
|
|
a66814fd7a | ||
|
|
18ff8cd1fb | ||
|
|
17c226b070 | ||
|
|
6122f1c450 | ||
|
|
4a474843fb | ||
|
|
7d43159a7d | ||
|
|
3ea4c43add | ||
|
|
c6f0ea2c81 | ||
|
|
60d5ef4d82 | ||
|
|
21316d5709 | ||
|
|
aba61d9ebd | ||
|
|
965356ae63 | ||
|
|
d1b5767a82 | ||
|
|
ae7d5bf617 | ||
|
|
e3667cb908 | ||
|
|
f745c0181a | ||
|
|
dd885780d6 | ||
|
|
95ea74549c | ||
|
|
445aa844b9 | ||
|
|
f098fe319b | ||
|
|
2ab6fef099 | ||
|
|
8e83bcd2ac | ||
|
|
d32f2e9999 | ||
|
|
4739131ca6 | ||
|
|
b164c4dec3 | ||
|
|
f5235b2d76 | ||
|
|
362f2a84bd | ||
|
|
d828f90c26 | ||
|
|
f687ac0c32 | ||
|
|
0772098b1b | ||
|
|
06966d2a0e | ||
|
|
46346e9e3a | ||
|
|
303465af35 | ||
|
|
71ab81ec69 | ||
|
|
aab479f8cf | ||
|
|
fd052d2a86 | ||
|
|
acb32d472d | ||
|
|
683e530cf3 | ||
|
|
f521498b43 | ||
|
|
fb3457d157 | ||
|
|
b1929bb2b6 | ||
|
|
141ac8df59 | ||
|
|
30775bc3e3 | ||
|
|
0bc8c9c8f9 | ||
|
|
efccd6353b | ||
|
|
8c42d1257f | ||
|
|
94bc26e652 | ||
|
|
29ac9aea5d | ||
|
|
b5ca1e9e53 | ||
|
|
899c85ae67 | ||
|
|
4554a49d32 | ||
|
|
203f357c32 | ||
|
|
dfea168499 | ||
|
|
8f9958dc24 | ||
|
|
dbcc0a85d0 | ||
|
|
b2351ea0dc | ||
|
|
1f12be3072 | ||
|
|
88272cf7ac | ||
|
|
241d1bd7e1 | ||
|
|
56addcd172 | ||
|
|
8d8e1810d4 | ||
|
|
b5ddc11c46 | ||
|
|
f107746e90 | ||
|
|
f68a26381a | ||
|
|
5a2cc90786 | ||
|
|
3881d5c1f2 | ||
|
|
958f2c00c8 | ||
|
|
165333b0fc | ||
|
|
62b1f32062 | ||
|
|
02ab14cc2e | ||
|
|
018f7b7378 | ||
|
|
5b8350aaaa | ||
|
|
be83bb13a8 | ||
|
|
aea6e71ef8 | ||
|
|
b3bdcd2278 | ||
|
|
18ac41973b | ||
|
|
b7b23a0ff5 | ||
|
|
ded1655d49 | ||
|
|
52fb306535 | ||
|
|
de6f3ad017 | ||
|
|
a3718cde06 | ||
|
|
9760475a39 | ||
|
|
f2a5fe3678 | ||
|
|
cc827e157a | ||
|
|
7b4e25008a | ||
|
|
f66e5a9c3d | ||
|
|
9954f5b4a4 | ||
|
|
53936661c8 | ||
|
|
e2552ff8a9 | ||
|
|
6ab08cc3e1 | ||
|
|
3205373bb3 | ||
|
|
3b8d1f7076 | ||
|
|
2dba1e391d | ||
|
|
5832c25ad1 | ||
|
|
95338f9cc4 | ||
|
|
d0854927fc | ||
|
|
b57d0eb418 | ||
|
|
8f27578de2 | ||
|
|
5a7eb9c881 | ||
|
|
569a3d9ff8 | ||
|
|
69bc7108bd | ||
|
|
8a557e9d71 | ||
|
|
fe0f071993 | ||
|
|
effa53339c | ||
|
|
f6fb0e4620 | ||
|
|
cf46a014c1 | ||
|
|
d72b5fa16d | ||
|
|
eacccd2acb | ||
|
|
0151507cef | ||
|
|
f0c5052aa8 | ||
|
|
b9a0500f16 | ||
|
|
49b3663332 | ||
|
|
0fea781f8f | ||
|
|
3c4cadc020 | ||
|
|
0d18a1e85f | ||
|
|
e2615ccf88 | ||
|
|
26301897d0 | ||
|
|
595deb0e13 | ||
|
|
4bb5ccbefb | ||
|
|
01cbf17ba2 | ||
|
|
a16739a3ac | ||
|
|
4355145a62 | ||
|
|
bb7cd97439 | ||
|
|
17b34c7309 | ||
|
|
3a5049042a | ||
|
|
5372d1aab2 | ||
|
|
52eca14ca6 | ||
|
|
1155f5ac63 | ||
|
|
0367a80819 | ||
|
|
f395119ede | ||
|
|
ad7d4c6b70 | ||
|
|
7319953ae3 | ||
|
|
b8e106a72e | ||
|
|
f30f8eba2f | ||
|
|
7ed2296fc5 | ||
|
|
0691a46669 | ||
|
|
d7f01c1f7d | ||
|
|
4d71929c60 | ||
|
|
dadce055f8 | ||
|
|
9e56d3969a | ||
|
|
1aad55b66f | ||
|
|
70789cf4bb | ||
|
|
951d25ff66 | ||
|
|
437e258384 | ||
|
|
f225891526 | ||
|
|
9c1483100a | ||
|
|
8449a5df87 | ||
|
|
0232778f35 | ||
|
|
f28fccd2db | ||
|
|
3f3cb9d09b | ||
|
|
53cdf8a3d1 | ||
|
|
4f9de66f0e | ||
|
|
b548ffabbe | ||
|
|
ac5f21d613 | ||
|
|
5a77d015be | ||
|
|
baf92f3f1c | ||
|
|
16258f21d1 | ||
|
|
6401920d70 | ||
|
|
1be29606c5 | ||
|
|
fb66e2e249 | ||
|
|
aaf71b380e | ||
|
|
a29aec9abb | ||
|
|
d42ea9e88a | ||
|
|
4985c11bd6 | ||
|
|
5198b513d3 | ||
|
|
366a16ff05 | ||
|
|
522d93607a | ||
|
|
f5cf1e46a4 | ||
|
|
294f93af97 | ||
|
|
fcb3dfe56d | ||
|
|
ebf20b83b2 | ||
|
|
d2867580ab | ||
|
|
8dc238efae | ||
|
|
7cd4b5e11c | ||
|
|
00043f9509 | ||
|
|
9b81f3f263 | ||
|
|
2747d1a1a9 | ||
|
|
9f7ed0b232 | ||
|
|
c176ea7366 | ||
|
|
108afbc0bb | ||
|
|
9cb9f98d2f | ||
|
|
f5577fdbd8 | ||
|
|
8a81ed1b5a | ||
|
|
593cde16bc | ||
|
|
8d70d498d5 | ||
|
|
5745b469d3 | ||
|
|
a11c842ecd | ||
|
|
615eb0db86 | ||
|
|
203feb6ea2 | ||
|
|
08c3f0bca6 | ||
|
|
3bf02ea7e8 | ||
|
|
acb4cd2135 | ||
|
|
fb86ecb802 | ||
|
|
2c5865cd90 | ||
|
|
ebbcd05e03 | ||
|
|
de4f04a272 | ||
|
|
f2f57eb44f | ||
|
|
8119259bb6 | ||
|
|
e664f38170 | ||
|
|
f464cf2380 | ||
|
|
02c395a179 | ||
|
|
acdccab019 | ||
|
|
e9f674e5fb | ||
|
|
0f8d47c9ed | ||
|
|
f1d56c981d | ||
|
|
ea595784f9 | ||
|
|
549fe1f3af | ||
|
|
cf6b0f9cef | ||
|
|
02e930624a | ||
|
|
ec56906bd6 | ||
|
|
23d299234c | ||
|
|
f84c181eac | ||
|
|
8ff0226361 | ||
|
|
d756b11fa2 | ||
|
|
ec74ae7ec1 | ||
|
|
785851a736 | ||
|
|
2a2d5a7a1f | ||
|
|
a60ed4a599 | ||
|
|
5ed6662145 | ||
|
|
f885e364ba | ||
|
|
3ac666b3e6 | ||
|
|
4b37eb13dc | ||
|
|
3a13c654e6 | ||
|
|
ec2d180739 | ||
|
|
049f2f0805 | ||
|
|
b34fc03e5e | ||
|
|
4f8458d8d6 | ||
|
|
b24b490393 | ||
|
|
264953871b | ||
|
|
542455ce2a | ||
|
|
d50e4bb819 | ||
|
|
4485ca74f6 | ||
|
|
7f72b214e5 | ||
|
|
fe2fdef7b0 | ||
|
|
430dadaf83 | ||
|
|
36f1dea5e1 | ||
|
|
8dd16caec8 | ||
|
|
ea5350c5ec | ||
|
|
814aad65f1 | ||
|
|
5843a45d01 | ||
|
|
999494cef8 | ||
|
|
47579bdf5c | ||
|
|
b02780c41d | ||
|
|
ea930a352c | ||
|
|
f9dacf8aac | ||
|
|
b5029dfdad | ||
|
|
cfcd0fa6f7 | ||
|
|
714e103ac3 | ||
|
|
595ecd5f4b | ||
|
|
324070c8f6 | ||
|
|
2017407b4d | ||
|
|
df9c213bb0 | ||
|
|
9dcdc7e79a | ||
|
|
10f94b0ab1 | ||
|
|
ecd5351870 | ||
|
|
08ad6abd04 | ||
|
|
33fb617053 | ||
|
|
91690a2920 | ||
|
|
7896debe6c | ||
|
|
41b2ed2bbc | ||
|
|
71fbe6e800 | ||
|
|
152b5d46c4 | ||
|
|
90b9f08e5d | ||
|
|
1f5a73a530 | ||
|
|
049cf8cdf4 | ||
|
|
19d4705ffd | ||
|
|
299f9ebffa | ||
|
|
f44186e575 | ||
|
|
e18068d9d8 | ||
|
|
e6c1aeaf08 | ||
|
|
fae5ceef2a | ||
|
|
4617960863 | ||
|
|
78eaf503fd | ||
|
|
f6711b7da5 | ||
|
|
955e00fbec | ||
|
|
4e36925c66 | ||
|
|
c4b52fc7c9 | ||
|
|
e87c31de66 | ||
|
|
9bd212cf24 | ||
|
|
ef14c18c8e | ||
|
|
98f39a37fb | ||
|
|
723b4a15a3 | ||
|
|
c07d3bd8dd | ||
|
|
456c347d45 | ||
|
|
60f13e7a86 | ||
|
|
35fc7fda7a | ||
|
|
50d750733e | ||
|
|
7a7c60459e | ||
|
|
2e8f8c9b0c | ||
|
|
b3dc23c5a8 | ||
|
|
59ff42c421 | ||
|
|
efaf09ee4b | ||
|
|
bc8cc1adb3 | ||
|
|
55abd1c6d0 | ||
|
|
58e9c26115 | ||
|
|
ee59dc1b5c | ||
|
|
266949c7fc | ||
|
|
2426aaa099 | ||
|
|
b51f5da314 | ||
|
|
781d7b0d9b | ||
|
|
92a483bca2 | ||
|
|
e7047ec2fc | ||
|
|
411c18bbce | ||
|
|
4bc14da2b3 | ||
|
|
4c13945c37 | ||
|
|
51eb0da824 | ||
|
|
11b3325e99 | ||
|
|
f48afb4710 | ||
|
|
0f3e0cb4ad | ||
|
|
a56cbd3036 | ||
|
|
407da77ea4 | ||
|
|
6413e5f81a | ||
|
|
4f67d0b647 | ||
|
|
1f42bd7057 | ||
|
|
7993780dda | ||
|
|
b8c67ce41b | ||
|
|
9acd40d97b | ||
|
|
cfb449cc80 | ||
|
|
7d9b09adaa | ||
|
|
1e301ff83e | ||
|
|
19d46f8f2f | ||
|
|
86e3395c11 | ||
|
|
f74c32cad2 | ||
|
|
ab60dcf564 | ||
|
|
8a23ca0b28 | ||
|
|
5abdf9a556 | ||
|
|
bde33501c4 | ||
|
|
e3ff414513 | ||
|
|
63c1303cfb | ||
|
|
ddd43b6bc3 | ||
|
|
feba7cbf4d | ||
|
|
4d06d99bf8 | ||
|
|
8c291b97b9 | ||
|
|
d03c2de901 | ||
|
|
7d3c5f1e64 | ||
|
|
81573de393 | ||
|
|
a80dd5d001 | ||
|
|
7e0077f293 | ||
|
|
1eb035e6ad | ||
|
|
4e064fbab4 | ||
|
|
cf3d79d4c1 | ||
|
|
6a3c4ac50a | ||
|
|
48efc25f74 | ||
|
|
a102b21d17 | ||
|
|
1acc315cea | ||
|
|
00db1b5579 | ||
|
|
37f45d9e56 | ||
|
|
ec02c761aa | ||
|
|
09b7f6c2a1 | ||
|
|
6bb5503524 | ||
|
|
b5e99bd064 | ||
|
|
bccbc5509a | ||
|
|
ec951cdc15 | ||
|
|
e288430c05 | ||
|
|
7ca00d694d | ||
|
|
3716950cfc | ||
|
|
5b44631397 | ||
|
|
c31055db61 | ||
|
|
01c13bddea | ||
|
|
ca1c182567 | ||
|
|
c4fdf09c05 | ||
|
|
1df5bb5687 | ||
|
|
75f9dec644 | ||
|
|
bdd14ac517 | ||
|
|
63e5d00bdf | ||
|
|
c25fb3d74f | ||
|
|
572d41325b | ||
|
|
e02120cdf7 | ||
|
|
7b1221a74d | ||
|
|
d6b4f994ad | ||
|
|
2f41a38568 | ||
|
|
441c490024 | ||
|
|
4cd1fb1f40 | ||
|
|
7459652e3e | ||
|
|
b55a827ea2 | ||
|
|
84e0489562 | ||
|
|
7885faf18b | ||
|
|
66a41dafc4 | ||
|
|
69b7113bb5 | ||
|
|
3ba2281f96 | ||
|
|
c1b1e8c329 | ||
|
|
f19b9c155e | ||
|
|
5d016fdb6b | ||
|
|
cae9924fd9 | ||
|
|
089f28e8ba | ||
|
|
dcb44d3a09 | ||
|
|
f99cba0b92 | ||
|
|
e10dc0dace | ||
|
|
c85bf2352d | ||
|
|
04056b767f | ||
|
|
49a89d636b | ||
|
|
d322e7baba | ||
|
|
ada2ac9ae2 | ||
|
|
cb5eadb33b | ||
|
|
b94f91b9b2 | ||
|
|
06a17c8511 | ||
|
|
eebd70aaa6 | ||
|
|
779c775df9 | ||
|
|
1d4d2925c2 | ||
|
|
b67db7c2d5 | ||
|
|
bbc2c44541 | ||
|
|
cf88779527 | ||
|
|
79a7c17176 | ||
|
|
0719388cfb | ||
|
|
25f457c7f6 | ||
|
|
7e5a6313f0 | ||
|
|
f16b52cb7d | ||
|
|
0963edbc65 | ||
|
|
18953b2998 | ||
|
|
527b7eb074 | ||
|
|
0b1d89d7ae | ||
|
|
08d3e929e5 | ||
|
|
f207e1682f | ||
|
|
e6fa47380a | ||
|
|
61954951ed | ||
|
|
34a97c447f | ||
|
|
a221a313ae | ||
|
|
1c525e20b1 | ||
|
|
f8ae991717 | ||
|
|
d87a0d0286 | ||
|
|
39f716a121 | ||
|
|
d638b05834 | ||
|
|
ea7cf737a1 | ||
|
|
9812e88959 | ||
|
|
c1aaad06d8 | ||
|
|
d8fd48c436 | ||
|
|
0bcce50285 | ||
|
|
96e0b2a2b1 | ||
|
|
f3794d2c42 | ||
|
|
204a14b8cf | ||
|
|
92ec592520 | ||
|
|
c170365dcf | ||
|
|
a0576bdeea | ||
|
|
48a9d63af3 | ||
|
|
d5059ba5e1 | ||
|
|
dd1f20edc5 | ||
|
|
97fd736923 | ||
|
|
3feff7d78a | ||
|
|
5d0c6b0868 | ||
|
|
c09b5941ce | ||
|
|
19c29b6007 | ||
|
|
97d647a139 | ||
|
|
bcc46a2f25 | ||
|
|
d428de590f | ||
|
|
cd1c600548 | ||
|
|
ba950a3d1f | ||
|
|
254367788a | ||
|
|
7e4325cbc9 | ||
|
|
7ace7231c6 | ||
|
|
1fd456f91a | ||
|
|
f6546eff45 | ||
|
|
2faa0f19eb | ||
|
|
d8fbd3a8ba | ||
|
|
10b5006934 | ||
|
|
f4ca3d8757 | ||
|
|
762be79f0b | ||
|
|
639b73cd2a | ||
|
|
a698a6391a | ||
|
|
89c78a9808 | ||
|
|
f210e197f3 | ||
|
|
9122379abc | ||
|
|
1a91a2700b | ||
|
|
b5f3996250 | ||
|
|
84b3c18f71 | ||
|
|
441bfa2dfb | ||
|
|
d310beb417 | ||
|
|
411bcf1a41 | ||
|
|
efd17316ab | ||
|
|
4342703743 | ||
|
|
6987176059 | ||
|
|
39436b2152 | ||
|
|
66037309c6 | ||
|
|
380f6048e0 | ||
|
|
a9c0602149 | ||
|
|
825fe7bd23 | ||
|
|
dc899c4c88 | ||
|
|
dad5a902d3 | ||
|
|
25214bd7dc | ||
|
|
3cc673bdd8 | ||
|
|
de0919cd62 | ||
|
|
5aa0fef2ce | ||
|
|
3988e32f41 | ||
|
|
6f16e52a6d | ||
|
|
c6c2de9567 | ||
|
|
cebc1f2696 | ||
|
|
56d8ad932d | ||
|
|
0103dc09d2 | ||
|
|
71c1427a1b | ||
|
|
30bb0dd595 | ||
|
|
99f39d32ab | ||
|
|
851ec530b4 | ||
|
|
79e6ab31d8 | ||
|
|
b20af834ff | ||
|
|
1453277294 | ||
|
|
e4e24460f9 | ||
|
|
db9cffe7c2 | ||
|
|
9c475272da | ||
|
|
6f2c894d69 | ||
|
|
4147a2202e | ||
|
|
28d1fe6718 | ||
|
|
116a2042a7 | ||
|
|
945983ac52 | ||
|
|
e7c8002b56 | ||
|
|
86b5e1a72f | ||
|
|
bab834574c | ||
|
|
76f3a63de1 | ||
|
|
93b4c6b31e | ||
|
|
12055ed8c2 | ||
|
|
c80f6219d5 | ||
|
|
801c7307fb | ||
|
|
a7b95b7c72 | ||
|
|
919580a228 | ||
|
|
e83d6b0cfa | ||
|
|
cb070accb4 | ||
|
|
9ce6fc7322 | ||
|
|
a7b9cfbe98 | ||
|
|
219bab2d85 | ||
|
|
d51bebd4d7 | ||
|
|
120c6b43e1 | ||
|
|
63075b81e6 | ||
|
|
9418083770 | ||
|
|
5d1ac2df64 | ||
|
|
90555566ed | ||
|
|
bb7e00b699 | ||
|
|
faa431c98d | ||
|
|
757ad7cdf2 | ||
|
|
31491202aa | ||
|
|
26c1c60187 | ||
|
|
2ccbba650c | ||
|
|
c73406c2bd | ||
|
|
c1423c016c | ||
|
|
ecf51b0b3d | ||
|
|
9d0388a043 | ||
|
|
6a4da4958e | ||
|
|
e8f772efff | ||
|
|
59866fcd30 | ||
|
|
4832cf4fd6 | ||
|
|
fd610ae025 | ||
|
|
88441019a5 | ||
|
|
aa1feec746 | ||
|
|
e5e353c81d | ||
|
|
0bdddd3c89 | ||
|
|
7bc0726016 | ||
|
|
ea4bf91abc | ||
|
|
5d9332266d | ||
|
|
7601ed344c | ||
|
|
405f041e90 | ||
|
|
aa6b869c15 | ||
|
|
00a767db38 | ||
|
|
5106a144f0 | ||
|
|
3efdbbc79c | ||
|
|
2ae7f49115 | ||
|
|
3e33fbcd35 | ||
|
|
444555d3e4 | ||
|
|
7fa56dd773 | ||
|
|
6a74f524e5 | ||
|
|
9c5b59ac01 | ||
|
|
dac26729a9 | ||
|
|
4d1120f5fd | ||
|
|
1840601f8e | ||
|
|
9824fe3e39 | ||
|
|
4e2e5be201 | ||
|
|
01acfa71ca | ||
|
|
88962af8b2 | ||
|
|
d2af0f25be | ||
|
|
27f4c212f3 | ||
|
|
ebfa769925 | ||
|
|
df22cdf6e9 | ||
|
|
041446005b | ||
|
|
7c39a9b0e1 | ||
|
|
e05a7df7f9 | ||
|
|
0f370f9b66 | ||
|
|
556acefe75 | ||
|
|
c96ece9f5e | ||
|
|
843a13e88f | ||
|
|
05cd92f766 | ||
|
|
6cf23d6610 | ||
|
|
a425e1d26d | ||
|
|
04a0af9085 | ||
|
|
0047702aab | ||
|
|
457b7073b5 | ||
|
|
ef92f507dd | ||
|
|
f328194d12 | ||
|
|
f6010e106b | ||
|
|
786d6d55cf | ||
|
|
d724e7226c | ||
|
|
738c782f02 | ||
|
|
33b05c859a | ||
|
|
ed369d7223 | ||
|
|
fb32bb12b1 | ||
|
|
19418b6b28 | ||
|
|
37fd3d40ae | ||
|
|
f559a57206 | ||
|
|
24092eea06 | ||
|
|
3e996035ea | ||
|
|
aaacb8c955 | ||
|
|
ae8a94d615 | ||
|
|
addf47dcac | ||
|
|
69a74a567b | ||
|
|
1b46d4f09a | ||
|
|
8b497881f2 | ||
|
|
056a43e1a6 | ||
|
|
adc3183cd2 | ||
|
|
0aec98dce2 | ||
|
|
907da0580b | ||
|
|
7d117d7591 | ||
|
|
9b7f8ba84b | ||
|
|
dab5ec9b8d | ||
|
|
c6f13892e0 | ||
|
|
c3f9e01794 | ||
|
|
2127f7c8eb | ||
|
|
f659d23619 | ||
|
|
216c110609 | ||
|
|
6f3b91fe26 | ||
|
|
05e0f32345 | ||
|
|
57b8e00695 | ||
|
|
bea40e6a41 | ||
|
|
f87a47dc97 | ||
|
|
6418d767e8 | ||
|
|
8171e6de13 | ||
|
|
66ee45b65c | ||
|
|
3945a32177 | ||
|
|
b042495f37 | ||
|
|
eb6241a3dd | ||
|
|
dc803d25a6 | ||
|
|
b8187d39fb | ||
|
|
420ccdfbae | ||
|
|
41466a4147 | ||
|
|
9798f2d711 | ||
|
|
5f3543921b | ||
|
|
a41366cc3a | ||
|
|
4c7e4b91a6 | ||
|
|
8fb89a5728 | ||
|
|
67b43f75e2 | ||
|
|
cfccfbd6f4 | ||
|
|
1591e3479d | ||
|
|
448c435b1b | ||
|
|
ef33252c43 | ||
|
|
f971a5d8ed | ||
|
|
49383a4af7 | ||
|
|
ce8bfc56ad | ||
|
|
28183f4b66 | ||
|
|
a0abc1eddd | ||
|
|
c2e5546071 | ||
|
|
8aa083bd28 | ||
|
|
a295770e32 | ||
|
|
c9f00bcce2 | ||
|
|
f1863a1fe7 | ||
|
|
c30bd02c9d | ||
|
|
0d62caab21 | ||
|
|
323029baa6 | ||
|
|
57709c4bc6 | ||
|
|
b464afb9e2 | ||
|
|
795c454db1 | ||
|
|
b7ce583a5e | ||
|
|
e08bf16637 | ||
|
|
66a13ccbdf | ||
|
|
a735bf5c2a | ||
|
|
c3edaa7941 | ||
|
|
63cd4d4e20 | ||
|
|
b96c3595af | ||
|
|
26ca04a8a2 | ||
|
|
1980f639b1 | ||
|
|
63a05dde46 | ||
|
|
1bb5794a1f | ||
|
|
23b50bcccc | ||
|
|
9216b96b41 | ||
|
|
d3faed875d | ||
|
|
c37acb82aa | ||
|
|
647cac5bb4 | ||
|
|
f11a0c8f30 | ||
|
|
2458e54814 | ||
|
|
dfe9714c86 | ||
|
|
1b3b75208c | ||
|
|
eabe3eaec0 | ||
|
|
b002d2b4f1 | ||
|
|
445a4b669a | ||
|
|
092cfca522 | ||
|
|
f866023399 | ||
|
|
8b70cb0ef8 | ||
|
|
810e28a397 | ||
|
|
6ff741b5cf | ||
|
|
98c8ac0d70 | ||
|
|
cb2c7c4d34 | ||
|
|
78a6e5eb2b | ||
|
|
ed9bfe2262 | ||
|
|
86511bbbef | ||
|
|
03b59cd5f0 | ||
|
|
5380716a70 | ||
|
|
18b30467f7 | ||
|
|
0052d5196d | ||
|
|
b55b0ea0f2 | ||
|
|
25e211bcf0 | ||
|
|
635704d424 | ||
|
|
47364bce69 | ||
|
|
3cd6c26056 | ||
|
|
8b0d797ecd | ||
|
|
3c8b394511 | ||
|
|
84ba2ec82b | ||
|
|
cf3375bf7c | ||
|
|
643d3e0b79 | ||
|
|
874c3a9978 | ||
|
|
781e50d41f | ||
|
|
57dbd6e90d | ||
|
|
e9fef49e12 | ||
|
|
a227bc8053 | ||
|
|
d410dc3162 | ||
|
|
41c7c7919c | ||
|
|
db6c763d8b | ||
|
|
72d6f966ac | ||
|
|
28e074608c | ||
|
|
5b8de5b7f2 | ||
|
|
bce350c666 | ||
|
|
332aa2f919 | ||
|
|
e4db67ea57 | ||
|
|
b983015dd4 | ||
|
|
9b718d41f0 | ||
|
|
da33a18588 | ||
|
|
1c71038540 | ||
|
|
8ea131fc80 | ||
|
|
de8d320230 | ||
|
|
b2a73c404b | ||
|
|
0666267d27 | ||
|
|
042189fd87 | ||
|
|
a8b7268911 | ||
|
|
1461f02deb | ||
|
|
63730d9dd0 | ||
|
|
818a746e32 | ||
|
|
ce15620dc1 | ||
|
|
b2419c31c1 | ||
|
|
918abd7276 | ||
|
|
b120366d48 | ||
|
|
340963b2d7 | ||
|
|
750acf3a45 | ||
|
|
0a1e734193 | ||
|
|
5496b4a7cd | ||
|
|
f22fa9594d | ||
|
|
b491d477c3 | ||
|
|
2df4cb93ac | ||
|
|
42ba7a1b75 | ||
|
|
573246f73c | ||
|
|
2b998de460 | ||
|
|
fe5da2e60d | ||
|
|
1b7ba44e79 | ||
|
|
b65e5aca86 | ||
|
|
677d14c213 | ||
|
|
e3e69c25fd | ||
|
|
9d527d076b | ||
|
|
58e5feb3f4 | ||
|
|
12f798dc18 | ||
|
|
9ef8d2f671 | ||
|
|
d52ce4ea1a | ||
|
|
8b0747d657 | ||
|
|
f22f64f0db | ||
|
|
747b4004ea | ||
|
|
b35d6e5cff | ||
|
|
dbea5f7a8d | ||
|
|
4bb40a9688 | ||
|
|
d2532d1335 | ||
|
|
00d0d870d2 | ||
|
|
f38e2802b6 | ||
|
|
1b100a167a | ||
|
|
d4e1c88052 | ||
|
|
2c0c5a809c | ||
|
|
f6d04d01b9 | ||
|
|
2fc915f509 | ||
|
|
e3cfc92180 | ||
|
|
7fcf29e615 | ||
|
|
e81bac32fd | ||
|
|
2257f38b68 | ||
|
|
2165a78d10 | ||
|
|
e6f6731c66 | ||
|
|
5a9a653f3e | ||
|
|
ff0846cbb7 | ||
|
|
3e2ed279fd | ||
|
|
19ef1f371d | ||
|
|
8d79702d8a | ||
|
|
6cfcf76e0b | ||
|
|
c9478a3b4e | ||
|
|
113d5ae872 | ||
|
|
1bd75aafdb | ||
|
|
ba48e7e9cd | ||
|
|
4e19358d65 | ||
|
|
43bc1ea065 | ||
|
|
3842bfd899 | ||
|
|
6dcd641681 | ||
|
|
1180537589 | ||
|
|
2e7ad58918 | ||
|
|
39ffc3702f | ||
|
|
31415cb27a | ||
|
|
840a9951b5 | ||
|
|
3c87d572b9 | ||
|
|
d3831559cf | ||
|
|
44ef19743e | ||
|
|
171f83306e | ||
|
|
0314429c8f | ||
|
|
086707315f | ||
|
|
9fd0c027e7 | ||
|
|
0e581e0044 | ||
|
|
e8801f7eaa | ||
|
|
3a677b45ac | ||
|
|
dc46f6f041 | ||
|
|
916b215fc5 | ||
|
|
9f0e8f7849 | ||
|
|
a5294c4e52 | ||
|
|
e511ab2cc6 | ||
|
|
7200b3aa0f | ||
|
|
e8efcdee0a | ||
|
|
2bcc056a41 | ||
|
|
b2bd3c0653 | ||
|
|
4238df5436 | ||
|
|
c68b3908a6 | ||
|
|
1c05b87e30 | ||
|
|
67750ce3b3 | ||
|
|
096285ab64 | ||
|
|
0b2f7c6407 | ||
|
|
8a4240b1fa | ||
|
|
395d339234 | ||
|
|
6daa8b9adb | ||
|
|
e00b6248c9 | ||
|
|
e8aa5583d0 | ||
|
|
f1d5d5d28e | ||
|
|
cc7f4ba67e | ||
|
|
af907e4b6d | ||
|
|
d2f09a054c | ||
|
|
cef46edebc | ||
|
|
9e997cd0d1 | ||
|
|
171aa22b0b | ||
|
|
d75ad774a9 | ||
|
|
571571ca19 | ||
|
|
b61b663895 | ||
|
|
ee4a15aae0 | ||
|
|
c01e94a431 | ||
|
|
9fcd9e191e | ||
|
|
8bdcbbb085 | ||
|
|
b7289e912c | ||
|
|
daef1f00c2 | ||
|
|
21784def70 | ||
|
|
5b0a06af48 | ||
|
|
43af28f5b4 | ||
|
|
6b4ae919e8 | ||
|
|
5449a2a8b5 | ||
|
|
8b428cf0f7 | ||
|
|
9204a9b2c2 | ||
|
|
f80f3f492a | ||
|
|
e61adc0d89 | ||
|
|
89f2bfbb58 | ||
|
|
a3d4d7bf68 | ||
|
|
65c24bd3d4 | ||
|
|
cbaf3c5bba | ||
|
|
34c3be365a | ||
|
|
cbd9af8583 | ||
|
|
89d544d6f2 | ||
|
|
b87c288016 | ||
|
|
0f741a9e2d | ||
|
|
88662c243d | ||
|
|
93d87d6d4c | ||
|
|
cdd925b289 | ||
|
|
64c360c515 | ||
|
|
fb2a94af3f | ||
|
|
1407a055ee | ||
|
|
275068c86f | ||
|
|
6866158f0d | ||
|
|
bffbbeaa9a | ||
|
|
11cd983d58 | ||
|
|
d10b2f3173 | ||
|
|
47637bea6d | ||
|
|
2530dc0ebd | ||
|
|
f3df3ec134 | ||
|
|
79c506ebf0 | ||
|
|
f2db379fa3 | ||
|
|
ddcbb628a1 | ||
|
|
fbed632f3a | ||
|
|
e2a71338eb | ||
|
|
82451a4717 | ||
|
|
ff1e4a7063 | ||
|
|
28a8465102 | ||
|
|
5dd499c6d4 | ||
|
|
589e610ebc | ||
|
|
bd4b33d7a2 | ||
|
|
2e69bfe44d | ||
|
|
09af8447a1 | ||
|
|
8e937ce4cc | ||
|
|
6f11acbd67 | ||
|
|
944cca98c8 | ||
|
|
59d437c727 | ||
|
|
f39c9404a3 | ||
|
|
229327ad8b | ||
|
|
efe92ee546 | ||
|
|
d6220f12a9 | ||
|
|
3941a275f7 | ||
|
|
3f073b1d9c | ||
|
|
3f494cc49d | ||
|
|
e2d64485b8 | ||
|
|
ca95b71f67 | ||
|
|
6dcc6898be | ||
|
|
ea7eeb2fd2 | ||
|
|
81879bc171 | ||
|
|
6a06a5a597 | ||
|
|
3f67b03378 | ||
|
|
1ef014ee6b | ||
|
|
b118502a05 | ||
|
|
e966264188 | ||
|
|
7ee5a41aac | ||
|
|
5f536b5d23 | ||
|
|
3ddb6ffa34 | ||
|
|
c17e597d05 | ||
|
|
81f8524a12 | ||
|
|
90b717e723 | ||
|
|
e5a50ed3c4 | ||
|
|
24c539251f | ||
|
|
1aa31e4da9 | ||
|
|
51077c8212 | ||
|
|
3244fae7d4 | ||
|
|
40c7628fc8 | ||
|
|
f11f26cc53 | ||
|
|
824bd2ac11 | ||
|
|
2f454e5ae8 | ||
|
|
f2da3efc78 | ||
|
|
f7e7775990 | ||
|
|
50f5181488 | ||
|
|
4ac1f9ac55 | ||
|
|
f3352daf4f | ||
|
|
4faad81f50 | ||
|
|
b55c1602b5 | ||
|
|
7af05f07ff | ||
|
|
f6cad30bb6 | ||
|
|
63dae52324 | ||
|
|
f33acb3f02 | ||
|
|
c69a9b2f61 | ||
|
|
bedf1b2126 | ||
|
|
784ceeb90d | ||
|
|
109b5ccdcd | ||
|
|
f31260b044 | ||
|
|
5f4a2801cb | ||
|
|
6d92eee69b | ||
|
|
c75512d89d | ||
|
|
4126ca466f | ||
|
|
da840e9851 | ||
|
|
8a57969fd7 | ||
|
|
8d82639319 | ||
|
|
40d7fca368 | ||
|
|
99e6e73235 | ||
|
|
3e35ac9d7f | ||
|
|
9fc8a5efe5 | ||
|
|
818dc3a089 | ||
|
|
36b9494385 | ||
|
|
f57e844b2e | ||
|
|
343dd9bcce | ||
|
|
f7f77a746a | ||
|
|
3f2fbc4c61 | ||
|
|
4e8f2d6881 | ||
|
|
2fbd0271f6 | ||
|
|
7bf665f125 | ||
|
|
a5696bdf4f | ||
|
|
e15528bf1d | ||
|
|
e28aa99af1 | ||
|
|
3051430040 | ||
|
|
29b20fd528 | ||
|
|
5b36681213 | ||
|
|
0f75036c07 | ||
|
|
b1a01fda91 | ||
|
|
83f55f61a6 | ||
|
|
f89f50dbd0 | ||
|
|
05f8975d21 | ||
|
|
4780cc5efa | ||
|
|
9bc6af2449 | ||
|
|
c4b428a388 | ||
|
|
aea4db2f5a | ||
|
|
b5c5f870a4 | ||
|
|
23bf3d1cb9 | ||
|
|
1be6dbbdf6 | ||
|
|
1acdc84d10 | ||
|
|
52929b61f8 | ||
|
|
b0faf6113e | ||
|
|
f838df92d2 | ||
|
|
7a536c2912 | ||
|
|
6f1e828454 | ||
|
|
2d3687655b | ||
|
|
b057ff81ee | ||
|
|
a9d1014fb2 | ||
|
|
183bdc11c0 | ||
|
|
95ba01b538 | ||
|
|
7b21b8c3fb | ||
|
|
33ca884cc5 | ||
|
|
2b5f23197c | ||
|
|
1104113c07 | ||
|
|
62f8583445 | ||
|
|
3155adb299 | ||
|
|
14a59d4ce7 | ||
|
|
17aaf5ec97 | ||
|
|
3f5cf24da9 | ||
|
|
05e483cbb3 | ||
|
|
c8f250f8dd | ||
|
|
9412094f25 | ||
|
|
8312aa27d4 | ||
|
|
d3aa3791fe | ||
|
|
2b189f098e | ||
|
|
3328b7a514 | ||
|
|
88e1f80eee | ||
|
|
0ebbc36059 | ||
|
|
43ed3c3589 | ||
|
|
8095daea4a | ||
|
|
51e178454d | ||
|
|
82b2bfd20b | ||
|
|
ec1faeec72 | ||
|
|
c1326d7b10 | ||
|
|
845fb2d1c1 | ||
|
|
930fac8058 | ||
|
|
13e50935a8 | ||
|
|
e4d7de608c | ||
|
|
19f192c3a5 | ||
|
|
86fed3fe09 | ||
|
|
2f4e9c3f9f | ||
|
|
416f3f20b4 | ||
|
|
5df0a64d30 | ||
|
|
a25df9dee0 | ||
|
|
d484b8a04e | ||
|
|
8596d483bc | ||
|
|
5f716ea467 | ||
|
|
9242ccf238 | ||
|
|
c2b5f1c15b | ||
|
|
d85af4d6f5 | ||
|
|
93bdbf5aa4 | ||
|
|
dc690161d5 | ||
|
|
a176cb56a3 | ||
|
|
254c962554 | ||
|
|
8128d39737 | ||
|
|
938c35302f | ||
|
|
6a81450144 | ||
|
|
e5227aab89 | ||
|
|
02ef355f98 | ||
|
|
7f19a04f0f | ||
|
|
67660881ed | ||
|
|
e9aba28932 | ||
|
|
279b4a1464 | ||
|
|
d5648d617e | ||
|
|
af39d750cd | ||
|
|
d792db7948 | ||
|
|
3e6f2b1a45 | ||
|
|
5266293a0f | ||
|
|
6a014af79a | ||
|
|
d9f970d8d3 | ||
|
|
b23e251036 | ||
|
|
6f8a8647de | ||
|
|
5977a94842 | ||
|
|
d6180c8c86 | ||
|
|
909bc97c52 | ||
|
|
8e76e13472 | ||
|
|
69ade87325 | ||
|
|
9bbf768d3c | ||
|
|
1978f996d8 | ||
|
|
ad0a9df77a | ||
|
|
760021e677 | ||
|
|
b2c86acd0a | ||
|
|
959cdb358b | ||
|
|
a5a3a7bbc6 | ||
|
|
2d6d9f7552 | ||
|
|
6bbbdd26f4 | ||
|
|
65a3307bc9 | ||
|
|
21f62c3346 | ||
|
|
746297314f | ||
|
|
59fd178014 | ||
|
|
42fd522c63 | ||
|
|
1bfa2d27a6 | ||
|
|
5e46e0800b | ||
|
|
f800b52172 | ||
|
|
ab4cc1e11b | ||
|
|
4ee011adb5 | ||
|
|
71fafd761a | ||
|
|
4b8d8826af | ||
|
|
62fc7f4f24 | ||
|
|
784479939d | ||
|
|
6ce2ed870d | ||
|
|
c92464db69 | ||
|
|
a89bf734a9 | ||
|
|
1055398849 | ||
|
|
a66298e6f1 | ||
|
|
0cae0900cf | ||
|
|
ca58198a76 | ||
|
|
e0022d8cfe | ||
|
|
495327c020 | ||
|
|
afb8b3c030 | ||
|
|
31c9cd8604 | ||
|
|
7008a0ba66 | ||
|
|
0091125cae | ||
|
|
89ca2afd6b | ||
|
|
e63a5ba122 | ||
|
|
a7936ef96d | ||
|
|
2ebcd63d6a | ||
|
|
cdad0e6485 | ||
|
|
2a05fa0d48 | ||
|
|
48b2915c18 | ||
|
|
254f06c131 | ||
|
|
8183a4ca7f | ||
|
|
265a7e7ec7 | ||
|
|
cfffda83fb | ||
|
|
74a203a050 | ||
|
|
12504105c4 | ||
|
|
2bb297b102 | ||
|
|
2fa077b0e9 | ||
|
|
7eba5c308a | ||
|
|
44b76a75d2 | ||
|
|
61074b43a6 | ||
|
|
d1e23e04aa | ||
|
|
5d0774d62f | ||
|
|
ad6b71352d | ||
|
|
52e56bf70d | ||
|
|
c480af9007 | ||
|
|
f644b112ad | ||
|
|
bdd5411747 | ||
|
|
1f8ea99b4b | ||
|
|
5ef157bae1 | ||
|
|
23f2b4d0a8 | ||
|
|
9d38a270db | ||
|
|
6f1ddda9b2 | ||
|
|
6a16a636bf | ||
|
|
bb06a8c870 | ||
|
|
28e574bc4b | ||
|
|
a4efbd590d | ||
|
|
2a8af8e675 | ||
|
|
90f3856fd5 | ||
|
|
15bcb813d4 | ||
|
|
484af8ed53 | ||
|
|
1cf33a46d5 | ||
|
|
151b12a80f | ||
|
|
484cfc3d76 | ||
|
|
32d0df0c1f | ||
|
|
22472fe5a1 | ||
|
|
325409a011 | ||
|
|
3984dc6539 | ||
|
|
94c026cd19 | ||
|
|
7d35939206 | ||
|
|
caf7c50408 | ||
|
|
1965c0099e | ||
|
|
b9abecfc4c | ||
|
|
e258a1c087 | ||
|
|
091fb64681 | ||
|
|
92a3ff6168 | ||
|
|
9e055a0f1f | ||
|
|
eec769be59 | ||
|
|
b89e6d74fa | ||
|
|
c1da9420c7 | ||
|
|
adc5df1bc3 | ||
|
|
07c6bee78f | ||
|
|
b407590cee | ||
|
|
40161553e2 | ||
|
|
285817b28a | ||
|
|
ee93a70e7b | ||
|
|
42f5da5d2d | ||
|
|
5109f16b77 | ||
|
|
90fda5c97c | ||
|
|
06a59fd44d | ||
|
|
5edb1beb63 | ||
|
|
fe640e5858 | ||
|
|
e387f5ba62 | ||
|
|
9f932bcc82 | ||
|
|
86f0e873c7 | ||
|
|
9018ddc32a | ||
|
|
1afb002d69 | ||
|
|
4f3ff46a81 | ||
|
|
af34245692 | ||
|
|
88d71f4793 | ||
|
|
39d1e39212 | ||
|
|
5d83e9e1de | ||
|
|
23a85ba191 | ||
|
|
d949e8fe18 | ||
|
|
a9200ed0b3 | ||
|
|
9fba05f758 | ||
|
|
07e1417ef0 | ||
|
|
edc1f7b176 | ||
|
|
abff264000 | ||
|
|
bf3a67be43 | ||
|
|
dd78f7463f | ||
|
|
c9ef9f1c48 | ||
|
|
05db78e9c5 | ||
|
|
75c11d7fec | ||
|
|
0ca2f4f824 | ||
|
|
96bb0c9471 | ||
|
|
08d00dad52 | ||
|
|
357aace895 | ||
|
|
624742d9b4 | ||
|
|
3cd92e87d1 | ||
|
|
1a7cd2c0e2 | ||
|
|
f4d2abd3df | ||
|
|
f0f30fc43f | ||
|
|
8f5c2bc8aa | ||
|
|
112e19a59c | ||
|
|
67a4fb912f | ||
|
|
0dea1142da | ||
|
|
41cabca2ab | ||
|
|
c38fd1f661 | ||
|
|
dec6fd3adc | ||
|
|
3e6acc24d6 | ||
|
|
a4d0720fa1 | ||
|
|
bc4667acbc | ||
|
|
db39b04d76 | ||
|
|
827e6cc644 | ||
|
|
4715ce5903 | ||
|
|
27e25e9d1e | ||
|
|
b726d64229 | ||
|
|
b4416280cf | ||
|
|
905e28ee87 | ||
|
|
70c4851f2c | ||
|
|
bc9efb577b | ||
|
|
450f0d7248 | ||
|
|
4d1178cc24 | ||
|
|
1750513ac7 | ||
|
|
4387ba6a17 | ||
|
|
79de9d6c78 | ||
|
|
00a3bc4359 | ||
|
|
5fa6f9ebe1 | ||
|
|
4afa243ff1 | ||
|
|
e17f9311c8 | ||
|
|
2e2f57e23b | ||
|
|
028eb45723 | ||
|
|
18c4c7bfe7 | ||
|
|
9cfb1c88d6 | ||
|
|
24173d11bf | ||
|
|
54cb8214d9 | ||
|
|
150ba0e1ff | ||
|
|
5508c228e7 | ||
|
|
373a3384ac | ||
|
|
51ab31dbab | ||
|
|
415c4f613c | ||
|
|
e49d97298a | ||
|
|
64347aaaf9 | ||
|
|
1f246bfcc8 | ||
|
|
140c20fb5e | ||
|
|
5fdc5e5c25 | ||
|
|
154e735c46 | ||
|
|
8257a3c1f6 | ||
|
|
1063f1d833 | ||
|
|
538c2b2d8d | ||
|
|
4477ee33ac | ||
|
|
70a80ef3ad | ||
|
|
6fe2b5236d | ||
|
|
1aee086a09 | ||
|
|
68b5eed41d | ||
|
|
fe9acb3469 | ||
|
|
acf566b291 | ||
|
|
68ad748e77 | ||
|
|
bce3d08c66 | ||
|
|
b3f3d5a42f | ||
|
|
57697373ef | ||
|
|
7dcf3eb3fc | ||
|
|
deee2c1ef2 | ||
|
|
e598d9b59e | ||
|
|
e697ef6dec | ||
|
|
1a0deab2a5 | ||
|
|
6726b3c2cb | ||
|
|
93021da221 | ||
|
|
a07a4ada19 | ||
|
|
365316aa59 | ||
|
|
fe980e2334 | ||
|
|
69ce235c7b | ||
|
|
684c5907dd | ||
|
|
6fcdf75325 | ||
|
|
15b040907c | ||
|
|
058c727282 | ||
|
|
cec388f208 | ||
|
|
528ea98bd3 | ||
|
|
fd8f39a283 | ||
|
|
551fed3169 | ||
|
|
7c29c9eec1 | ||
|
|
86a1386d6f | ||
|
|
1a5c3a9a60 | ||
|
|
d2a6c5ffa2 | ||
|
|
4024bc7eee | ||
|
|
d4a2970092 | ||
|
|
057865a6a5 | ||
|
|
f95a88d988 | ||
|
|
e0de7c0852 | ||
|
|
1e2aee3919 | ||
|
|
ce25ceda58 | ||
|
|
615eae2c82 | ||
|
|
4d4c8c8a40 | ||
|
|
9a3dab0a2e | ||
|
|
e8bc306850 | ||
|
|
d31c0c5264 | ||
|
|
31781e97b6 | ||
|
|
73316758be | ||
|
|
09a5c07886 | ||
|
|
911a2d6cb4 | ||
|
|
828736e7d0 | ||
|
|
4447ddc8bb | ||
|
|
3497fd007f | ||
|
|
a48dfe98cf | ||
|
|
2192a91d62 | ||
|
|
486e45ffaf | ||
|
|
022f09447b | ||
|
|
8a7f255cd0 | ||
|
|
fb732f7a94 | ||
|
|
57a0c9c98d | ||
|
|
e83d5b64dc | ||
|
|
42d309fffc | ||
|
|
25725957e9 | ||
|
|
72f0751905 | ||
|
|
12cd67b7ca | ||
|
|
2a3d933cc6 | ||
|
|
96ebfc3b36 | ||
|
|
9ae8254e20 | ||
|
|
a95a086be7 | ||
|
|
dc1bc0f423 | ||
|
|
889eaba2b7 | ||
|
|
6fd2d7cfee | ||
|
|
c2db3de498 | ||
|
|
8d67211450 | ||
|
|
58d61dd639 | ||
|
|
3e738c8a6c | ||
|
|
2d1968f841 | ||
|
|
04f1a280e0 | ||
|
|
c6ccc2f690 | ||
|
|
6b547c3956 | ||
|
|
92974f9a98 | ||
|
|
94f2e7f9f9 | ||
|
|
80b6f9b0cb | ||
|
|
071197fb64 | ||
|
|
c49fb47fbe | ||
|
|
c8a720d17d | ||
|
|
c7db333abb | ||
|
|
85d1d1f870 | ||
|
|
2321939218 | ||
|
|
f9d624c504 | ||
|
|
1bc557c9c5 | ||
|
|
5010da6ab0 | ||
|
|
9d27e00ddb | ||
|
|
c479eace45 | ||
|
|
002052f8de | ||
|
|
eae2615348 | ||
|
|
a71a6b5acf | ||
|
|
ac441c7413 | ||
|
|
b9fa42a197 | ||
|
|
37b135a400 | ||
|
|
c9388ecc73 | ||
|
|
12b9fd4f03 | ||
|
|
503a5a24fb | ||
|
|
3519a5a026 | ||
|
|
e8dd99fa53 | ||
|
|
7f794a122f | ||
|
|
dfd3ead90d | ||
|
|
9cf500a3f6 | ||
|
|
7428f51217 | ||
|
|
552b36e657 | ||
|
|
086c1db2d9 | ||
|
|
33386bed66 | ||
|
|
5fece85491 | ||
|
|
49ccd2a8e1 | ||
|
|
1323afed8b | ||
|
|
a063c8c188 | ||
|
|
4f3b15e6ea | ||
|
|
17bf8dc99c | ||
|
|
29760b2eb7 | ||
|
|
767977c533 | ||
|
|
839bbcb039 | ||
|
|
3072498665 | ||
|
|
6ad44b76b9 | ||
|
|
d88f52ee7d | ||
|
|
399a6b2b47 | ||
|
|
451872527c | ||
|
|
3fbfa1885c | ||
|
|
3d5b2d41b5 | ||
|
|
30adc62232 | ||
|
|
96a54866ab | ||
|
|
51b9de037d | ||
|
|
96688aa646 | ||
|
|
a6350f717d | ||
|
|
f69876280c | ||
|
|
e93dcba46e | ||
|
|
9a9109431b | ||
|
|
bb30b9f913 | ||
|
|
094b47391d | ||
|
|
2c42f6a8b8 | ||
|
|
121c51f4f3 | ||
|
|
af3c722fec | ||
|
|
ca8d6f1072 | ||
|
|
8dc28b6c75 | ||
|
|
7bd5ccaad0 | ||
|
|
7261a5550f | ||
|
|
25063f75d7 | ||
|
|
af5c11874c | ||
|
|
4bc4d2c767 | ||
|
|
cf3789f045 | ||
|
|
b0bbfed238 | ||
|
|
c76d0e7be9 | ||
|
|
1b0d30aeb7 | ||
|
|
a76a961cdd | ||
|
|
f80b946bea | ||
|
|
a8857320a5 | ||
|
|
cbf212f981 | ||
|
|
4158664d2b | ||
|
|
4e8e7fb067 | ||
|
|
ef610802c7 | ||
|
|
5b73ea3cf6 | ||
|
|
eb9ca33414 | ||
|
|
78df016584 | ||
|
|
4665b3ebfb | ||
|
|
85a0d29d04 | ||
|
|
416d394cd9 | ||
|
|
0062194d74 | ||
|
|
10b626b3d5 | ||
|
|
2f53ad30ee | ||
|
|
5a3d85745a | ||
|
|
3f96e1623d | ||
|
|
88351275fe | ||
|
|
fa4f50739a | ||
|
|
dfef407499 | ||
|
|
8d6dc136e1 | ||
|
|
b73d87f5e5 | ||
|
|
babada8b5f | ||
|
|
80ec0431e8 | ||
|
|
545a5046f5 | ||
|
|
10afb9639a | ||
|
|
88e66ecf94 | ||
|
|
8cdc15c309 | ||
|
|
4cbf3f5ddd | ||
|
|
c9c03c3ee6 | ||
|
|
b3400559be | ||
|
|
1010c1b43e | ||
|
|
c4dc5b80b2 | ||
|
|
38076fd6ba | ||
|
|
1d13ff0b39 | ||
|
|
0c52ce6c8e | ||
|
|
a20c206de7 | ||
|
|
6c8221580c | ||
|
|
d6eb3afd13 | ||
|
|
1b4bc60999 | ||
|
|
4379b8b411 | ||
|
|
95f154985c | ||
|
|
9dcf878f1b | ||
|
|
7698316fda | ||
|
|
f6d5996ead | ||
|
|
3ef59b50c4 | ||
|
|
12d7479144 | ||
|
|
86c76cad74 | ||
|
|
1ef44f8243 | ||
|
|
3f0afab301 | ||
|
|
aca7f36b57 | ||
|
|
6d2f1188ac | ||
|
|
e8afadd52c | ||
|
|
36ee294e83 | ||
|
|
dd7e61d77f | ||
|
|
0e22cb2680 | ||
|
|
13e4c2a9b1 | ||
|
|
aa9d92d94a | ||
|
|
077f965426 | ||
|
|
8d11e0df7a | ||
|
|
324a8c91d0 | ||
|
|
8d116cc8a2 | ||
|
|
97f1c808ce | ||
|
|
9a1843ef2d | ||
|
|
1547d72cf3 | ||
|
|
2ea7f0ecad | ||
|
|
3b29556a0c | ||
|
|
c4d7f30e25 | ||
|
|
57fa355e56 | ||
|
|
f15042dbf0 | ||
|
|
643bc48a00 | ||
|
|
ec007559ff | ||
|
|
c80d81c80a | ||
|
|
61de1c1146 | ||
|
|
918086e253 | ||
|
|
38514e3c8d | ||
|
|
493a7f9823 | ||
|
|
19f5be231d | ||
|
|
7c5dc07016 | ||
|
|
b9e5be5f56 | ||
|
|
89f46f0fa1 | ||
|
|
d1788a5ddb | ||
|
|
34d5982bd5 | ||
|
|
a2732291cd | ||
|
|
2dab5015b7 | ||
|
|
4c08ae3ff6 | ||
|
|
fa9aa90813 | ||
|
|
5634ee973c | ||
|
|
93bb42a0b5 | ||
|
|
1e16b9384d | ||
|
|
5497a44037 | ||
|
|
f9c56dbb09 | ||
|
|
262262fbb2 | ||
|
|
86691ccff5 | ||
|
|
f16eaadd4f | ||
|
|
c1295bb9f1 | ||
|
|
c52415b219 | ||
|
|
82e1807769 | ||
|
|
f6029fb925 | ||
|
|
af5167b7f3 | ||
|
|
d9de9d5478 | ||
|
|
b3a97004f4 | ||
|
|
29b9d0a245 | ||
|
|
771df8a436 | ||
|
|
9321c7871f | ||
|
|
bce9a68b39 | ||
|
|
8609e68161 | ||
|
|
15338ab694 | ||
|
|
f1e4af2c29 | ||
|
|
c46c76a399 | ||
|
|
a6a0e05a1a | ||
|
|
573c4673ee | ||
|
|
681c6f21b7 | ||
|
|
606a01df70 | ||
|
|
453e01a091 | ||
|
|
ebf1acd33c | ||
|
|
0628030bf4 | ||
|
|
cf6cbbb881 | ||
|
|
3c95c92b0f | ||
|
|
22ae0ddf15 | ||
|
|
b1db7acf72 | ||
|
|
5babacad9b | ||
|
|
a5f5091041 | ||
|
|
2091d73ef5 | ||
|
|
513931dfea | ||
|
|
63c4697b46 | ||
|
|
7d703de7e9 | ||
|
|
336458d4b5 | ||
|
|
bd28dbee0e | ||
|
|
2bd360feca | ||
|
|
374b1192a3 | ||
|
|
106a57c5ae | ||
|
|
6548157293 | ||
|
|
13707f988b | ||
|
|
af347a8c86 | ||
|
|
27641ee490 | ||
|
|
1b72f4b749 | ||
|
|
2b7b74ad68 | ||
|
|
45ee620e9c | ||
|
|
4983eb6a23 | ||
|
|
3bab69e921 | ||
|
|
94376f46ad | ||
|
|
d16bb64fa4 | ||
|
|
ff024e3064 | ||
|
|
f0acdee4c5 | ||
|
|
2f3bfd1c13 | ||
|
|
5e2319c326 | ||
|
|
f88f8661ac | ||
|
|
d3e8f3fb62 | ||
|
|
bd07f121b9 | ||
|
|
6dd8de1774 | ||
|
|
7ca81170c7 | ||
|
|
98b23cce29 | ||
|
|
c8ae90fef6 | ||
|
|
8a3e9a6d44 | ||
|
|
86cbddc475 | ||
|
|
d25709cdea | ||
|
|
0285c22a2d | ||
|
|
4ccb56d0e6 | ||
|
|
d7f18f5019 | ||
|
|
f0d9a4e1a4 | ||
|
|
d4e375fc1e | ||
|
|
45f318d2ff | ||
|
|
cf31602bce | ||
|
|
7e64aa80d8 | ||
|
|
9abdc089f8 | ||
|
|
43f39f2e37 | ||
|
|
ec73881a4d | ||
|
|
d8ab7e8012 | ||
|
|
e77db59660 | ||
|
|
652c532292 | ||
|
|
a477b68109 | ||
|
|
ca825701dc | ||
|
|
f7e05dc755 | ||
|
|
4f29753726 | ||
|
|
37612118c8 | ||
|
|
049969971e | ||
|
|
d2c5f80e2e | ||
|
|
79de8f3c25 | ||
|
|
685dcaa1e6 | ||
|
|
2f1a1c3835 | ||
|
|
c913be0464 | ||
|
|
537893420b | ||
|
|
1ab5508324 | ||
|
|
319a6831a9 | ||
|
|
07acdd4aa8 | ||
|
|
b6378edcd6 | ||
|
|
3fbb41ecc9 | ||
|
|
73305861f5 | ||
|
|
0a643efa0c | ||
|
|
376a806bfb | ||
|
|
a6c7e61e61 | ||
|
|
62adabd0e0 | ||
|
|
28bde89172 | ||
|
|
743cfc0ad6 | ||
|
|
9947956d7b | ||
|
|
8341a7d472 | ||
|
|
e78c4e813c | ||
|
|
c6954de3ea | ||
|
|
8a14fff545 | ||
|
|
a8d70ac568 | ||
|
|
ab8c383082 | ||
|
|
c552fad6d4 | ||
|
|
155526a44e | ||
|
|
e741b0c257 | ||
|
|
9fe02ce1cd | ||
|
|
42c4d6aec7 | ||
|
|
c8c78bd4b9 | ||
|
|
770cb0ba97 | ||
|
|
485425cec7 | ||
|
|
7d4ebe114f | ||
|
|
6fff2cf9b6 | ||
|
|
c1b5220ee7 | ||
|
|
d63a435362 | ||
|
|
df45fed050 | ||
|
|
20eeddfb8a | ||
|
|
ddb80bb3d4 | ||
|
|
8a44b2cc7e | ||
|
|
090bc0c1a3 | ||
|
|
8ea7a3ee68 | ||
|
|
47177c9edc | ||
|
|
f6e32a832f | ||
|
|
c21c23bbba | ||
|
|
6922ccc0b9 | ||
|
|
40194a2a68 | ||
|
|
8aa0b19d83 | ||
|
|
f54bb2a330 | ||
|
|
dc8f947d7c | ||
|
|
71f3f3f1af | ||
|
|
3f7ba86255 | ||
|
|
dfe126f3e9 | ||
|
|
f53cc00c09 | ||
|
|
67dbc5f365 | ||
|
|
256ec6c52f | ||
|
|
ef764dde1c | ||
|
|
85e4777d5c | ||
|
|
1ea6672430 | ||
|
|
d933d6f2a4 | ||
|
|
92357b2d61 | ||
|
|
46216b0e83 | ||
|
|
5c73a6e206 | ||
|
|
c8c3281f06 | ||
|
|
9c00bdd86e | ||
|
|
92dc5e1fa4 | ||
|
|
50d4326e3b | ||
|
|
d5c6a833c8 | ||
|
|
1012514e0f | ||
|
|
28ef18a894 | ||
|
|
5bfba06a3b | ||
|
|
2e1dd00c80 | ||
|
|
730cacf672 | ||
|
|
4abba65ec7 | ||
|
|
33f613bf87 | ||
|
|
4aafdb185a | ||
|
|
be520829b8 | ||
|
|
13741fb99d | ||
|
|
08b218bfa5 | ||
|
|
5558c0e4cf | ||
|
|
7cf53252ee | ||
|
|
44266d6d92 | ||
|
|
58a3a3fa68 | ||
|
|
711b13801e | ||
|
|
f25962337d | ||
|
|
15c7f1317e | ||
|
|
91c41b6dde | ||
|
|
31ffbf1133 | ||
|
|
e33fffbde1 | ||
|
|
6d29c34da7 | ||
|
|
69e8ea7143 | ||
|
|
aac6a4cf13 | ||
|
|
86e302f5f3 | ||
|
|
485d5d4a18 | ||
|
|
85cc696f50 | ||
|
|
d454d5a4f5 | ||
|
|
a17bddf2a1 | ||
|
|
7e1d5954e5 | ||
|
|
ac2c96f5b1 | ||
|
|
bb3d45a386 | ||
|
|
fe7e8dc955 | ||
|
|
edfe1b2f8b | ||
|
|
1e02d599dc | ||
|
|
3795aaf42a | ||
|
|
774d8cd721 | ||
|
|
44ac202fbf | ||
|
|
4abf0e1e10 | ||
|
|
ffdd0620d0 | ||
|
|
9ac6cb9ce4 | ||
|
|
1c7a2269d6 | ||
|
|
90fae58b49 | ||
|
|
64a73e9293 | ||
|
|
0c1a4b5576 | ||
|
|
540b917a26 | ||
|
|
cfe39b7859 | ||
|
|
6ca1ad1e27 | ||
|
|
eb2196f5ce | ||
|
|
01eaf53bb3 | ||
|
|
2400f5782e | ||
|
|
726abe4deb | ||
|
|
138ed120dd | ||
|
|
2fda5f5c98 | ||
|
|
560e1e6c4b | ||
|
|
53ac8c7df2 | ||
|
|
d72b7ed4fb | ||
|
|
2deb55512f | ||
|
|
b189a21974 | ||
|
|
396161765b | ||
|
|
93edb3ff3a | ||
|
|
30a466ba38 | ||
|
|
6671032faf | ||
|
|
17ff3173d6 | ||
|
|
bf53f9280a | ||
|
|
61dffd8669 | ||
|
|
e8d0057710 | ||
|
|
3e9e27e98f | ||
|
|
6f2240aefd | ||
|
|
bd60c11bd8 | ||
|
|
38f6207f88 | ||
|
|
dd05b7f67f | ||
|
|
67ee87522a | ||
|
|
3f6d00d387 | ||
|
|
7ef2270ee7 | ||
|
|
456bbc02c8 | ||
|
|
1d4ea00d12 | ||
|
|
abf8150b2e | ||
|
|
2d7dc71b6f | ||
|
|
7d5fb5df3f | ||
|
|
28d146bed6 | ||
|
|
9506c860f6 | ||
|
|
baa88a1c14 | ||
|
|
d28948b143 | ||
|
|
a8c912ead6 | ||
|
|
24896427fc | ||
|
|
b5f52bf01c | ||
|
|
8105f91a02 | ||
|
|
b8b8dd5c15 | ||
|
|
9466dae4e5 | ||
|
|
5234bff579 | ||
|
|
51a01ca8a6 | ||
|
|
b8d315ff76 | ||
|
|
bb93686754 | ||
|
|
64ef0ad71a | ||
|
|
0f3c353dd3 | ||
|
|
f616ecf361 | ||
|
|
2ee4f9f34e | ||
|
|
c89ec5af1e | ||
|
|
0e38c5f39c | ||
|
|
7080a28efc | ||
|
|
fda2bf9c92 | ||
|
|
63e46e5f8d | ||
|
|
d6a13f4440 | ||
|
|
18c2676084 | ||
|
|
9387f7333e | ||
|
|
2f8134a7ff | ||
|
|
408e8e9f44 | ||
|
|
0af467d18f | ||
|
|
e5565a793e | ||
|
|
2bc8db9ca5 | ||
|
|
3848849013 | ||
|
|
0992ada2fe | ||
|
|
a3b0d8631f | ||
|
|
d7d13721d3 | ||
|
|
a351e74fe9 | ||
|
|
6e4f70b817 | ||
|
|
faea46710c | ||
|
|
5521910de7 | ||
|
|
3ff95d9074 | ||
|
|
1bae5dfff6 | ||
|
|
0c3fe52ef7 | ||
|
|
1f75ce30df | ||
|
|
0c898bdb07 | ||
|
|
660645c742 | ||
|
|
af02478ba0 | ||
|
|
337dcde9fa | ||
|
|
324e22accf | ||
|
|
dfb598cf33 | ||
|
|
3c0ed0309a | ||
|
|
5e0fe4c77c | ||
|
|
173cca5413 | ||
|
|
8beec4f0e7 | ||
|
|
45af2b1742 | ||
|
|
1398fac3f1 | ||
|
|
8b33975944 | ||
|
|
dfb12f0628 |
No files matched your search
@@ -1,20 +1,24 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
about: Help us improve KeyDB by reporting a bug
|
||||
title: '[BUG]'
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
** Log Files **
|
||||
These should be KeyDB logs, not syslogs or logs from your container manager. If you are reporting a crash there will be a line in your log stating:
|
||||
"=== KEYDB BUG REPORT START: Cut & paste starting from here ==="
|
||||
A short description of the bug.
|
||||
|
||||
Please copy everything after this line.
|
||||
**To reproduce**
|
||||
|
||||
**To Reproduce**
|
||||
Do you know how to reproduce this? If so please provide repro steps.
|
||||
Steps to reproduce the behavior and/or a minimal code sample.
|
||||
|
||||
**Expected behavior**
|
||||
|
||||
A description of what you expected to happen.
|
||||
|
||||
**Additional information**
|
||||
|
||||
Any additional information that is relevant to the problem.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Crash report
|
||||
about: Submit a crash report
|
||||
title: '[CRASH]'
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Crash report**
|
||||
|
||||
Paste the complete crash log between the quotes below. Please include a few lines from the log preceding the crash report to provide some context.
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
**Aditional information**
|
||||
|
||||
1. OS distribution and version
|
||||
2. Steps to reproduce (if any)
|
||||
@@ -1,20 +1,24 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
about: Suggest a feature for KeyDB
|
||||
title: '[NEW]'
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
**The problem/use-case that the feature addresses**
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
A description of the problem that the feature will solve, or the use-case with which the feature will be used.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
**Description of the feature**
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
A description of what you want to happen.
|
||||
|
||||
**Alternatives you've considered**
|
||||
|
||||
Any alternative solutions or features you've considered, including references to existing open and closed feature requests in this repository.
|
||||
|
||||
**Additional information**
|
||||
|
||||
Any additional information that is relevant to the feature request.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Other
|
||||
about: Can't find the right issue type? Use this one!
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
@@ -7,17 +7,17 @@ jobs:
|
||||
test-ubuntu-latest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
|
||||
make BUILD_TLS=yes -j2
|
||||
make KEYDB_CFLAGS='-Werror' KEYDB_CXXFLAGS='-Werror' BUILD_TLS=yes -j2
|
||||
- name: gen-cert
|
||||
run: ./utils/gen-test-certs.sh
|
||||
- name: test-tls
|
||||
run: |
|
||||
sudo apt-get -y install tcl8.5 tcl-tls
|
||||
sudo apt-get -y install tcl tcl-tls
|
||||
./runtest --clients 2 --verbose --tls
|
||||
- name: cluster-test
|
||||
run: |
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
./runtest-moduleapi
|
||||
|
||||
build-ubuntu-old:
|
||||
runs-on: ubuntu-16.04
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make -j2
|
||||
@@ -42,17 +42,28 @@ jobs:
|
||||
build-macos-latest:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: make -j2
|
||||
run: make KEYDB_CFLAGS='-Werror' KEYDB_CXXFLAGS='-Werror' -j2
|
||||
|
||||
build-libc-malloc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
|
||||
make MALLOC=libc -j2
|
||||
make KEYDB_CFLAGS='-Werror' KEYDB_CXXFLAGS='-Werror' MALLOC=libc -j2
|
||||
|
||||
build-ubuntu-32bit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install gcc-multilib g++-multilib libc6-dev-i386 lib32z1 uuid-dev:i386 libcurl4-openssl-dev:i386
|
||||
make KEYDB_CFLAGS='-Werror' KEYDB_CXXFLAGS='-Werror' 32bit -j2
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
name: Daily
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 7 * * *'
|
||||
|
||||
jobs:
|
||||
|
||||
test-jemalloc:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1200
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
|
||||
make
|
||||
- name: test
|
||||
run: |
|
||||
sudo apt-get install tcl8.5
|
||||
./runtest --accurate --verbose
|
||||
- name: module api test
|
||||
run: ./runtest-moduleapi --verbose
|
||||
|
||||
test-libc-malloc:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1200
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
|
||||
make MALLOC=libc
|
||||
- name: test
|
||||
run: |
|
||||
sudo apt-get install tcl8.5
|
||||
./runtest --accurate --verbose
|
||||
- name: module api test
|
||||
run: ./runtest-moduleapi --verbose
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
|
||||
make BUILD_TLS=yes -j2
|
||||
- name: "test (tls)"
|
||||
run: |
|
||||
sudo apt-get install tcl8.5 tcl-tls
|
||||
./utils/gen-test-certs.sh
|
||||
./runtest --accurate --verbose --tls
|
||||
- name: test
|
||||
run: ./runtest --accurate --verbose
|
||||
- name: module api test (tls)
|
||||
run: ./runtest-moduleapi --verbose --tls
|
||||
|
||||
test-ubuntu-arm:
|
||||
runs-on: [self-hosted, linux, arm]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
|
||||
make -j4
|
||||
- name: test
|
||||
run: |
|
||||
sudo apt-get -y install tcl8.5
|
||||
./runtest --clients 2 --verbose
|
||||
- name: module tests
|
||||
run: |
|
||||
./runtest-moduleapi
|
||||
|
||||
test-valgrind:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 14400
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
|
||||
make valgrind
|
||||
- name: test
|
||||
run: |
|
||||
sudo apt-get install tcl8.5 valgrind -y
|
||||
./runtest --valgrind --verbose --clients 1
|
||||
- name: module api test
|
||||
run: ./runtest-moduleapi --valgrind --verbose --clients 1
|
||||
@@ -2,7 +2,7 @@ name: Endurance
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 * * * *'
|
||||
- cron: '30 * * * *'
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ redis-check-rdb
|
||||
keydb-check-rdb
|
||||
redis-check-dump
|
||||
keydb-check-dump
|
||||
keydb-diagnostic-tool
|
||||
redis-cli
|
||||
redis-sentinel
|
||||
redis-server
|
||||
@@ -48,9 +49,14 @@ src/nodes.conf
|
||||
deps/lua/src/lua
|
||||
deps/lua/src/luac
|
||||
deps/lua/src/liblua.a
|
||||
tests/tls/*
|
||||
.make-*
|
||||
.prerequisites
|
||||
*.dSYM
|
||||
Makefile.dep
|
||||
.vscode/*
|
||||
.idea/*
|
||||
.ccls
|
||||
.ccls-cache/*
|
||||
compile_commands.json
|
||||
keydb.code-workspace
|
||||
+641
-2096
File diff suppressed because it is too large.
Load diff
@@ -1 +1 @@
|
||||
Please check https://github.com/antirez/redis/issues
|
||||
Please check https://github.com/redis/redis/issues
|
||||
@@ -0,0 +1,96 @@
|
||||
Contributor Covenant Code of Conduct
|
||||
Our Pledge
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
Our Standards
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others’ private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
Enforcement Responsibilities
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
Scope
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
Enforcement
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
this email address: redis@redis.io.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
Enforcement Guidelines
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
1. Correction
|
||||
Community Impact: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
Consequence: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
2. Warning
|
||||
Community Impact: A violation through a single incident or series
|
||||
of actions.
|
||||
Consequence: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
3. Temporary Ban
|
||||
Community Impact: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
Consequence: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
4. Permanent Ban
|
||||
Community Impact: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
Consequence: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
Attribution
|
||||
This Code of Conduct is adapted from the Contributor Covenant,
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
Community Impact Guidelines were inspired by Mozilla’s code of conduct
|
||||
enforcement ladder.
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,50 +0,0 @@
|
||||
Note: by contributing code to the Redis project in any form, including sending
|
||||
a pull request via Github, a code fragment or patch via private email or
|
||||
public discussion groups, you agree to release your code under the terms
|
||||
of the BSD license that you can find in the COPYING file included in the Redis
|
||||
source distribution. You will include BSD license in the COPYING file within
|
||||
each source file that you contribute.
|
||||
|
||||
# IMPORTANT: HOW TO USE REDIS GITHUB ISSUES
|
||||
|
||||
* Github issues SHOULD ONLY BE USED to report bugs, and for DETAILED feature
|
||||
requests. Everything else belongs to the Redis Google Group:
|
||||
|
||||
https://groups.google.com/forum/m/#!forum/Redis-db
|
||||
|
||||
PLEASE DO NOT POST GENERAL QUESTIONS that are not about bugs or suspected
|
||||
bugs in the Github issues system. We'll be very happy to help you and provide
|
||||
all the support in the mailing list.
|
||||
|
||||
There is also an active community of Redis users at Stack Overflow:
|
||||
|
||||
http://stackoverflow.com/questions/tagged/redis
|
||||
|
||||
# How to provide a patch for a new feature
|
||||
|
||||
1. If it is a major feature or a semantical change, please don't start coding
|
||||
straight away: if your feature is not a conceptual fit you'll lose a lot of
|
||||
time writing the code without any reason. Start by posting in the mailing list
|
||||
and creating an issue at Github with the description of, exactly, what you want
|
||||
to accomplish and why. Use cases are important for features to be accepted.
|
||||
Here you'll see if there is consensus about your idea.
|
||||
|
||||
2. If in step 1 you get an acknowledgment from the project leaders, use the
|
||||
following procedure to submit a patch:
|
||||
|
||||
a. Fork Redis on github ( http://help.github.com/fork-a-repo/ )
|
||||
b. Create a topic branch (git checkout -b my_branch)
|
||||
c. Push to your branch (git push origin my_branch)
|
||||
d. Initiate a pull request on github ( https://help.github.com/articles/creating-a-pull-request/ )
|
||||
e. Done :)
|
||||
|
||||
3. Keep in mind that we are very overloaded, so issues and PRs sometimes wait
|
||||
for a *very* long time. However this is not lack of interest, as the project
|
||||
gets more and more users, we find ourselves in a constant need to prioritize
|
||||
certain issues/PRs over others. If you think your issue/PR is very important
|
||||
try to popularize it, have other users commenting and sharing their point of
|
||||
view and so forth. This helps.
|
||||
|
||||
4. For minor fixes just open a pull request on Github.
|
||||
|
||||
Thanks!
|
||||
@@ -1,5 +1,6 @@
|
||||
Copyright (c) 2006-2015, Salvatore Sanfilippo
|
||||
Copyright (C) 2019, John Sully
|
||||
Copyright (c) 2006-2020, Salvatore Sanfilippo
|
||||
Copyright (C) 2019-2021, John Sully
|
||||
Copyright (C) 2020-2021, EQ Alpha Technology Ltd.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||

|
||||
[](https://stackshare.io/eq-alpha-technology-inc/eq-alpha-technology-inc)
|
||||
|
||||
##### New! Want to extend KeyDB with Javascript? Try [ModJS](https://github.com/JohnSully/ModJS)
|
||||
##### Want to extend KeyDB with Javascript? Try [ModJS](https://github.com/JohnSully/ModJS)
|
||||
|
||||
##### Need Help? Check out our extensive [documentation](https://docs.keydb.dev).
|
||||
|
||||
##### Have feedback? Take our quick survey: https://www.surveymonkey.com/r/Y9XNS93
|
||||
##### NEW!!! KeyDB now has a Slack Community Workspace. Click [here](https://docs.keydb.dev/slack/) to learn more and join the KeyDB Community Slack workspace.
|
||||
|
||||
What is KeyDB?
|
||||
--------------
|
||||
@@ -15,11 +15,13 @@ KeyDB is a high performance fork of Redis with a focus on multithreading, memory
|
||||
|
||||
KeyDB maintains full compatibility with the Redis protocol, modules, and scripts. This includes the atomicity guarantees for scripts and transactions. Because KeyDB keeps in sync with Redis development KeyDB is a superset of Redis functionality, making KeyDB a drop in replacement for existing Redis deployments.
|
||||
|
||||
On the same hardware KeyDB can perform twice as many queries per second as Redis, with 60% lower latency. Active-Replication simplifies hot-spare failover allowing you to easily distribute writes over replicas and use simple TCP based load balancing/failover. KeyDB's higher performance allows you to do more on less hardware which reduces operation costs and complexity.
|
||||
On the same hardware KeyDB can achieve significantly higher throughput than Redis. Active-Replication simplifies hot-spare failover allowing you to easily distribute writes over replicas and use simple TCP based load balancing/failover. KeyDB's higher performance allows you to do more on less hardware which reduces operation costs and complexity.
|
||||
|
||||
<img src="https://keydb.dev/assets/img/blog/5x_opspersecVSdatasize.PNG"/>
|
||||
The chart below compares several KeyDB and Redis setups, including the latest Redis6 io-threads option, and TLS benchmarks.
|
||||
|
||||
See the full benchmark results and setup information here: https://docs.keydb.dev/blog/2019/10/07/blog-post/
|
||||
<img src="https://docs.keydb.dev/img/blog/2020-09-15/ops_comparison.png"/>
|
||||
|
||||
See the full benchmark results and setup information here: https://docs.keydb.dev/blog/2020/09/29/blog-post/
|
||||
|
||||
Why fork Redis?
|
||||
---------------
|
||||
@@ -31,19 +33,13 @@ Because of this difference of opinion features which are right for KeyDB may not
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
Try our docker container: https://hub.docker.com/r/eqalpha/keydb
|
||||
Check out KeyDB's [Docker Image](https://hub.docker.com/r/eqalpha/keydb)
|
||||
|
||||
Talk on Gitter: https://gitter.im/KeyDB
|
||||
Join us on [Slack](https://docs.keydb.dev/slack/)
|
||||
|
||||
Visit our Website: https://keydb.dev
|
||||
Post to the [Community Forum](https://community.keydb.dev)
|
||||
|
||||
See options for channel partners and support contracts: https://keydb.dev/support.html
|
||||
|
||||
Learn with KeyDB’s official documentation site: https://docs.keydb.dev
|
||||
|
||||
[Subscribe to the KeyDB mailing list](https://eqalpha.us20.list-manage.com/subscribe/post?u=978f486c2f95589b24591a9cc&id=4ab9220500)
|
||||
|
||||
Management GUI: We recommend [FastoNoSQL](https://fastonosql.com/) which has official KeyDB support.
|
||||
Learn more through KeyDB's [Documentation & Learning Center](https://docs.keydb.dev)
|
||||
|
||||
|
||||
Benchmarking KeyDB
|
||||
@@ -82,6 +78,8 @@ Building KeyDB
|
||||
|
||||
KeyDB can be compiled and is tested for use on Linux. KeyDB currently relies on SO_REUSEPORT's load balancing behavior which is available only in Linux. When we support marshalling connections across threads we plan to support other operating systems such as FreeBSD.
|
||||
|
||||
More on CentOS/Archlinux/Alpine/Debian/Ubuntu dependencies and builds can be found here: https://docs.keydb.dev/docs/build/
|
||||
|
||||
Install dependencies:
|
||||
|
||||
% sudo apt install build-essential nasm autotools-dev autoconf libjemalloc-dev tcl tcl-dev uuid-dev libcurl4-openssl-dev
|
||||
@@ -95,9 +93,14 @@ libssl-dev on Debian/Ubuntu) and run:
|
||||
|
||||
% make BUILD_TLS=yes
|
||||
|
||||
You can enable flash support with:
|
||||
To build with systemd support, you'll need systemd development libraries (such
|
||||
as libsystemd-dev on Debian/Ubuntu or systemd-devel on CentOS) and run:
|
||||
|
||||
% make MALLOC=memkind
|
||||
% make USE_SYSTEMD=yes
|
||||
|
||||
To append a suffix to KeyDB program names, use:
|
||||
|
||||
% make PROG_SUFFIX="-alt"
|
||||
|
||||
***Note that the following dependencies may be needed:
|
||||
% sudo apt-get install autoconf autotools-dev libnuma-dev libtool
|
||||
@@ -109,10 +112,17 @@ installed):
|
||||
% ./runtest --tls
|
||||
|
||||
|
||||
If TLS is built, running the tests with TLS enabled (you will need `tcl-tls`
|
||||
installed):
|
||||
|
||||
% ./utils/gen-test-certs.sh
|
||||
% ./runtest --tls
|
||||
|
||||
|
||||
Fixing build problems with dependencies or cached build options
|
||||
---------
|
||||
|
||||
KeyDB has some dependencies which are included into the `deps` directory.
|
||||
KeyDB has some dependencies which are included in the `deps` directory.
|
||||
`make` does not automatically rebuild dependencies even if something in
|
||||
the source code of dependencies changes.
|
||||
|
||||
@@ -139,7 +149,7 @@ with a 64 bit target, or the other way around, you need to perform a
|
||||
In case of build errors when trying to build a 32 bit binary of KeyDB, try
|
||||
the following steps:
|
||||
|
||||
* Install the packages libc6-dev-i386 (also try g++-multilib).
|
||||
* Install the package libc6-dev-i386 (also try g++-multilib).
|
||||
* Try using the following command line instead of `make 32bit`:
|
||||
`make CFLAGS="-m32 -march=native" LDFLAGS="-m32"`
|
||||
|
||||
@@ -160,18 +170,30 @@ To compile against jemalloc on Mac OS X systems, use:
|
||||
|
||||
% make MALLOC=jemalloc
|
||||
|
||||
Monotonic clock
|
||||
---------------
|
||||
|
||||
By default, KeyDB will build using the POSIX clock_gettime function as the
|
||||
monotonic clock source. On most modern systems, the internal processor clock
|
||||
can be used to improve performance. Cautions can be found here:
|
||||
http://oliveryang.net/2015/09/pitfalls-of-TSC-usage/
|
||||
|
||||
To build with support for the processor's internal instruction clock, use:
|
||||
|
||||
% make CFLAGS="-DUSE_PROCESSOR_CLOCK"
|
||||
|
||||
Verbose build
|
||||
-------------
|
||||
|
||||
KeyDB will build with a user friendly colorized output by default.
|
||||
If you want to see a more verbose output use the following:
|
||||
If you want to see a more verbose output, use the following:
|
||||
|
||||
% make V=1
|
||||
|
||||
Running KeyDB
|
||||
-------------
|
||||
|
||||
To run KeyDB with the default configuration just type:
|
||||
To run KeyDB with the default configuration, just type:
|
||||
|
||||
% cd src
|
||||
% ./keydb-server
|
||||
@@ -224,7 +246,7 @@ You can find the list of all the available commands at https://docs.keydb.dev/do
|
||||
Installing KeyDB
|
||||
-----------------
|
||||
|
||||
In order to install KeyDB binaries into /usr/local/bin just use:
|
||||
In order to install KeyDB binaries into /usr/local/bin, just use:
|
||||
|
||||
% make install
|
||||
|
||||
@@ -233,8 +255,8 @@ different destination.
|
||||
|
||||
Make install will just install binaries in your system, but will not configure
|
||||
init scripts and configuration files in the appropriate place. This is not
|
||||
needed if you want just to play a bit with KeyDB, but if you are installing
|
||||
it the proper way for a production system, we have a script doing this
|
||||
needed if you just want to play a bit with KeyDB, but if you are installing
|
||||
it the proper way for a production system, we have a script that does this
|
||||
for Ubuntu and Debian systems:
|
||||
|
||||
% cd utils
|
||||
|
||||
@@ -13,13 +13,13 @@ Run `make BUILD_TLS=yes`.
|
||||
|
||||
### Tests
|
||||
|
||||
To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
|
||||
To run KeyDB test suite with TLS, you'll need TLS support for TCL (i.e.
|
||||
`tcl-tls` package on Debian/Ubuntu).
|
||||
|
||||
1. Run `./utils/gen-test-certs.sh` to generate a root CA and a server
|
||||
certificate.
|
||||
|
||||
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run Redis and Redis
|
||||
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run KeyDB and KeyDB
|
||||
Cluster tests in TLS mode.
|
||||
|
||||
### Running manually
|
||||
@@ -27,23 +27,23 @@ To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
|
||||
To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was
|
||||
invoked so sample certificates/keys are available):
|
||||
|
||||
./src/redis-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/redis.crt \
|
||||
--tls-key-file ./tests/tls/redis.key \
|
||||
./src/keydb-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/client.crt \
|
||||
--tls-key-file ./tests/tls/client.key \
|
||||
--tls-ca-cert-file ./tests/tls/ca.crt
|
||||
|
||||
To connect to this Redis server with `redis-cli`:
|
||||
To connect to this Redis server with `keydb-cli`:
|
||||
|
||||
./src/redis-cli --tls \
|
||||
--cert ./tests/tls/redis.crt \
|
||||
--key ./tests/tls/redis.key \
|
||||
./src/keydb-cli --tls \
|
||||
--cert ./tests/tls/keydb.crt \
|
||||
--key ./tests/tls/keydb.key \
|
||||
--cacert ./tests/tls/ca.crt
|
||||
|
||||
This will disable TCP and enable TLS on port 6379. It's also possible to have
|
||||
both TCP and TLS available, but you'll need to assign different ports.
|
||||
|
||||
To make a Replica connect to the master using TLS, use `--tls-replication yes`,
|
||||
and to make Redis Cluster use TLS across nodes use `--tls-cluster yes`.
|
||||
and to make KeyDB Cluster use TLS across nodes use `--tls-cluster yes`.
|
||||
|
||||
Connections
|
||||
-----------
|
||||
@@ -56,18 +56,18 @@ Note that unlike Redis, KeyDB fully supports multithreading of TLS connections.
|
||||
To-Do List
|
||||
----------
|
||||
|
||||
- [ ] redis-benchmark support. The current implementation is a mix of using
|
||||
- [ ] keydb-benchmark support. The current implementation is a mix of using
|
||||
hiredis for parsing and basic networking (establishing connections), but
|
||||
directly manipulating sockets for most actions. This will need to be cleaned
|
||||
up for proper TLS support. The best approach is probably to migrate to hiredis
|
||||
async mode.
|
||||
- [ ] redis-cli `--slave` and `--rdb` support.
|
||||
- [ ] keydb-cli `--slave` and `--rdb` support.
|
||||
|
||||
Multi-port
|
||||
----------
|
||||
|
||||
Consider the implications of allowing TLS to be configured on a separate port,
|
||||
making Redis listening on multiple ports:
|
||||
making KeyDB listening on multiple ports:
|
||||
|
||||
1. Startup banner port notification
|
||||
2. Proctitle
|
||||
|
||||
Vendored
+10
-3
@@ -37,6 +37,7 @@ distclean:
|
||||
-(cd linenoise && $(MAKE) clean) > /dev/null || true
|
||||
-(cd lua && $(MAKE) clean) > /dev/null || true
|
||||
-(cd jemalloc && [ -f Makefile ] && $(MAKE) distclean) > /dev/null || true
|
||||
-(cd hdr_histogram && $(MAKE) clean) > /dev/null || true
|
||||
-(rm -f .make-*)
|
||||
|
||||
.PHONY: distclean
|
||||
@@ -62,18 +63,24 @@ memkind:
|
||||
cd memkind && $(MAKE)
|
||||
|
||||
|
||||
hdr_histogram: .make-prerequisites
|
||||
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
||||
cd hdr_histogram && $(MAKE)
|
||||
|
||||
.PHONY: hdr_histogram
|
||||
|
||||
ifeq ($(uname_S),SunOS)
|
||||
# Make isinf() available
|
||||
LUA_CFLAGS= -D__C99FEATURES__=1
|
||||
endif
|
||||
|
||||
LUA_CFLAGS+= -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' $(CFLAGS)
|
||||
LUA_CFLAGS+= -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -DLUA_USE_MKSTEMP $(CFLAGS)
|
||||
LUA_LDFLAGS+= $(LDFLAGS)
|
||||
# lua's Makefile defines AR="ar rcu", which is unusual, and makes it more
|
||||
# challenging to cross-compile lua (and redis). These defines make it easier
|
||||
# to fit redis into cross-compilation environments, which typically set AR.
|
||||
AR=ar
|
||||
ARFLAGS=rcu
|
||||
ARFLAGS=rc
|
||||
|
||||
lua: .make-prerequisites
|
||||
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
||||
@@ -86,7 +93,7 @@ JEMALLOC_LDFLAGS= $(LDFLAGS)
|
||||
|
||||
jemalloc: .make-prerequisites
|
||||
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
||||
cd jemalloc && ./configure --with-version=5.1.0-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ --enable-cc-silence CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
|
||||
cd jemalloc && ./configure --with-version=5.2.1-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
|
||||
cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
|
||||
|
||||
.PHONY: jemalloc
|
||||
Vendored
+6
-6
@@ -17,11 +17,11 @@ active defragmentation logic. However this feature of Redis is not mandatory
|
||||
and Redis is able to understand if the Jemalloc version it is compiled
|
||||
against supports such Redis-specific modifications. So in theory, if you
|
||||
are not interested in the active defragmentation, you can replace Jemalloc
|
||||
just following tose steps:
|
||||
just following these steps:
|
||||
|
||||
1. Remove the jemalloc directory.
|
||||
2. Substitute it with the new jemalloc source tree.
|
||||
3. Edit the Makefile localted in the same directory as the README you are
|
||||
3. Edit the Makefile located in the same directory as the README you are
|
||||
reading, and change the --with-version in the Jemalloc configure script
|
||||
options with the version you are using. This is required because otherwise
|
||||
Jemalloc configuration script is broken and will not work nested in another
|
||||
@@ -33,7 +33,7 @@ If you want to upgrade Jemalloc while also providing support for
|
||||
active defragmentation, in addition to the above steps you need to perform
|
||||
the following additional steps:
|
||||
|
||||
5. In Jemalloc three, file `include/jemalloc/jemalloc_macros.h.in`, make sure
|
||||
5. In Jemalloc tree, file `include/jemalloc/jemalloc_macros.h.in`, make sure
|
||||
to add `#define JEMALLOC_FRAG_HINT`.
|
||||
6. Implement the function `je_get_defrag_hint()` inside `src/jemalloc.c`. You
|
||||
can see how it is implemented in the current Jemalloc source tree shipped
|
||||
@@ -47,9 +47,9 @@ Hiredis
|
||||
Hiredis uses the SDS string library, that must be the same version used inside Redis itself. Hiredis is also very critical for Sentinel. Historically Redis often used forked versions of hiredis in a way or the other. In order to upgrade it is advised to take a lot of care:
|
||||
|
||||
1. Check with diff if hiredis API changed and what impact it could have in Redis.
|
||||
2. Make sure thet the SDS library inside Hiredis and inside Redis are compatible.
|
||||
2. Make sure that the SDS library inside Hiredis and inside Redis are compatible.
|
||||
3. After the upgrade, run the Redis Sentinel test.
|
||||
4. Check manually that redis-cli and redis-benchmark behave as expecteed, since we have no tests for CLI utilities currently.
|
||||
4. Check manually that redis-cli and redis-benchmark behave as expected, since we have no tests for CLI utilities currently.
|
||||
|
||||
Linenoise
|
||||
---
|
||||
@@ -77,6 +77,6 @@ and our version:
|
||||
|
||||
1. Makefile is modified to allow a different compiler than GCC.
|
||||
2. We have the implementation source code, and directly link to the following external libraries: `lua_cjson.o`, `lua_struct.o`, `lua_cmsgpack.o` and `lua_bit.o`.
|
||||
3. There is a security fix in `ldo.c`, line 498: The check for `LUA_SIGNATURE[0]` is removed in order toa void direct bytecode execution.
|
||||
3. There is a security fix in `ldo.c`, line 498: The check for `LUA_SIGNATURE[0]` is removed in order to avoid direct bytecode execution.
|
||||
|
||||
|
||||
Vendored
+121
@@ -0,0 +1,121 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
The code in this repository code was Written by Gil Tene, Michael Barker,
|
||||
and Matt Warren, and released to the public domain, as explained at
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
For users of this code who wish to consume it under the "BSD" license
|
||||
rather than under the public domain or CC0 contribution text mentioned
|
||||
above, the code found under this directory is *also* provided under the
|
||||
following license (commonly referred to as the BSD 2-Clause License). This
|
||||
license does not detract from the above stated release of the code into
|
||||
the public domain, and simply represents an additional license granted by
|
||||
the Author.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
** Beginning of "BSD 2-Clause License" text. **
|
||||
|
||||
Copyright (c) 2012, 2013, 2014 Gil Tene
|
||||
Copyright (c) 2014 Michael Barker
|
||||
Copyright (c) 2014 Matt Warren
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
STD=
|
||||
WARN= -Wall
|
||||
OPT= -Os
|
||||
|
||||
R_CFLAGS= $(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS)
|
||||
R_LDFLAGS= $(LDFLAGS)
|
||||
DEBUG= -g
|
||||
|
||||
R_CC=$(CC) $(R_CFLAGS)
|
||||
R_LD=$(CC) $(R_LDFLAGS)
|
||||
|
||||
hdr_histogram.o: hdr_histogram.h hdr_histogram.c
|
||||
|
||||
.c.o:
|
||||
$(R_CC) -c $<
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
|
||||
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
HdrHistogram_c v0.11.0
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
This port contains a subset of the 'C' version of High Dynamic Range (HDR) Histogram available at [github.com/HdrHistogram/HdrHistogram_c](https://github.com/HdrHistogram/HdrHistogram_c).
|
||||
|
||||
|
||||
The code present on `hdr_histogram.c`, `hdr_histogram.h`, and `hdr_atomic.c` was Written by Gil Tene, Michael Barker,
|
||||
and Matt Warren, and released to the public domain, as explained at
|
||||
http://creativecommons.org/publicdomain/zero/1.0/.
|
||||
Vendored
+146
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* hdr_atomic.h
|
||||
* Written by Philip Orwig and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#ifndef HDR_ATOMIC_H__
|
||||
#define HDR_ATOMIC_H__
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <intrin.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static void __inline * hdr_atomic_load_pointer(void** pointer)
|
||||
{
|
||||
_ReadBarrier();
|
||||
return *pointer;
|
||||
}
|
||||
|
||||
static void hdr_atomic_store_pointer(void** pointer, void* value)
|
||||
{
|
||||
_WriteBarrier();
|
||||
*pointer = value;
|
||||
}
|
||||
|
||||
static int64_t __inline hdr_atomic_load_64(int64_t* field)
|
||||
{
|
||||
_ReadBarrier();
|
||||
return *field;
|
||||
}
|
||||
|
||||
static void __inline hdr_atomic_store_64(int64_t* field, int64_t value)
|
||||
{
|
||||
_WriteBarrier();
|
||||
*field = value;
|
||||
}
|
||||
|
||||
static int64_t __inline hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
return _InterlockedExchange64(field, value);
|
||||
#else
|
||||
int64_t comparand;
|
||||
int64_t initial_value = *field;
|
||||
do
|
||||
{
|
||||
comparand = initial_value;
|
||||
initial_value = _InterlockedCompareExchange64(field, value, comparand);
|
||||
}
|
||||
while (comparand != initial_value);
|
||||
|
||||
return initial_value;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t __inline hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
return _InterlockedExchangeAdd64(field, value) + value;
|
||||
#else
|
||||
int64_t comparand;
|
||||
int64_t initial_value = *field;
|
||||
do
|
||||
{
|
||||
comparand = initial_value;
|
||||
initial_value = _InterlockedCompareExchange64(field, comparand + value, comparand);
|
||||
}
|
||||
while (comparand != initial_value);
|
||||
|
||||
return initial_value + value;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool __inline hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
|
||||
{
|
||||
return *expected == _InterlockedCompareExchange64(field, desired, *expected);
|
||||
}
|
||||
|
||||
#elif defined(__ATOMIC_SEQ_CST)
|
||||
|
||||
#define hdr_atomic_load_pointer(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
#define hdr_atomic_store_pointer(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
|
||||
#define hdr_atomic_load_64(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
#define hdr_atomic_store_64(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
|
||||
#define hdr_atomic_exchange_64(f,i) __atomic_exchange_n(f,i, __ATOMIC_SEQ_CST)
|
||||
#define hdr_atomic_add_fetch_64(field, value) __atomic_add_fetch(field, value, __ATOMIC_SEQ_CST)
|
||||
#define hdr_atomic_compare_exchange_64(field, expected, desired) __atomic_compare_exchange_n(field, expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static inline void* hdr_atomic_load_pointer(void** pointer)
|
||||
{
|
||||
void* p = *pointer;
|
||||
asm volatile ("" ::: "memory");
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void hdr_atomic_store_pointer(void** pointer, void* value)
|
||||
{
|
||||
asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*pointer));
|
||||
}
|
||||
|
||||
static inline int64_t hdr_atomic_load_64(int64_t* field)
|
||||
{
|
||||
int64_t i = *field;
|
||||
asm volatile ("" ::: "memory");
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void hdr_atomic_store_64(int64_t* field, int64_t value)
|
||||
{
|
||||
asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*field));
|
||||
}
|
||||
|
||||
static inline int64_t hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
|
||||
{
|
||||
int64_t result = 0;
|
||||
asm volatile ("lock; xchgq %1, %2" : "=r" (result), "+q" (value), "+m" (*field));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int64_t hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
|
||||
{
|
||||
return __sync_add_and_fetch(field, value);
|
||||
}
|
||||
|
||||
static inline bool hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
|
||||
{
|
||||
int64_t original;
|
||||
asm volatile( "lock; cmpxchgq %2, %1" : "=a"(original), "+m"(*field) : "q"(desired), "0"(*expected));
|
||||
return original == *expected;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Unable to determine atomic operations for your platform"
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HDR_ATOMIC_H__ */
|
||||
Vendored
+1155
File diff suppressed because it is too large.
Load diff
Vendored
+509
@@ -0,0 +1,509 @@
|
||||
/**
|
||||
* hdr_histogram.h
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*
|
||||
* The source for the hdr_histogram utilises a few C99 constructs, specifically
|
||||
* the use of stdint/stdbool and inline variable declaration.
|
||||
*/
|
||||
|
||||
#ifndef HDR_HISTOGRAM_H
|
||||
#define HDR_HISTOGRAM_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct hdr_histogram
|
||||
{
|
||||
int64_t lowest_trackable_value;
|
||||
int64_t highest_trackable_value;
|
||||
int32_t unit_magnitude;
|
||||
int32_t significant_figures;
|
||||
int32_t sub_bucket_half_count_magnitude;
|
||||
int32_t sub_bucket_half_count;
|
||||
int64_t sub_bucket_mask;
|
||||
int32_t sub_bucket_count;
|
||||
int32_t bucket_count;
|
||||
int64_t min_value;
|
||||
int64_t max_value;
|
||||
int32_t normalizing_index_offset;
|
||||
double conversion_ratio;
|
||||
int32_t counts_len;
|
||||
int64_t total_count;
|
||||
int64_t* counts;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allocate the memory and initialise the hdr_histogram.
|
||||
*
|
||||
* Due to the size of the histogram being the result of some reasonably
|
||||
* involved math on the input parameters this function it is tricky to stack allocate.
|
||||
* The histogram should be released with hdr_close
|
||||
*
|
||||
* @param lowest_trackable_value The smallest possible value to be put into the
|
||||
* histogram.
|
||||
* @param highest_trackable_value The largest possible value to be put into the
|
||||
* histogram.
|
||||
* @param significant_figures The level of precision for this histogram, i.e. the number
|
||||
* of figures in a decimal number that will be maintained. E.g. a value of 3 will mean
|
||||
* the results from the histogram will be accurate up to the first three digits. Must
|
||||
* be a value between 1 and 5 (inclusive).
|
||||
* @param result Output parameter to capture allocated histogram.
|
||||
* @return 0 on success, EINVAL if lowest_trackable_value is < 1 or the
|
||||
* significant_figure value is outside of the allowed range, ENOMEM if malloc
|
||||
* failed.
|
||||
*/
|
||||
int hdr_init(
|
||||
int64_t lowest_trackable_value,
|
||||
int64_t highest_trackable_value,
|
||||
int significant_figures,
|
||||
struct hdr_histogram** result);
|
||||
|
||||
/**
|
||||
* Free the memory and close the hdr_histogram.
|
||||
*
|
||||
* @param h The histogram you want to close.
|
||||
*/
|
||||
void hdr_close(struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Allocate the memory and initialise the hdr_histogram. This is the equivalent of calling
|
||||
* hdr_init(1, highest_trackable_value, significant_figures, result);
|
||||
*
|
||||
* @deprecated use hdr_init.
|
||||
*/
|
||||
int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result);
|
||||
|
||||
|
||||
/**
|
||||
* Reset a histogram to zero - empty out a histogram and re-initialise it
|
||||
*
|
||||
* If you want to re-use an existing histogram, but reset everything back to zero, this
|
||||
* is the routine to use.
|
||||
*
|
||||
* @param h The histogram you want to reset to empty.
|
||||
*
|
||||
*/
|
||||
void hdr_reset(struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Get the memory size of the hdr_histogram.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @return The amount of memory used by the hdr_histogram in bytes
|
||||
*/
|
||||
size_t hdr_get_memory_size(struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Records a value in the histogram, will round this value of to a precision at or better
|
||||
* than the significant_figure specified at construction time.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_value(struct hdr_histogram* h, int64_t value);
|
||||
|
||||
/**
|
||||
* Records a value in the histogram, will round this value of to a precision at or better
|
||||
* than the significant_figure specified at construction time.
|
||||
*
|
||||
* Will record this value atomically, however the whole structure may appear inconsistent
|
||||
* when read concurrently with this update. Do NOT mix calls to this method with calls
|
||||
* to non-atomic updates.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_value_atomic(struct hdr_histogram* h, int64_t value);
|
||||
|
||||
/**
|
||||
* Records count values in the histogram, will round this value of to a
|
||||
* precision at or better than the significant_figure specified at construction
|
||||
* time.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @param count Number of 'value's to add to the histogram
|
||||
* @return false if any value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count);
|
||||
|
||||
/**
|
||||
* Records count values in the histogram, will round this value of to a
|
||||
* precision at or better than the significant_figure specified at construction
|
||||
* time.
|
||||
*
|
||||
* Will record this value atomically, however the whole structure may appear inconsistent
|
||||
* when read concurrently with this update. Do NOT mix calls to this method with calls
|
||||
* to non-atomic updates.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @param count Number of 'value's to add to the histogram
|
||||
* @return false if any value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count);
|
||||
|
||||
/**
|
||||
* Record a value in the histogram and backfill based on an expected interval.
|
||||
*
|
||||
* Records a value in the histogram, will round this value of to a precision at or better
|
||||
* than the significant_figure specified at contruction time. This is specifically used
|
||||
* for recording latency. If the value is larger than the expected_interval then the
|
||||
* latency recording system has experienced co-ordinated omission. This method fills in the
|
||||
* values that would have occured had the client providing the load not been blocked.
|
||||
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @param expected_interval The delay between recording values.
|
||||
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expexcted_interval);
|
||||
|
||||
/**
|
||||
* Record a value in the histogram and backfill based on an expected interval.
|
||||
*
|
||||
* Records a value in the histogram, will round this value of to a precision at or better
|
||||
* than the significant_figure specified at contruction time. This is specifically used
|
||||
* for recording latency. If the value is larger than the expected_interval then the
|
||||
* latency recording system has experienced co-ordinated omission. This method fills in the
|
||||
* values that would have occured had the client providing the load not been blocked.
|
||||
*
|
||||
* Will record this value atomically, however the whole structure may appear inconsistent
|
||||
* when read concurrently with this update. Do NOT mix calls to this method with calls
|
||||
* to non-atomic updates.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @param expected_interval The delay between recording values.
|
||||
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expexcted_interval);
|
||||
|
||||
/**
|
||||
* Record a value in the histogram 'count' times. Applies the same correcting logic
|
||||
* as 'hdr_record_corrected_value'.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @param count Number of 'value's to add to the histogram
|
||||
* @param expected_interval The delay between recording values.
|
||||
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval);
|
||||
|
||||
/**
|
||||
* Record a value in the histogram 'count' times. Applies the same correcting logic
|
||||
* as 'hdr_record_corrected_value'.
|
||||
*
|
||||
* Will record this value atomically, however the whole structure may appear inconsistent
|
||||
* when read concurrently with this update. Do NOT mix calls to this method with calls
|
||||
* to non-atomic updates.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value Value to add to the histogram
|
||||
* @param count Number of 'value's to add to the histogram
|
||||
* @param expected_interval The delay between recording values.
|
||||
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
|
||||
* true otherwise.
|
||||
*/
|
||||
bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval);
|
||||
|
||||
/**
|
||||
* Adds all of the values from 'from' to 'this' histogram. Will return the
|
||||
* number of values that are dropped when copying. Values will be dropped
|
||||
* if they around outside of h.lowest_trackable_value and
|
||||
* h.highest_trackable_value.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param from Histogram to copy values from.
|
||||
* @return The number of values dropped when copying.
|
||||
*/
|
||||
int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from);
|
||||
|
||||
/**
|
||||
* Adds all of the values from 'from' to 'this' histogram. Will return the
|
||||
* number of values that are dropped when copying. Values will be dropped
|
||||
* if they around outside of h.lowest_trackable_value and
|
||||
* h.highest_trackable_value.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param from Histogram to copy values from.
|
||||
* @return The number of values dropped when copying.
|
||||
*/
|
||||
int64_t hdr_add_while_correcting_for_coordinated_omission(
|
||||
struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval);
|
||||
|
||||
/**
|
||||
* Get minimum value from the histogram. Will return 2^63-1 if the histogram
|
||||
* is empty.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
*/
|
||||
int64_t hdr_min(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Get maximum value from the histogram. Will return 0 if the histogram
|
||||
* is empty.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
*/
|
||||
int64_t hdr_max(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Get the value at a specific percentile.
|
||||
*
|
||||
* @param h "This" pointer.
|
||||
* @param percentile The percentile to get the value for
|
||||
*/
|
||||
int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile);
|
||||
|
||||
/**
|
||||
* Gets the standard deviation for the values in the histogram.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @return The standard deviation
|
||||
*/
|
||||
double hdr_stddev(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Gets the mean for the values in the histogram.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @return The mean
|
||||
*/
|
||||
double hdr_mean(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Determine if two values are equivalent with the histogram's resolution.
|
||||
* Where "equivalent" means that value samples recorded for any two
|
||||
* equivalent values are counted in a common total count.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param a first value to compare
|
||||
* @param b second value to compare
|
||||
* @return 'true' if values are equivalent with the histogram's resolution.
|
||||
*/
|
||||
bool hdr_values_are_equivalent(const struct hdr_histogram* h, int64_t a, int64_t b);
|
||||
|
||||
/**
|
||||
* Get the lowest value that is equivalent to the given value within the histogram's resolution.
|
||||
* Where "equivalent" means that value samples recorded for any two
|
||||
* equivalent values are counted in a common total count.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value The given value
|
||||
* @return The lowest value that is equivalent to the given value within the histogram's resolution.
|
||||
*/
|
||||
int64_t hdr_lowest_equivalent_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
/**
|
||||
* Get the count of recorded values at a specific value
|
||||
* (to within the histogram resolution at the value level).
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value The value for which to provide the recorded count
|
||||
* @return The total count of values recorded in the histogram within the value range that is
|
||||
* {@literal >=} lowestEquivalentValue(<i>value</i>) and {@literal <=} highestEquivalentValue(<i>value</i>)
|
||||
*/
|
||||
int64_t hdr_count_at_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
int64_t hdr_count_at_index(const struct hdr_histogram* h, int32_t index);
|
||||
|
||||
int64_t hdr_value_at_index(const struct hdr_histogram* h, int32_t index);
|
||||
|
||||
struct hdr_iter_percentiles
|
||||
{
|
||||
bool seen_last_value;
|
||||
int32_t ticks_per_half_distance;
|
||||
double percentile_to_iterate_to;
|
||||
double percentile;
|
||||
};
|
||||
|
||||
struct hdr_iter_recorded
|
||||
{
|
||||
int64_t count_added_in_this_iteration_step;
|
||||
};
|
||||
|
||||
struct hdr_iter_linear
|
||||
{
|
||||
int64_t value_units_per_bucket;
|
||||
int64_t count_added_in_this_iteration_step;
|
||||
int64_t next_value_reporting_level;
|
||||
int64_t next_value_reporting_level_lowest_equivalent;
|
||||
};
|
||||
|
||||
struct hdr_iter_log
|
||||
{
|
||||
double log_base;
|
||||
int64_t count_added_in_this_iteration_step;
|
||||
int64_t next_value_reporting_level;
|
||||
int64_t next_value_reporting_level_lowest_equivalent;
|
||||
};
|
||||
|
||||
/**
|
||||
* The basic iterator. This is a generic structure
|
||||
* that supports all of the types of iteration. Use
|
||||
* the appropriate initialiser to get the desired
|
||||
* iteration.
|
||||
*
|
||||
* @
|
||||
*/
|
||||
struct hdr_iter
|
||||
{
|
||||
const struct hdr_histogram* h;
|
||||
/** raw index into the counts array */
|
||||
int32_t counts_index;
|
||||
/** snapshot of the length at the time the iterator is created */
|
||||
int64_t total_count;
|
||||
/** value directly from array for the current counts_index */
|
||||
int64_t count;
|
||||
/** sum of all of the counts up to and including the count at this index */
|
||||
int64_t cumulative_count;
|
||||
/** The current value based on counts_index */
|
||||
int64_t value;
|
||||
int64_t highest_equivalent_value;
|
||||
int64_t lowest_equivalent_value;
|
||||
int64_t median_equivalent_value;
|
||||
int64_t value_iterated_from;
|
||||
int64_t value_iterated_to;
|
||||
|
||||
union
|
||||
{
|
||||
struct hdr_iter_percentiles percentiles;
|
||||
struct hdr_iter_recorded recorded;
|
||||
struct hdr_iter_linear linear;
|
||||
struct hdr_iter_log log;
|
||||
} specifics;
|
||||
|
||||
bool (* _next_fp)(struct hdr_iter* iter);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Initalises the basic iterator.
|
||||
*
|
||||
* @param itr 'This' pointer
|
||||
* @param h The histogram to iterate over
|
||||
*/
|
||||
void hdr_iter_init(struct hdr_iter* iter, const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with percentiles.
|
||||
*/
|
||||
void hdr_iter_percentile_init(struct hdr_iter* iter, const struct hdr_histogram* h, int32_t ticks_per_half_distance);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with recorded values.
|
||||
*/
|
||||
void hdr_iter_recorded_init(struct hdr_iter* iter, const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with linear values.
|
||||
*/
|
||||
void hdr_iter_linear_init(
|
||||
struct hdr_iter* iter,
|
||||
const struct hdr_histogram* h,
|
||||
int64_t value_units_per_bucket);
|
||||
|
||||
/**
|
||||
* Update the iterator value units per bucket
|
||||
*/
|
||||
void hdr_iter_linear_set_value_units_per_bucket(struct hdr_iter* iter, int64_t value_units_per_bucket);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with logarithmic values
|
||||
*/
|
||||
void hdr_iter_log_init(
|
||||
struct hdr_iter* iter,
|
||||
const struct hdr_histogram* h,
|
||||
int64_t value_units_first_bucket,
|
||||
double log_base);
|
||||
|
||||
/**
|
||||
* Iterate to the next value for the iterator. If there are no more values
|
||||
* available return faluse.
|
||||
*
|
||||
* @param itr 'This' pointer
|
||||
* @return 'false' if there are no values remaining for this iterator.
|
||||
*/
|
||||
bool hdr_iter_next(struct hdr_iter* iter);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLASSIC,
|
||||
CSV
|
||||
} format_type;
|
||||
|
||||
/**
|
||||
* Print out a percentile based histogram to the supplied stream. Note that
|
||||
* this call will not flush the FILE, this is left up to the user.
|
||||
*
|
||||
* @param h 'This' pointer
|
||||
* @param stream The FILE to write the output to
|
||||
* @param ticks_per_half_distance The number of iteration steps per half-distance to 100%
|
||||
* @param value_scale Scale the output values by this amount
|
||||
* @param format_type Format to use, e.g. CSV.
|
||||
* @return 0 on success, error code on failure. EIO if an error occurs writing
|
||||
* the output.
|
||||
*/
|
||||
int hdr_percentiles_print(
|
||||
struct hdr_histogram* h, FILE* stream, int32_t ticks_per_half_distance,
|
||||
double value_scale, format_type format);
|
||||
|
||||
/**
|
||||
* Internal allocation methods, used by hdr_dbl_histogram.
|
||||
*/
|
||||
struct hdr_histogram_bucket_config
|
||||
{
|
||||
int64_t lowest_trackable_value;
|
||||
int64_t highest_trackable_value;
|
||||
int64_t unit_magnitude;
|
||||
int64_t significant_figures;
|
||||
int32_t sub_bucket_half_count_magnitude;
|
||||
int32_t sub_bucket_half_count;
|
||||
int64_t sub_bucket_mask;
|
||||
int32_t sub_bucket_count;
|
||||
int32_t bucket_count;
|
||||
int32_t counts_len;
|
||||
};
|
||||
|
||||
int hdr_calculate_bucket_config(
|
||||
int64_t lowest_trackable_value,
|
||||
int64_t highest_trackable_value,
|
||||
int significant_figures,
|
||||
struct hdr_histogram_bucket_config* cfg);
|
||||
|
||||
void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg);
|
||||
|
||||
int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
int64_t hdr_next_non_equivalent_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
int64_t hdr_median_equivalent_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
/**
|
||||
* Used to reset counters after importing data manuallying into the histogram, used by the logging code
|
||||
* and other custom serialisation tools.
|
||||
*/
|
||||
void hdr_reset_internal_counters(struct hdr_histogram* h);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -6,3 +6,4 @@
|
||||
/*.a
|
||||
/*.pc
|
||||
*.dSYM
|
||||
tags
|
||||
Vendored
+43
-9
@@ -1,5 +1,4 @@
|
||||
language: c
|
||||
sudo: false
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
@@ -8,17 +7,34 @@ os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
dist: bionic
|
||||
|
||||
branches:
|
||||
only:
|
||||
- staging
|
||||
- trying
|
||||
- master
|
||||
- /^release\/.*$/
|
||||
|
||||
install:
|
||||
- if [ "$BITS" == "64" ]; then
|
||||
wget https://github.com/redis/redis/archive/6.0.6.tar.gz;
|
||||
tar -xzvf 6.0.6.tar.gz;
|
||||
pushd redis-6.0.6 && BUILD_TLS=yes make && export PATH=$PWD/src:$PATH && popd;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.6.2-10.13-HighSierra.pkg;
|
||||
sudo installer -pkg MacPorts-2.6.2-10.13-HighSierra.pkg -target /;
|
||||
export PATH=$PATH:/opt/local/bin && sudo port -v selfupdate;
|
||||
sudo port -N install openssl redis;
|
||||
fi;
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:chris-lea/redis-server'
|
||||
packages:
|
||||
- libc6-dbg
|
||||
- libc6-dev
|
||||
@@ -27,14 +43,20 @@ addons:
|
||||
- libc6-dbg:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- libssl-dev
|
||||
- libssl-dev:i386
|
||||
- valgrind
|
||||
- redis
|
||||
|
||||
env:
|
||||
- BITS="32"
|
||||
- BITS="64"
|
||||
|
||||
script:
|
||||
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DHIREDIS_SSL:BOOL=ON";
|
||||
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON";
|
||||
if [ "$BITS" == "64" ]; then
|
||||
EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DENABLE_SSL_TESTS:BOOL=ON";
|
||||
fi;
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
if [ "$BITS" == "32" ]; then
|
||||
CFLAGS="-m32 -Werror";
|
||||
@@ -58,12 +80,24 @@ script:
|
||||
fi;
|
||||
fi;
|
||||
export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS
|
||||
- make && make clean;
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
if [ "$BITS" == "64" ]; then
|
||||
OPENSSL_PREFIX="$(ls -d /usr/local/Cellar/openssl@1.1/*)" USE_SSL=1 make;
|
||||
fi;
|
||||
else
|
||||
USE_SSL=1 make;
|
||||
fi;
|
||||
- mkdir build/ && cd build/
|
||||
- cmake .. ${EXTRA_CMAKE_OPTS}
|
||||
- make VERBOSE=1
|
||||
- ctest -V
|
||||
- if [ "$BITS" == "64" ]; then
|
||||
TEST_SSL=1 SKIPS_AS_FAILS=1 ctest -V;
|
||||
else
|
||||
SKIPS_AS_FAILS=1 ctest -V;
|
||||
fi;
|
||||
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
# Windows MinGW cross compile on Linux
|
||||
- os: linux
|
||||
@@ -89,9 +123,9 @@ matrix:
|
||||
- eval "${MATRIX_EVAL}"
|
||||
install:
|
||||
- choco install ninja
|
||||
- choco install -y memurai-developer
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
- cmd.exe /C '"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 &&
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release &&
|
||||
ninja -v'
|
||||
- ctest -V
|
||||
- cmd.exe //C 'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat' amd64 '&&'
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DENABLE_EXAMPLES=ON '&&' ninja -v
|
||||
- ./hiredis-test.exe
|
||||
Vendored
+164
-18
@@ -1,28 +1,175 @@
|
||||
### 1.0.0 (unreleased)
|
||||
## [1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) - (2020-08-03)
|
||||
|
||||
Announcing Hiredis v1.0.0, which adds support for RESP3, SSL connections, allocator injection, and better Windows support! :tada:
|
||||
|
||||
_A big thanks to everyone who helped with this release. The following list includes everyone who contributed at least five lines, sorted by lines contributed._ :sparkling_heart:
|
||||
|
||||
[Michael Grunder](https://github.com/michael-grunder), [Yossi Gottlieb](https://github.com/yossigo),
|
||||
[Mark Nunberg](https://github.com/mnunberg), [Marcus Geelnard](https://github.com/mbitsnbites),
|
||||
[Justin Brewer](https://github.com/justinbrewer), [Valentino Geron](https://github.com/valentinogeron),
|
||||
[Minun Dragonation](https://github.com/dragonation), [Omri Steiner](https://github.com/OmriSteiner),
|
||||
[Sangmoon Yi](https://github.com/jman-krafton), [Jinjiazh](https://github.com/jinjiazhang),
|
||||
[Odin Hultgren Van Der Horst](https://github.com/Miniwoffer), [Muhammad Zahalqa](https://github.com/tryfinally),
|
||||
[Nick Rivera](https://github.com/heronr), [Qi Yang](https://github.com/movebean),
|
||||
[kevin1018](https://github.com/kevin1018)
|
||||
|
||||
[Full Changelog](https://github.com/redis/hiredis/compare/v0.14.1...v1.0.0)
|
||||
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
|
||||
protocol errors. This is consistent with the RESP specification. On 32-bit
|
||||
platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
* `redisOptions` now has two timeout fields. One for connecting, and one for commands. If you're presently using `options->timeout` you will need to change it to use `options->connect_timeout`. (See [example](https://github.com/redis/hiredis/commit/38b5ae543f5c99eb4ccabbe277770fc6bc81226f#diff-86ba39d37aa829c8c82624cce4f049fbL36))
|
||||
|
||||
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
|
||||
User code should compare this to `size_t` values as well. If it was used to
|
||||
compare to other values, casting might be necessary or can be removed, if
|
||||
casting was applied before.
|
||||
|
||||
### 0.x.x (unreleased)
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
|
||||
User code should compare this to `size_t` values as well.
|
||||
If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
|
||||
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now protocol errors. This is consistent
|
||||
with the RESP specification. On 32-bit platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
|
||||
* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter.
|
||||
|
||||
**New features:**
|
||||
- Support for RESP3
|
||||
[\#697](https://github.com/redis/hiredis/pull/697),
|
||||
[\#805](https://github.com/redis/hiredis/pull/805),
|
||||
[\#819](https://github.com/redis/hiredis/pull/819),
|
||||
[\#841](https://github.com/redis/hiredis/pull/841)
|
||||
([Yossi Gottlieb](https://github.com/yossigo), [Michael Grunder](https://github.com/michael-grunder))
|
||||
- Support for SSL connections
|
||||
[\#645](https://github.com/redis/hiredis/pull/645),
|
||||
[\#699](https://github.com/redis/hiredis/pull/699),
|
||||
[\#702](https://github.com/redis/hiredis/pull/702),
|
||||
[\#708](https://github.com/redis/hiredis/pull/708),
|
||||
[\#711](https://github.com/redis/hiredis/pull/711),
|
||||
[\#821](https://github.com/redis/hiredis/pull/821),
|
||||
[more](https://github.com/redis/hiredis/pulls?q=is%3Apr+is%3Amerged+SSL)
|
||||
([Mark Nunberg](https://github.com/mnunberg), [Yossi Gottlieb](https://github.com/yossigo))
|
||||
- Run-time allocator injection
|
||||
[\#800](https://github.com/redis/hiredis/pull/800)
|
||||
([Michael Grunder](https://github.com/michael-grunder))
|
||||
- Improved Windows support (including MinGW and Windows CI)
|
||||
[\#652](https://github.com/redis/hiredis/pull/652),
|
||||
[\#663](https://github.com/redis/hiredis/pull/663)
|
||||
([Marcus Geelnard](https://www.bitsnbites.eu/author/m/))
|
||||
- Adds support for distinct connect and command timeouts
|
||||
[\#839](https://github.com/redis/hiredis/pull/839),
|
||||
[\#829](https://github.com/redis/hiredis/pull/829)
|
||||
([Valentino Geron](https://github.com/valentinogeron))
|
||||
- Add generic pointer and destructor to `redisContext` that users can use for context.
|
||||
[\#855](https://github.com/redis/hiredis/pull/855)
|
||||
([Michael Grunder](https://github.com/michael-grunder))
|
||||
|
||||
**Closed issues (that involved code changes):**
|
||||
|
||||
- Makefile does not install TLS libraries [\#809](https://github.com/redis/hiredis/issues/809)
|
||||
- redisConnectWithOptions should not set command timeout [\#722](https://github.com/redis/hiredis/issues/722), [\#829](https://github.com/redis/hiredis/pull/829) ([valentinogeron](https://github.com/valentinogeron))
|
||||
- Fix integer overflow in `sdsrange` [\#827](https://github.com/redis/hiredis/issues/827)
|
||||
- INFO & CLUSTER commands failed when using RESP3 [\#802](https://github.com/redis/hiredis/issues/802)
|
||||
- Windows compatibility patches [\#687](https://github.com/redis/hiredis/issues/687), [\#838](https://github.com/redis/hiredis/issues/838), [\#842](https://github.com/redis/hiredis/issues/842)
|
||||
- RESP3 PUSH messages incorrectly use pending callback [\#825](https://github.com/redis/hiredis/issues/825)
|
||||
- Asynchronous PSUBSCRIBE command fails when using RESP3 [\#815](https://github.com/redis/hiredis/issues/815)
|
||||
- New SSL API [\#804](https://github.com/redis/hiredis/issues/804), [\#813](https://github.com/redis/hiredis/issues/813)
|
||||
- Hard-coded limit of nested reply depth [\#794](https://github.com/redis/hiredis/issues/794)
|
||||
- Fix TCP_NODELAY in Windows/OSX [\#679](https://github.com/redis/hiredis/issues/679), [\#690](https://github.com/redis/hiredis/issues/690), [\#779](https://github.com/redis/hiredis/issues/779), [\#785](https://github.com/redis/hiredis/issues/785),
|
||||
- Added timers to libev adapter. [\#778](https://github.com/redis/hiredis/issues/778), [\#795](https://github.com/redis/hiredis/pull/795)
|
||||
- Initialization discards const qualifier [\#777](https://github.com/redis/hiredis/issues/777)
|
||||
- \[BUG\]\[MinGW64\] Error setting socket timeout [\#775](https://github.com/redis/hiredis/issues/775)
|
||||
- undefined reference to hi_malloc [\#769](https://github.com/redis/hiredis/issues/769)
|
||||
- hiredis pkg-config file incorrectly ignores multiarch libdir spec'n [\#767](https://github.com/redis/hiredis/issues/767)
|
||||
- Don't use -G to build shared object on Solaris [\#757](https://github.com/redis/hiredis/issues/757)
|
||||
- error when make USE\_SSL=1 [\#748](https://github.com/redis/hiredis/issues/748)
|
||||
- Allow to change SSL Mode [\#646](https://github.com/redis/hiredis/issues/646)
|
||||
- hiredis/adapters/libevent.h memleak [\#618](https://github.com/redis/hiredis/issues/618)
|
||||
- redisLibuvPoll crash when server closes the connetion [\#545](https://github.com/redis/hiredis/issues/545)
|
||||
- about redisAsyncDisconnect question [\#518](https://github.com/redis/hiredis/issues/518)
|
||||
- hiredis adapters libuv error for help [\#508](https://github.com/redis/hiredis/issues/508)
|
||||
- API/ABI changes analysis [\#506](https://github.com/redis/hiredis/issues/506)
|
||||
- Memory leak patch in Redis [\#502](https://github.com/redis/hiredis/issues/502)
|
||||
- Remove the depth limitation [\#421](https://github.com/redis/hiredis/issues/421)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Move SSL management to a distinct private pointer [\#855](https://github.com/redis/hiredis/pull/855) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Move include to sockcompat.h to maintain style [\#850](https://github.com/redis/hiredis/pull/850) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Remove erroneous tag and add license to push example [\#849](https://github.com/redis/hiredis/pull/849) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- fix windows compiling with mingw [\#848](https://github.com/redis/hiredis/pull/848) ([rmalizia44](https://github.com/rmalizia44))
|
||||
- Some Windows quality of life improvements. [\#846](https://github.com/redis/hiredis/pull/846) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use \_WIN32 define instead of WIN32 [\#845](https://github.com/redis/hiredis/pull/845) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Non Linux CI fixes [\#844](https://github.com/redis/hiredis/pull/844) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Resp3 oob push support [\#841](https://github.com/redis/hiredis/pull/841) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- fix \#785: defer TCP\_NODELAY in async tcp connections [\#836](https://github.com/redis/hiredis/pull/836) ([OmriSteiner](https://github.com/OmriSteiner))
|
||||
- sdsrange overflow fix [\#830](https://github.com/redis/hiredis/pull/830) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use explicit pointer casting for c++ compatibility [\#826](https://github.com/redis/hiredis/pull/826) ([aureus1](https://github.com/aureus1))
|
||||
- Document allocator injection and completeness fix in test.c [\#824](https://github.com/redis/hiredis/pull/824) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use unique names for allocator struct members [\#823](https://github.com/redis/hiredis/pull/823) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- New SSL API to replace redisSecureConnection\(\). [\#821](https://github.com/redis/hiredis/pull/821) ([yossigo](https://github.com/yossigo))
|
||||
- Add logic to handle RESP3 push messages [\#819](https://github.com/redis/hiredis/pull/819) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use standrad isxdigit instead of custom helper function. [\#814](https://github.com/redis/hiredis/pull/814) ([tryfinally](https://github.com/tryfinally))
|
||||
- Fix missing SSL build/install options. [\#812](https://github.com/redis/hiredis/pull/812) ([yossigo](https://github.com/yossigo))
|
||||
- Add link to ABI tracker [\#808](https://github.com/redis/hiredis/pull/808) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Resp3 verbatim string support [\#805](https://github.com/redis/hiredis/pull/805) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Allow users to replace allocator and handle OOM everywhere. [\#800](https://github.com/redis/hiredis/pull/800) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Remove nested depth limitation. [\#797](https://github.com/redis/hiredis/pull/797) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Attempt to fix compilation on Solaris [\#796](https://github.com/redis/hiredis/pull/796) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Support timeouts in libev adapater [\#795](https://github.com/redis/hiredis/pull/795) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Fix pkgconfig when installing to a custom lib dir [\#793](https://github.com/redis/hiredis/pull/793) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Fix USE\_SSL=1 make/cmake on OSX and CMake tests [\#789](https://github.com/redis/hiredis/pull/789) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use correct libuv call on Windows [\#784](https://github.com/redis/hiredis/pull/784) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Added CMake package config and fixed hiredis\_ssl on Windows [\#783](https://github.com/redis/hiredis/pull/783) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- CMake: Set hiredis\_ssl shared object version. [\#780](https://github.com/redis/hiredis/pull/780) ([yossigo](https://github.com/yossigo))
|
||||
- Win32 tests and timeout fix [\#776](https://github.com/redis/hiredis/pull/776) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Provides an optional cleanup callback for async data. [\#768](https://github.com/redis/hiredis/pull/768) ([heronr](https://github.com/heronr))
|
||||
- Housekeeping fixes [\#764](https://github.com/redis/hiredis/pull/764) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- install alloc.h [\#756](https://github.com/redis/hiredis/pull/756) ([ch1aki](https://github.com/ch1aki))
|
||||
- fix spelling mistakes [\#746](https://github.com/redis/hiredis/pull/746) ([ShooterIT](https://github.com/ShooterIT))
|
||||
- Free the reply in redisGetReply when passed NULL [\#741](https://github.com/redis/hiredis/pull/741) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Fix dead code in sslLogCallback relating to should\_log variable. [\#737](https://github.com/redis/hiredis/pull/737) ([natoscott](https://github.com/natoscott))
|
||||
- Fix typo in dict.c. [\#731](https://github.com/redis/hiredis/pull/731) ([Kevin-Xi](https://github.com/Kevin-Xi))
|
||||
- Adding an option to DISABLE\_TESTS [\#727](https://github.com/redis/hiredis/pull/727) ([pbotros](https://github.com/pbotros))
|
||||
- Update README with SSL support. [\#720](https://github.com/redis/hiredis/pull/720) ([yossigo](https://github.com/yossigo))
|
||||
- Fixes leaks in unit tests [\#715](https://github.com/redis/hiredis/pull/715) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- SSL Tests [\#711](https://github.com/redis/hiredis/pull/711) ([yossigo](https://github.com/yossigo))
|
||||
- SSL Reorganization [\#708](https://github.com/redis/hiredis/pull/708) ([yossigo](https://github.com/yossigo))
|
||||
- Fix MSVC build. [\#706](https://github.com/redis/hiredis/pull/706) ([yossigo](https://github.com/yossigo))
|
||||
- SSL: Properly report SSL\_connect\(\) errors. [\#702](https://github.com/redis/hiredis/pull/702) ([yossigo](https://github.com/yossigo))
|
||||
- Silent SSL trace to stdout by default. [\#699](https://github.com/redis/hiredis/pull/699) ([yossigo](https://github.com/yossigo))
|
||||
- Port RESP3 support from Redis. [\#697](https://github.com/redis/hiredis/pull/697) ([yossigo](https://github.com/yossigo))
|
||||
- Removed whitespace before newline [\#691](https://github.com/redis/hiredis/pull/691) ([Miniwoffer](https://github.com/Miniwoffer))
|
||||
- Add install adapters header files [\#688](https://github.com/redis/hiredis/pull/688) ([kevin1018](https://github.com/kevin1018))
|
||||
- Remove unnecessary null check before free [\#684](https://github.com/redis/hiredis/pull/684) ([qlyoung](https://github.com/qlyoung))
|
||||
- redisReaderGetReply leak memory [\#671](https://github.com/redis/hiredis/pull/671) ([movebean](https://github.com/movebean))
|
||||
- fix timeout code in windows [\#670](https://github.com/redis/hiredis/pull/670) ([jman-krafton](https://github.com/jman-krafton))
|
||||
- test: fix errstr matching for musl libc [\#665](https://github.com/redis/hiredis/pull/665) ([ghost](https://github.com/ghost))
|
||||
- Windows: MinGW fixes and Windows Travis builders [\#663](https://github.com/redis/hiredis/pull/663) ([mbitsnbites](https://github.com/mbitsnbites))
|
||||
- The setsockopt and getsockopt API diffs from BSD socket and WSA one [\#662](https://github.com/redis/hiredis/pull/662) ([dragonation](https://github.com/dragonation))
|
||||
- Fix Compile Error On Windows \(Visual Studio\) [\#658](https://github.com/redis/hiredis/pull/658) ([jinjiazhang](https://github.com/jinjiazhang))
|
||||
- Fix NXDOMAIN test case [\#653](https://github.com/redis/hiredis/pull/653) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Add MinGW support [\#652](https://github.com/redis/hiredis/pull/652) ([mbitsnbites](https://github.com/mbitsnbites))
|
||||
- SSL Support [\#645](https://github.com/redis/hiredis/pull/645) ([mnunberg](https://github.com/mnunberg))
|
||||
- Fix Invalid argument after redisAsyncConnectUnix [\#644](https://github.com/redis/hiredis/pull/644) ([codehz](https://github.com/codehz))
|
||||
- Makefile: use predefined AR [\#632](https://github.com/redis/hiredis/pull/632) ([Mic92](https://github.com/Mic92))
|
||||
- FreeBSD build fix [\#628](https://github.com/redis/hiredis/pull/628) ([devnexen](https://github.com/devnexen))
|
||||
- Fix errors not propagating properly with libuv.h. [\#624](https://github.com/redis/hiredis/pull/624) ([yossigo](https://github.com/yossigo))
|
||||
- Update README.md [\#621](https://github.com/redis/hiredis/pull/621) ([Crunsher](https://github.com/Crunsher))
|
||||
- Fix redisBufferRead documentation [\#620](https://github.com/redis/hiredis/pull/620) ([hacst](https://github.com/hacst))
|
||||
- Add CPPFLAGS to REAL\_CFLAGS [\#614](https://github.com/redis/hiredis/pull/614) ([thomaslee](https://github.com/thomaslee))
|
||||
- Update createArray to take size\_t [\#597](https://github.com/redis/hiredis/pull/597) ([justinbrewer](https://github.com/justinbrewer))
|
||||
- fix common realloc mistake and add null check more [\#580](https://github.com/redis/hiredis/pull/580) ([charsyam](https://github.com/charsyam))
|
||||
- Proper error reporting for connect failures [\#578](https://github.com/redis/hiredis/pull/578) ([mnunberg](https://github.com/mnunberg))
|
||||
|
||||
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
||||
|
||||
## [1.0.0-rc1](https://github.com/redis/hiredis/tree/v1.0.0-rc1) - (2020-07-29)
|
||||
|
||||
_Note: There were no changes to code between v1.0.0-rc1 and v1.0.0 so see v1.0.0 for changelog_
|
||||
|
||||
### 0.14.1 (2020-03-13)
|
||||
|
||||
* Adds safe allocation wrappers (CVE-2020-7105, #747, #752) (Michael Grunder)
|
||||
|
||||
### 0.14.0 (2018-09-25)
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
|
||||
User code should compare this to `size_t` values as well.
|
||||
If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
|
||||
|
||||
* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b])
|
||||
* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537])
|
||||
@@ -196,4 +343,3 @@ The parser, standalone since v0.12.0, can now be compiled on Windows
|
||||
### 0.10.0
|
||||
|
||||
* See commit log.
|
||||
|
||||
Vendored
+84
-9
@@ -3,6 +3,8 @@ INCLUDE(GNUInstallDirs)
|
||||
PROJECT(hiredis)
|
||||
|
||||
OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
|
||||
OPTION(DISABLE_TESTS "If tests should be compiled or not" OFF)
|
||||
OPTION(ENABLE_SSL_TESTS, "Should we test SSL connections" OFF)
|
||||
|
||||
MACRO(getVersionBit name)
|
||||
SET(VERSION_REGEX "^#define ${name} (.+)$")
|
||||
@@ -22,7 +24,8 @@ PROJECT(hiredis VERSION "${VERSION}")
|
||||
|
||||
SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
|
||||
|
||||
ADD_LIBRARY(hiredis SHARED
|
||||
SET(hiredis_sources
|
||||
alloc.c
|
||||
async.c
|
||||
dict.c
|
||||
hiredis.c
|
||||
@@ -31,20 +34,32 @@ ADD_LIBRARY(hiredis SHARED
|
||||
sds.c
|
||||
sockcompat.c)
|
||||
|
||||
SET(hiredis_sources ${hiredis_sources})
|
||||
|
||||
IF(WIN32)
|
||||
ADD_COMPILE_DEFINITIONS(_CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN)
|
||||
ENDIF()
|
||||
|
||||
ADD_LIBRARY(hiredis SHARED ${hiredis_sources})
|
||||
|
||||
SET_TARGET_PROPERTIES(hiredis
|
||||
PROPERTIES
|
||||
PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE
|
||||
VERSION "${HIREDIS_SONAME}")
|
||||
IF(WIN32 OR MINGW)
|
||||
TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32)
|
||||
ENDIF()
|
||||
TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC .)
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $<INSTALL_INTERFACE:.> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
|
||||
CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
|
||||
|
||||
INSTALL(TARGETS hiredis
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
EXPORT hiredis-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
INSTALL(FILES hiredis.h read.h sds.h async.h
|
||||
INSTALL(FILES hiredis.h read.h sds.h async.h alloc.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(DIRECTORY adapters
|
||||
@@ -53,6 +68,26 @@ INSTALL(DIRECTORY adapters
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
export(EXPORT hiredis-targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis-targets.cmake"
|
||||
NAMESPACE hiredis::)
|
||||
|
||||
SET(CMAKE_CONF_INSTALL_DIR share/hiredis)
|
||||
SET(INCLUDE_INSTALL_DIR include)
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(hiredis-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
|
||||
PATH_VARS INCLUDE_INSTALL_DIR)
|
||||
|
||||
INSTALL(EXPORT hiredis-targets
|
||||
FILE hiredis-targets.cmake
|
||||
NAMESPACE hiredis::
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
|
||||
|
||||
IF(ENABLE_SSL)
|
||||
IF (NOT OPENSSL_ROOT_DIR)
|
||||
IF (APPLE)
|
||||
@@ -60,26 +95,66 @@ IF(ENABLE_SSL)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
FIND_PACKAGE(OpenSSL REQUIRED)
|
||||
ADD_LIBRARY(hiredis_ssl SHARED
|
||||
SET(hiredis_ssl_sources
|
||||
ssl.c)
|
||||
ADD_LIBRARY(hiredis_ssl SHARED
|
||||
${hiredis_ssl_sources})
|
||||
|
||||
IF (APPLE)
|
||||
SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup")
|
||||
ENDIF()
|
||||
|
||||
SET_TARGET_PROPERTIES(hiredis_ssl
|
||||
PROPERTIES
|
||||
WINDOWS_EXPORT_ALL_SYMBOLS TRUE
|
||||
VERSION "${HIREDIS_SONAME}")
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
|
||||
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
|
||||
IF (WIN32 OR MINGW)
|
||||
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis)
|
||||
ENDIF()
|
||||
CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)
|
||||
|
||||
INSTALL(TARGETS hiredis_ssl
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
EXPORT hiredis_ssl-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
INSTALL(FILES hiredis_ssl.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
export(EXPORT hiredis_ssl-targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-targets.cmake"
|
||||
NAMESPACE hiredis::)
|
||||
|
||||
SET(CMAKE_CONF_INSTALL_DIR share/hiredis_ssl)
|
||||
configure_package_config_file(hiredis_ssl-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
|
||||
PATH_VARS INCLUDE_INSTALL_DIR)
|
||||
|
||||
INSTALL(EXPORT hiredis_ssl-targets
|
||||
FILE hiredis_ssl-targets.cmake
|
||||
NAMESPACE hiredis::
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
ENDIF()
|
||||
|
||||
IF(NOT (WIN32 OR MINGW))
|
||||
IF(NOT DISABLE_TESTS)
|
||||
ENABLE_TESTING()
|
||||
ADD_EXECUTABLE(hiredis-test test.c)
|
||||
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
|
||||
IF(ENABLE_SSL_TESTS)
|
||||
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1)
|
||||
TARGET_LINK_LIBRARIES(hiredis-test hiredis hiredis_ssl)
|
||||
ELSE()
|
||||
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
|
||||
ENDIF()
|
||||
ADD_TEST(NAME hiredis-test
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
|
||||
ENDIF()
|
||||
|
||||
Vendored
+59
-19
@@ -3,16 +3,16 @@
|
||||
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
# This file is released under the BSD license, see the COPYING file
|
||||
|
||||
OBJ=net.o hiredis.o sds.o async.o read.o sockcompat.o
|
||||
OBJ=alloc.o net.o hiredis.o sds.o async.o read.o sockcompat.o
|
||||
SSL_OBJ=ssl.o
|
||||
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib
|
||||
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-push
|
||||
ifeq ($(USE_SSL),1)
|
||||
EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl
|
||||
endif
|
||||
TESTS=hiredis-test
|
||||
LIBNAME=libhiredis
|
||||
SSL_LIBNAME=libhiredis_ssl
|
||||
PKGCONFNAME=hiredis.pc
|
||||
SSL_LIBNAME=libhiredis_ssl
|
||||
SSL_PKGCONFNAME=hiredis_ssl.pc
|
||||
|
||||
HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}')
|
||||
@@ -55,12 +55,17 @@ STLIBSUFFIX=a
|
||||
DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
|
||||
DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
|
||||
DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
|
||||
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
|
||||
|
||||
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME)
|
||||
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
|
||||
SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX)
|
||||
STLIB_MAKE_CMD=$(AR) rcs
|
||||
|
||||
SSL_DYLIB_MINOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
|
||||
SSL_DYLIB_MAJOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
|
||||
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
|
||||
SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX)
|
||||
SSL_DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(SSL_DYLIB_MINOR_NAME)
|
||||
|
||||
# Platform-specific overrides
|
||||
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
|
||||
@@ -72,7 +77,12 @@ ifeq ($(USE_SSL),1)
|
||||
endif
|
||||
|
||||
ifeq ($(uname_S),Linux)
|
||||
SSL_LDFLAGS=-lssl -lcrypto
|
||||
ifdef OPENSSL_PREFIX
|
||||
CFLAGS+=-I$(OPENSSL_PREFIX)/include
|
||||
SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
|
||||
else
|
||||
SSL_LDFLAGS=-lssl -lcrypto
|
||||
endif
|
||||
else
|
||||
OPENSSL_PREFIX?=/usr/local/opt/openssl
|
||||
CFLAGS+=-I$(OPENSSL_PREFIX)/include
|
||||
@@ -80,13 +90,22 @@ else
|
||||
endif
|
||||
|
||||
ifeq ($(uname_S),SunOS)
|
||||
IS_SUN_CC=$(shell sh -c '$(CC) -V 2>&1 |egrep -i -c "sun|studio"')
|
||||
ifeq ($(IS_SUN_CC),1)
|
||||
SUN_SHARED_FLAG=-G
|
||||
else
|
||||
SUN_SHARED_FLAG=-shared
|
||||
endif
|
||||
REAL_LDFLAGS+= -ldl -lnsl -lsocket
|
||||
DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
|
||||
DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
|
||||
SSL_DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(SSL_DYLIBNAME) -h $(SSL_DYLIB_MINOR_NAME) $(LDFLAGS) $(SSL_LDFLAGS)
|
||||
endif
|
||||
ifeq ($(uname_S),Darwin)
|
||||
DYLIBSUFFIX=dylib
|
||||
DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX)
|
||||
DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
|
||||
SSL_DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME) -o $(SSL_DYLIBNAME) $(LDFLAGS) $(SSL_LDFLAGS)
|
||||
DYLIB_PLUGIN=-Wl,-undefined -Wl,dynamic_lookup
|
||||
endif
|
||||
|
||||
all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME)
|
||||
@@ -95,15 +114,16 @@ all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
|
||||
endif
|
||||
|
||||
# Deps (use make dep to generate this)
|
||||
async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h
|
||||
dict.o: dict.c fmacros.h dict.h
|
||||
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h win32.h
|
||||
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h sockcompat.h win32.h
|
||||
read.o: read.c fmacros.h read.h sds.h
|
||||
sds.o: sds.c sds.h
|
||||
alloc.o: alloc.c fmacros.h alloc.h
|
||||
async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.h
|
||||
dict.o: dict.c fmacros.h alloc.h dict.h
|
||||
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h
|
||||
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h
|
||||
read.o: read.c fmacros.h alloc.h read.h sds.h win32.h
|
||||
sds.o: sds.c sds.h sdsalloc.h alloc.h
|
||||
sockcompat.o: sockcompat.c sockcompat.h
|
||||
ssl.o: ssl.c hiredis.h
|
||||
test.o: test.c fmacros.h hiredis.h read.h sds.h
|
||||
ssl.o: ssl.c hiredis.h read.h sds.h alloc.h async.h win32.h async_private.h
|
||||
test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h sockcompat.h win32.h
|
||||
|
||||
$(DYLIBNAME): $(OBJ)
|
||||
$(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS)
|
||||
@@ -112,7 +132,7 @@ $(STLIBNAME): $(OBJ)
|
||||
$(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ)
|
||||
|
||||
$(SSL_DYLIBNAME): $(SSL_OBJ)
|
||||
$(DYLIB_MAKE_CMD) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
|
||||
$(SSL_DYLIB_MAKE_CMD) $(DYLIB_PLUGIN) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
$(SSL_STLIBNAME): $(SSL_OBJ)
|
||||
$(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ)
|
||||
@@ -146,6 +166,7 @@ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
|
||||
hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
|
||||
ifndef AE_DIR
|
||||
hiredis-example-ae:
|
||||
@echo "Please specify AE_DIR (e.g. <redis repository>/src)"
|
||||
@@ -180,13 +201,19 @@ endif
|
||||
hiredis-example: examples/example.c $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-push: examples/example-push.c $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
examples: $(EXAMPLES)
|
||||
|
||||
TEST_LIBS = $(STLIBNAME)
|
||||
ifeq ($(USE_SSL),1)
|
||||
TEST_LIBS += $(SSL_STLIBNAME) -lssl -lcrypto -lpthread
|
||||
TEST_LIBS += $(SSL_STLIBNAME)
|
||||
TEST_LDFLAGS = $(SSL_LDFLAGS) -lssl -lcrypto -lpthread
|
||||
endif
|
||||
|
||||
hiredis-test: test.o $(TEST_LIBS)
|
||||
$(CC) -o $@ $(REAL_CFLAGS) -I. $^ $(REAL_LDFLAGS) $(TEST_LDFLAGS)
|
||||
|
||||
hiredis-%: %.o $(STLIBNAME)
|
||||
$(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS)
|
||||
@@ -221,7 +248,7 @@ $(PKGCONFNAME): hiredis.h
|
||||
@echo Libs: -L\$${libdir} -lhiredis >> $@
|
||||
@echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@
|
||||
|
||||
$(SSL_PKGCONFNAME): hiredis.h
|
||||
$(SSL_PKGCONFNAME): hiredis_ssl.h
|
||||
@echo "Generating $@ for pkgconfig..."
|
||||
@echo prefix=$(PREFIX) > $@
|
||||
@echo exec_prefix=\$${prefix} >> $@
|
||||
@@ -237,7 +264,7 @@ $(SSL_PKGCONFNAME): hiredis.h
|
||||
|
||||
install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
|
||||
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH)
|
||||
$(INSTALL) hiredis.h async.h read.h sds.h $(INSTALL_INCLUDE_PATH)
|
||||
$(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH)
|
||||
$(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters
|
||||
$(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME)
|
||||
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME)
|
||||
@@ -245,6 +272,19 @@ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
|
||||
mkdir -p $(INSTALL_PKGCONF_PATH)
|
||||
$(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
|
||||
|
||||
ifeq ($(USE_SSL),1)
|
||||
install: install-ssl
|
||||
|
||||
install-ssl: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
|
||||
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
|
||||
$(INSTALL) hiredis_ssl.h $(INSTALL_INCLUDE_PATH)
|
||||
$(INSTALL) $(SSL_DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME)
|
||||
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIBNAME)
|
||||
$(INSTALL) $(SSL_STLIBNAME) $(INSTALL_LIBRARY_PATH)
|
||||
mkdir -p $(INSTALL_PKGCONF_PATH)
|
||||
$(INSTALL) $(SSL_PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
|
||||
endif
|
||||
|
||||
32bit:
|
||||
@echo ""
|
||||
@echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386"
|
||||
|
||||
Vendored
+259
-13
@@ -1,6 +1,6 @@
|
||||
[](https://travis-ci.org/redis/hiredis)
|
||||
|
||||
**This Readme reflects the latest changed in the master branch. See [v0.13.3](https://github.com/redis/hiredis/tree/v0.13.3) for the Readme and documentation for the latest release.**
|
||||
**This Readme reflects the latest changed in the master branch. See [v1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline&l=hiredis)).**
|
||||
|
||||
# HIREDIS
|
||||
|
||||
@@ -24,12 +24,31 @@ The library comes with multiple APIs. There is the
|
||||
|
||||
## Upgrading to `1.0.0`
|
||||
|
||||
Version 1.0.0 marks a stable release of hiredis.
|
||||
Version 1.0.0 marks the first stable release of Hiredis.
|
||||
It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory.
|
||||
It also bundles the updated `sds` library, to sync up with upstream and Redis.
|
||||
For most applications a recompile against the new hiredis should be enough.
|
||||
For code changes see the [Changelog](CHANGELOG.md).
|
||||
|
||||
_Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling._
|
||||
|
||||
## IMPORTANT: Breaking changes from `0.14.1` -> `1.0.0`
|
||||
|
||||
* `redisContext` has two additional members (`free_privdata`, and `privctx`).
|
||||
* `redisOptions.timeout` has been renamed to `redisOptions.connect_timeout`, and we've added `redisOptions.command_timeout`.
|
||||
* `redisReplyObjectFunctions.createArray` now takes `size_t` instead of `int` for its length parameter.
|
||||
|
||||
## IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x
|
||||
|
||||
Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
|
||||
protocol errors. This is consistent with the RESP specification. On 32-bit
|
||||
platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
|
||||
Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
|
||||
User code should compare this to `size_t` values as well. If it was used to
|
||||
compare to other values, casting might be necessary or can be removed, if
|
||||
casting was applied before.
|
||||
|
||||
## Upgrading from `<0.9.0`
|
||||
|
||||
Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
|
||||
@@ -110,6 +129,8 @@ The standard replies that `redisCommand` are of the type `redisReply`. The
|
||||
`type` field in the `redisReply` should be used to test what kind of reply
|
||||
was received:
|
||||
|
||||
### RESP2
|
||||
|
||||
* **`REDIS_REPLY_STATUS`**:
|
||||
* The command replied with a status reply. The status string can be accessed using `reply->str`.
|
||||
The length of this string can be accessed using `reply->len`.
|
||||
@@ -134,16 +155,51 @@ was received:
|
||||
and can be accessed via `reply->element[..index..]`.
|
||||
Redis may reply with nested arrays but this is fully supported.
|
||||
|
||||
### RESP3
|
||||
|
||||
Hiredis also supports every new `RESP3` data type which are as follows. For more information about the protocol see the `RESP3` [specification.](https://github.com/antirez/RESP3/blob/master/spec.md)
|
||||
|
||||
* **`REDIS_REPLY_DOUBLE`**:
|
||||
* The command replied with a double-precision floating point number.
|
||||
The value is stored as a string in the `str` member, and can be converted with `strtod` or similar.
|
||||
|
||||
* **`REDIS_REPLY_BOOL`**:
|
||||
* A boolean true/false reply.
|
||||
The value is stored in the `integer` member and will be either `0` or `1`.
|
||||
|
||||
* **`REDIS_REPLY_MAP`**:
|
||||
* An array with the added invariant that there will always be an even number of elements.
|
||||
The MAP is functionally equivelant to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant.
|
||||
|
||||
* **`REDIS_REPLY_SET`**:
|
||||
* An array response where each entry is unique.
|
||||
Like the MAP type, the data is identical to an array response except there are no duplicate values.
|
||||
|
||||
* **`REDIS_REPLY_PUSH`**:
|
||||
* An array that can be generated spontaneously by Redis.
|
||||
This array response will always contain at least two subelements. The first contains the type of `PUSH` message (e.g. `message`, or `invalidate`), and the second being a sub-array with the `PUSH` payload itself.
|
||||
|
||||
* **`REDIS_REPLY_ATTR`**:
|
||||
* An array structurally identical to a `MAP` but intended as meta-data about a reply.
|
||||
_As of Redis 6.0.6 this reply type is not used in Redis_
|
||||
|
||||
* **`REDIS_REPLY_BIGNUM`**:
|
||||
* A string representing an arbitrarily large signed or unsigned integer value.
|
||||
The number will be encoded as a string in the `str` member of `redisReply`.
|
||||
|
||||
* **`REDIS_REPLY_VERB`**:
|
||||
* A verbatim string, intended to be presented to the user without modification.
|
||||
The string payload is stored in the `str` memeber, and type data is stored in the `vtype` member (e.g. `txt` for raw text or `md` for markdown).
|
||||
|
||||
Replies should be freed using the `freeReplyObject()` function.
|
||||
Note that this function will take care of freeing sub-reply objects
|
||||
contained in arrays and nested arrays, so there is no need for the user to
|
||||
free the sub replies (it is actually harmful and will corrupt the memory).
|
||||
|
||||
**Important:** the current version of hiredis (0.10.0) frees replies when the
|
||||
**Important:** the current version of hiredis (1.0.0) frees replies when the
|
||||
asynchronous API is used. This means you should not call `freeReplyObject` when
|
||||
you use this API. The reply is cleaned up by hiredis _after_ the callback
|
||||
returns. This behavior will probably change in future releases, so make sure to
|
||||
keep an eye on the changelog when upgrading (see issue #39).
|
||||
returns. We may introduce a flag to make this configurable in future versions of the library.
|
||||
|
||||
### Cleaning up
|
||||
|
||||
@@ -205,16 +261,16 @@ a single call to `read(2)`):
|
||||
redisReply *reply;
|
||||
redisAppendCommand(context,"SET foo bar");
|
||||
redisAppendCommand(context,"GET foo");
|
||||
redisGetReply(context,&reply); // reply for SET
|
||||
redisGetReply(context,(void *)&reply); // reply for SET
|
||||
freeReplyObject(reply);
|
||||
redisGetReply(context,&reply); // reply for GET
|
||||
redisGetReply(context,(void *)&reply); // reply for GET
|
||||
freeReplyObject(reply);
|
||||
```
|
||||
This API can also be used to implement a blocking subscriber:
|
||||
```c
|
||||
reply = redisCommand(context,"SUBSCRIBE foo");
|
||||
freeReplyObject(reply);
|
||||
while(redisGetReply(context,&reply) == REDIS_OK) {
|
||||
while(redisGetReply(context,(void *)&reply) == REDIS_OK) {
|
||||
// consume message
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
@@ -404,9 +460,199 @@ This should be done only in order to maximize performances when working with
|
||||
large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
|
||||
as soon as possible in order to prevent allocation of useless memory.
|
||||
|
||||
### Reader max array elements
|
||||
|
||||
By default the hiredis reply parser sets the maximum number of multi-bulk elements
|
||||
to 2^32 - 1 or 4,294,967,295 entries. If you need to process multi-bulk replies
|
||||
with more than this many elements you can set the value higher or to zero, meaning
|
||||
unlimited with:
|
||||
```c
|
||||
context->reader->maxelements = 0;
|
||||
```
|
||||
|
||||
## SSL/TLS Support
|
||||
|
||||
### Building
|
||||
|
||||
SSL/TLS support is not built by default and requires an explicit flag:
|
||||
|
||||
make USE_SSL=1
|
||||
|
||||
This requires OpenSSL development package (e.g. including header files to be
|
||||
available.
|
||||
|
||||
When enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and
|
||||
`libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries
|
||||
unaffected so no additional dependencies are introduced.
|
||||
|
||||
### Using it
|
||||
|
||||
First, you'll need to make sure you include the SSL header file:
|
||||
|
||||
```c
|
||||
#include "hiredis.h"
|
||||
#include "hiredis_ssl.h"
|
||||
```
|
||||
|
||||
You will also need to link against `libhiredis_ssl`, **in addition** to
|
||||
`libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies.
|
||||
|
||||
Hiredis implements SSL/TLS on top of its normal `redisContext` or
|
||||
`redisAsyncContext`, so you will need to establish a connection first and then
|
||||
initiate an SSL/TLS handshake.
|
||||
|
||||
#### Hiredis OpenSSL Wrappers
|
||||
|
||||
Before Hiredis can negotiate an SSL/TLS connection, it is necessary to
|
||||
initialize OpenSSL and create a context. You can do that in two ways:
|
||||
|
||||
1. Work directly with the OpenSSL API to initialize the library's global context
|
||||
and create `SSL_CTX *` and `SSL *` contexts. With an `SSL *` object you can
|
||||
call `redisInitiateSSL()`.
|
||||
2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a
|
||||
`redisSSLContext` object to hold configuration and use
|
||||
`redisInitiateSSLWithContext()` to initiate the SSL/TLS handshake.
|
||||
|
||||
```c
|
||||
/* An Hiredis SSL context. It holds SSL configuration and can be reused across
|
||||
* many contexts.
|
||||
*/
|
||||
redisSSLContext *ssl;
|
||||
|
||||
/* An error variable to indicate what went wrong, if the context fails to
|
||||
* initialize.
|
||||
*/
|
||||
redisSSLContextError ssl_error;
|
||||
|
||||
/* Initialize global OpenSSL state.
|
||||
*
|
||||
* You should call this only once when your app initializes, and only if
|
||||
* you don't explicitly or implicitly initialize OpenSSL it elsewhere.
|
||||
*/
|
||||
redisInitOpenSSL();
|
||||
|
||||
/* Create SSL context */
|
||||
ssl = redisCreateSSLContext(
|
||||
"cacertbundle.crt", /* File name of trusted CA/ca bundle file, optional */
|
||||
"/path/to/certs", /* Path of trusted certificates, optional */
|
||||
"client_cert.pem", /* File name of client certificate file, optional */
|
||||
"client_key.pem", /* File name of client private key, optional */
|
||||
"redis.mydomain.com", /* Server name to request (SNI), optional */
|
||||
&ssl_error
|
||||
) != REDIS_OK) {
|
||||
printf("SSL error: %s\n", redisSSLContextGetError(ssl_error);
|
||||
/* Abort... */
|
||||
}
|
||||
|
||||
/* Create Redis context and establish connection */
|
||||
c = redisConnect("localhost", 6443);
|
||||
if (c == NULL || c->err) {
|
||||
/* Handle error and abort... */
|
||||
}
|
||||
|
||||
/* Negotiate SSL/TLS */
|
||||
if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
|
||||
/* Handle error, in c->err / c->errstr */
|
||||
}
|
||||
```
|
||||
|
||||
## RESP3 PUSH replies
|
||||
Redis 6.0 introduced PUSH replies with the reply-type `>`. These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks.
|
||||
|
||||
### Default behavior
|
||||
Hiredis installs handlers on `redisContext` and `redisAsyncContext` by default, which will intercept and free any PUSH replies detected. This means existing code will work as-is after upgrading to Redis 6 and switching to `RESP3`.
|
||||
|
||||
### Custom PUSH handler prototypes
|
||||
The callback prototypes differ between `redisContext` and `redisAsyncContext`.
|
||||
|
||||
#### redisContext
|
||||
```c
|
||||
void my_push_handler(void *privdata, void *reply) {
|
||||
/* Handle the reply */
|
||||
|
||||
/* Note: We need to free the reply in our custom handler for
|
||||
blocking contexts. This lets us keep the reply if
|
||||
we want. */
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
```
|
||||
|
||||
#### redisAsyncContext
|
||||
```c
|
||||
void my_async_push_handler(redisAsyncContext *ac, void *reply) {
|
||||
/* Handle the reply */
|
||||
|
||||
/* Note: Because async hiredis always frees replies, you should
|
||||
not call freeReplyObject in an async push callback. */
|
||||
}
|
||||
```
|
||||
|
||||
### Installing a custom handler
|
||||
There are two ways to set your own PUSH handlers.
|
||||
|
||||
1. Set `push_cb` or `async_push_cb` in the `redisOptions` struct and connect with `redisConnectWithOptions` or `redisAsyncConnectWithOptions`.
|
||||
```c
|
||||
redisOptions = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||
options->push_cb = my_push_handler;
|
||||
redisContext *context = redisConnectWithOptions(&options);
|
||||
```
|
||||
2. Call `redisSetPushCallback` or `redisAsyncSetPushCallback` on a connected context.
|
||||
```c
|
||||
redisContext *context = redisConnect("127.0.0.1", 6379);
|
||||
redisSetPushCallback(context, my_push_handler);
|
||||
```
|
||||
|
||||
_Note `redisSetPushCallback` and `redisAsyncSetPushCallback` both return any currently configured handler, making it easy to override and then return to the old value._
|
||||
|
||||
### Specifying no handler
|
||||
If you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all. This can be done in two ways.
|
||||
1. Set the `REDIS_OPT_NO_PUSH_AUTOFREE` flag in `redisOptions` and leave the callback function pointer `NULL`.
|
||||
```c
|
||||
redisOptions = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||
options->options |= REDIS_OPT_NO_PUSH_AUTOFREE;
|
||||
redisContext *context = redisConnectWithOptions(&options);
|
||||
```
|
||||
3. Call `redisSetPushCallback` with `NULL` once connected.
|
||||
```c
|
||||
redisContext *context = redisConnect("127.0.0.1", 6379);
|
||||
redisSetPushCallback(context, NULL);
|
||||
```
|
||||
|
||||
_Note: With no handler configured, calls to `redisCommand` may generate more than one reply, so this strategy is only applicable when there's some kind of blocking`redisGetReply()` loop (e.g. `MONITOR` or `SUBSCRIBE` workloads)._
|
||||
|
||||
## Allocator injection
|
||||
|
||||
Hiredis uses a pass-thru structure of function pointers defined in [alloc.h](https://github.com/redis/hiredis/blob/f5d25850/alloc.h#L41) that contain the currently configured allocation and deallocation functions. By default they just point to libc (`malloc`, `calloc`, `realloc`, etc).
|
||||
|
||||
### Overriding
|
||||
|
||||
One can override the allocators like so:
|
||||
|
||||
```c
|
||||
hiredisAllocFuncs myfuncs = {
|
||||
.mallocFn = my_malloc,
|
||||
.callocFn = my_calloc,
|
||||
.reallocFn = my_realloc,
|
||||
.strdupFn = my_strdup,
|
||||
.freeFn = my_free,
|
||||
};
|
||||
|
||||
// Override allocators (function returns current allocators if needed)
|
||||
hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs);
|
||||
```
|
||||
|
||||
To reset the allocators to their default libc function simply call:
|
||||
|
||||
```c
|
||||
hiredisResetAllocators();
|
||||
```
|
||||
|
||||
## AUTHORS
|
||||
|
||||
Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
|
||||
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
|
||||
Hiredis is currently maintained by Matt Stancliff (matt at genges dot com) and
|
||||
Jan-Erik Rediger (janerik at fnordig dot com)
|
||||
Salvatore Sanfilippo (antirez at gmail),\
|
||||
Pieter Noordhuis (pcnoordhuis at gmail)\
|
||||
Michael Grunder (michael dot grunder at gmail)
|
||||
|
||||
_Hiredis is released under the BSD license._
|
||||
Vendored
+5
-2
@@ -96,7 +96,7 @@ static void redisAeCleanup(void *privdata) {
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
redisAeDelRead(privdata);
|
||||
redisAeDelWrite(privdata);
|
||||
free(e);
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
|
||||
@@ -108,7 +108,10 @@ static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisAeEvents*)malloc(sizeof(*e));
|
||||
e = (redisAeEvents*)hi_malloc(sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
e->loop = loop;
|
||||
e->fd = c->fd;
|
||||
|
||||
Vendored
+3
@@ -134,6 +134,9 @@ redis_source_new (redisAsyncContext *ac)
|
||||
g_return_val_if_fail(ac != NULL, NULL);
|
||||
|
||||
source = (RedisSource *)g_source_new(&source_funcs, sizeof *source);
|
||||
if (source == NULL)
|
||||
return NULL;
|
||||
|
||||
source->ac = ac;
|
||||
source->poll_fd.fd = c->fd;
|
||||
source->poll_fd.events = 0;
|
||||
|
||||
Vendored
+5
-2
@@ -43,7 +43,7 @@ static void redisIvykisCleanup(void *privdata) {
|
||||
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
|
||||
|
||||
iv_fd_unregister(&e->fd);
|
||||
free(e);
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static int redisIvykisAttach(redisAsyncContext *ac) {
|
||||
@@ -55,7 +55,10 @@ static int redisIvykisAttach(redisAsyncContext *ac) {
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisIvykisEvents*)malloc(sizeof(*e));
|
||||
e = (redisIvykisEvents*)hi_malloc(sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
|
||||
Vendored
+35
-3
@@ -41,6 +41,7 @@ typedef struct redisLibevEvents {
|
||||
struct ev_loop *loop;
|
||||
int reading, writing;
|
||||
ev_io rev, wev;
|
||||
ev_timer timer;
|
||||
} redisLibevEvents;
|
||||
|
||||
static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
|
||||
@@ -103,11 +104,39 @@ static void redisLibevDelWrite(void *privdata) {
|
||||
}
|
||||
}
|
||||
|
||||
static void redisLibevStopTimer(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
ev_timer_stop(EV_A_ &e->timer);
|
||||
}
|
||||
|
||||
static void redisLibevCleanup(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
redisLibevDelRead(privdata);
|
||||
redisLibevDelWrite(privdata);
|
||||
free(e);
|
||||
redisLibevStopTimer(privdata);
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) {
|
||||
((void)revents);
|
||||
redisLibevEvents *e = (redisLibevEvents*)timer->data;
|
||||
redisAsyncHandleTimeout(e->context);
|
||||
}
|
||||
|
||||
static void redisLibevSetTimeout(void *privdata, struct timeval tv) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
|
||||
if (!ev_is_active(&e->timer)) {
|
||||
ev_init(&e->timer, redisLibevTimeout);
|
||||
e->timer.data = e;
|
||||
}
|
||||
|
||||
e->timer.repeat = tv.tv_sec + tv.tv_usec / 1000000.00;
|
||||
ev_timer_again(EV_A_ &e->timer);
|
||||
}
|
||||
|
||||
static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
|
||||
@@ -119,14 +148,16 @@ static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisLibevEvents*)malloc(sizeof(*e));
|
||||
e = (redisLibevEvents*)hi_calloc(1, sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
#if EV_MULTIPLICITY
|
||||
e->loop = loop;
|
||||
#else
|
||||
e->loop = NULL;
|
||||
#endif
|
||||
e->reading = e->writing = 0;
|
||||
e->rev.data = e;
|
||||
e->wev.data = e;
|
||||
|
||||
@@ -136,6 +167,7 @@ static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
|
||||
ac->ev.addWrite = redisLibevAddWrite;
|
||||
ac->ev.delWrite = redisLibevDelWrite;
|
||||
ac->ev.cleanup = redisLibevCleanup;
|
||||
ac->ev.scheduleTimer = redisLibevSetTimeout;
|
||||
ac->ev.data = e;
|
||||
|
||||
/* Initialize read/write events */
|
||||
|
||||
Vendored
+5
-2
@@ -47,7 +47,7 @@ typedef struct redisLibeventEvents {
|
||||
} redisLibeventEvents;
|
||||
|
||||
static void redisLibeventDestroy(redisLibeventEvents *e) {
|
||||
free(e);
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static void redisLibeventHandler(int fd, short event, void *arg) {
|
||||
@@ -152,7 +152,10 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisLibeventEvents*)calloc(1, sizeof(*e));
|
||||
e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
|
||||
Vendored
+5
-7
@@ -73,7 +73,7 @@ static void redisLibuvDelWrite(void *privdata) {
|
||||
static void on_close(uv_handle_t* handle) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
|
||||
|
||||
free(p);
|
||||
hi_free(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,15 +98,13 @@ static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
|
||||
ac->ev.delWrite = redisLibuvDelWrite;
|
||||
ac->ev.cleanup = redisLibuvCleanup;
|
||||
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p));
|
||||
|
||||
if (!p) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)hi_malloc(sizeof(*p));
|
||||
if (p == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
if (uv_poll_init(loop, &p->handle, c->fd) != 0) {
|
||||
if (uv_poll_init_socket(loop, &p->handle, c->fd) != 0) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+4
-3
@@ -27,7 +27,7 @@ static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) {
|
||||
CFSocketInvalidate(redisRunLoop->socketRef);
|
||||
CFRelease(redisRunLoop->socketRef);
|
||||
}
|
||||
free(redisRunLoop);
|
||||
hi_free(redisRunLoop);
|
||||
}
|
||||
return REDIS_ERR;
|
||||
}
|
||||
@@ -80,8 +80,9 @@ static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLo
|
||||
/* Nothing should be attached when something is already attached */
|
||||
if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR;
|
||||
|
||||
RedisRunLoop* redisRunLoop = (RedisRunLoop*) calloc(1, sizeof(RedisRunLoop));
|
||||
if( !redisRunLoop ) return REDIS_ERR;
|
||||
RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop));
|
||||
if (redisRunLoop == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Setup redis stuff */
|
||||
redisRunLoop->context = redisAsyncCtx;
|
||||
|
||||
Vendored
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include "alloc.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
hiredisAllocFuncs hiredisAllocFns = {
|
||||
.mallocFn = malloc,
|
||||
.callocFn = calloc,
|
||||
.reallocFn = realloc,
|
||||
.strdupFn = strdup,
|
||||
.freeFn = free,
|
||||
};
|
||||
|
||||
/* Override hiredis' allocators with ones supplied by the user */
|
||||
hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *override) {
|
||||
hiredisAllocFuncs orig = hiredisAllocFns;
|
||||
|
||||
hiredisAllocFns = *override;
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
/* Reset allocators to use libc defaults */
|
||||
void hiredisResetAllocators(void) {
|
||||
hiredisAllocFns = (hiredisAllocFuncs) {
|
||||
.mallocFn = malloc,
|
||||
.callocFn = calloc,
|
||||
.reallocFn = realloc,
|
||||
.strdupFn = strdup,
|
||||
.freeFn = free,
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void *hi_malloc(size_t size) {
|
||||
return hiredisAllocFns.mallocFn(size);
|
||||
}
|
||||
|
||||
void *hi_calloc(size_t nmemb, size_t size) {
|
||||
return hiredisAllocFns.callocFn(nmemb, size);
|
||||
}
|
||||
|
||||
void *hi_realloc(void *ptr, size_t size) {
|
||||
return hiredisAllocFns.reallocFn(ptr, size);
|
||||
}
|
||||
|
||||
char *hi_strdup(const char *str) {
|
||||
return hiredisAllocFns.strdupFn(str);
|
||||
}
|
||||
|
||||
void hi_free(void *ptr) {
|
||||
hiredisAllocFns.freeFn(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef HIREDIS_ALLOC_H
|
||||
#define HIREDIS_ALLOC_H
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structure pointing to our actually configured allocators */
|
||||
typedef struct hiredisAllocFuncs {
|
||||
void *(*mallocFn)(size_t);
|
||||
void *(*callocFn)(size_t,size_t);
|
||||
void *(*reallocFn)(void*,size_t);
|
||||
char *(*strdupFn)(const char*);
|
||||
void (*freeFn)(void*);
|
||||
} hiredisAllocFuncs;
|
||||
|
||||
hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha);
|
||||
void hiredisResetAllocators(void);
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/* Hiredis' configured allocator function pointer struct */
|
||||
extern hiredisAllocFuncs hiredisAllocFns;
|
||||
|
||||
static inline void *hi_malloc(size_t size) {
|
||||
return hiredisAllocFns.mallocFn(size);
|
||||
}
|
||||
|
||||
static inline void *hi_calloc(size_t nmemb, size_t size) {
|
||||
return hiredisAllocFns.callocFn(nmemb, size);
|
||||
}
|
||||
|
||||
static inline void *hi_realloc(void *ptr, size_t size) {
|
||||
return hiredisAllocFns.reallocFn(ptr, size);
|
||||
}
|
||||
|
||||
static inline char *hi_strdup(const char *str) {
|
||||
return hiredisAllocFns.strdupFn(str);
|
||||
}
|
||||
|
||||
static inline void hi_free(void *ptr) {
|
||||
hiredisAllocFns.freeFn(ptr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *hi_malloc(size_t size);
|
||||
void *hi_calloc(size_t nmemb, size_t size);
|
||||
void *hi_realloc(void *ptr, size_t size);
|
||||
char *hi_strdup(const char *str);
|
||||
void hi_free(void *ptr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HIREDIS_ALLOC_H */
|
||||
Vendored
+173
-52
@@ -30,6 +30,7 @@
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include "alloc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef _MSC_VER
|
||||
@@ -46,18 +47,24 @@
|
||||
|
||||
#include "async_private.h"
|
||||
|
||||
/* Forward declaration of function in hiredis.c */
|
||||
/* Forward declarations of hiredis.c functions */
|
||||
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len);
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
/* Functions managing dictionary of callbacks for pub/sub. */
|
||||
static unsigned int callbackHash(const void *key) {
|
||||
return dictGenHashFunction((const unsigned char *)key,
|
||||
sdslen((const sds)key));
|
||||
hi_sdslen((const hisds)key));
|
||||
}
|
||||
|
||||
static void *callbackValDup(void *privdata, const void *src) {
|
||||
((void) privdata);
|
||||
redisCallback *dup = malloc(sizeof(*dup));
|
||||
redisCallback *dup;
|
||||
|
||||
dup = hi_malloc(sizeof(*dup));
|
||||
if (dup == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(dup,src,sizeof(*dup));
|
||||
return dup;
|
||||
}
|
||||
@@ -66,20 +73,20 @@ static int callbackKeyCompare(void *privdata, const void *key1, const void *key2
|
||||
int l1, l2;
|
||||
((void) privdata);
|
||||
|
||||
l1 = sdslen((const sds)key1);
|
||||
l2 = sdslen((const sds)key2);
|
||||
l1 = hi_sdslen((const hisds)key1);
|
||||
l2 = hi_sdslen((const hisds)key2);
|
||||
if (l1 != l2) return 0;
|
||||
return memcmp(key1,key2,l1) == 0;
|
||||
}
|
||||
|
||||
static void callbackKeyDestructor(void *privdata, void *key) {
|
||||
((void) privdata);
|
||||
sdsfree((sds)key);
|
||||
hi_sdsfree((hisds)key);
|
||||
}
|
||||
|
||||
static void callbackValDestructor(void *privdata, void *val) {
|
||||
((void) privdata);
|
||||
free(val);
|
||||
hi_free(val);
|
||||
}
|
||||
|
||||
static dictType callbackDict = {
|
||||
@@ -93,10 +100,19 @@ static dictType callbackDict = {
|
||||
|
||||
static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
|
||||
redisAsyncContext *ac;
|
||||
dict *channels = NULL, *patterns = NULL;
|
||||
|
||||
ac = realloc(c,sizeof(redisAsyncContext));
|
||||
channels = dictCreate(&callbackDict,NULL);
|
||||
if (channels == NULL)
|
||||
goto oom;
|
||||
|
||||
patterns = dictCreate(&callbackDict,NULL);
|
||||
if (patterns == NULL)
|
||||
goto oom;
|
||||
|
||||
ac = hi_realloc(c,sizeof(redisAsyncContext));
|
||||
if (ac == NULL)
|
||||
return NULL;
|
||||
goto oom;
|
||||
|
||||
c = &(ac->c);
|
||||
|
||||
@@ -108,6 +124,7 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
|
||||
ac->err = 0;
|
||||
ac->errstr = NULL;
|
||||
ac->data = NULL;
|
||||
ac->dataCleanup = NULL;
|
||||
|
||||
ac->ev.data = NULL;
|
||||
ac->ev.addRead = NULL;
|
||||
@@ -124,9 +141,14 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
|
||||
ac->replies.tail = NULL;
|
||||
ac->sub.invalid.head = NULL;
|
||||
ac->sub.invalid.tail = NULL;
|
||||
ac->sub.channels = dictCreate(&callbackDict,NULL);
|
||||
ac->sub.patterns = dictCreate(&callbackDict,NULL);
|
||||
ac->sub.channels = channels;
|
||||
ac->sub.patterns = patterns;
|
||||
|
||||
return ac;
|
||||
oom:
|
||||
if (channels) dictRelease(channels);
|
||||
if (patterns) dictRelease(patterns);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We want the error field to be accessible directly instead of requiring
|
||||
@@ -145,16 +167,26 @@ redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options) {
|
||||
redisContext *c;
|
||||
redisAsyncContext *ac;
|
||||
|
||||
/* Clear any erroneously set sync callback and flag that we don't want to
|
||||
* use freeReplyObject by default. */
|
||||
myOptions.push_cb = NULL;
|
||||
myOptions.options |= REDIS_OPT_NO_PUSH_AUTOFREE;
|
||||
|
||||
myOptions.options |= REDIS_OPT_NONBLOCK;
|
||||
c = redisConnectWithOptions(&myOptions);
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ac = redisAsyncInitialize(c);
|
||||
if (ac == NULL) {
|
||||
redisFree(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set any configured async push handler */
|
||||
redisAsyncSetPushCallback(ac, myOptions.async_push_cb);
|
||||
|
||||
__redisAsyncCopyError(ac);
|
||||
return ac;
|
||||
}
|
||||
@@ -214,7 +246,7 @@ static int __redisPushCallback(redisCallbackList *list, redisCallback *source) {
|
||||
redisCallback *cb;
|
||||
|
||||
/* Copy callback from stack to heap */
|
||||
cb = malloc(sizeof(*cb));
|
||||
cb = hi_malloc(sizeof(*cb));
|
||||
if (cb == NULL)
|
||||
return REDIS_ERR_OOM;
|
||||
|
||||
@@ -242,7 +274,7 @@ static int __redisShiftCallback(redisCallbackList *list, redisCallback *target)
|
||||
/* Copy callback from heap to stack */
|
||||
if (target != NULL)
|
||||
memcpy(target,cb,sizeof(*cb));
|
||||
free(cb);
|
||||
hi_free(cb);
|
||||
return REDIS_OK;
|
||||
}
|
||||
return REDIS_ERR;
|
||||
@@ -257,6 +289,14 @@ static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisRe
|
||||
}
|
||||
}
|
||||
|
||||
static void __redisRunPushCallback(redisAsyncContext *ac, redisReply *reply) {
|
||||
if (ac->push_cb != NULL) {
|
||||
ac->c.flags |= REDIS_IN_CALLBACK;
|
||||
ac->push_cb(ac, reply);
|
||||
ac->c.flags &= ~REDIS_IN_CALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function to free the context. */
|
||||
static void __redisAsyncFree(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
@@ -272,18 +312,28 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
|
||||
while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK)
|
||||
__redisRunCallback(ac,&cb,NULL);
|
||||
|
||||
/* Run subscription callbacks callbacks with NULL reply */
|
||||
it = dictGetIterator(ac->sub.channels);
|
||||
while ((de = dictNext(it)) != NULL)
|
||||
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
|
||||
dictReleaseIterator(it);
|
||||
dictRelease(ac->sub.channels);
|
||||
/* Run subscription callbacks with NULL reply */
|
||||
if (ac->sub.channels) {
|
||||
it = dictGetIterator(ac->sub.channels);
|
||||
if (it != NULL) {
|
||||
while ((de = dictNext(it)) != NULL)
|
||||
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
|
||||
dictReleaseIterator(it);
|
||||
}
|
||||
|
||||
it = dictGetIterator(ac->sub.patterns);
|
||||
while ((de = dictNext(it)) != NULL)
|
||||
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
|
||||
dictReleaseIterator(it);
|
||||
dictRelease(ac->sub.patterns);
|
||||
dictRelease(ac->sub.channels);
|
||||
}
|
||||
|
||||
if (ac->sub.patterns) {
|
||||
it = dictGetIterator(ac->sub.patterns);
|
||||
if (it != NULL) {
|
||||
while ((de = dictNext(it)) != NULL)
|
||||
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
|
||||
dictReleaseIterator(it);
|
||||
}
|
||||
|
||||
dictRelease(ac->sub.patterns);
|
||||
}
|
||||
|
||||
/* Signal event lib to clean up */
|
||||
_EL_CLEANUP(ac);
|
||||
@@ -298,6 +348,10 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
|
||||
}
|
||||
}
|
||||
|
||||
if (ac->dataCleanup) {
|
||||
ac->dataCleanup(ac->data);
|
||||
}
|
||||
|
||||
/* Cleanup self */
|
||||
redisFree(c);
|
||||
}
|
||||
@@ -364,11 +418,11 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
|
||||
dictEntry *de;
|
||||
int pvariant;
|
||||
char *stype;
|
||||
sds sname;
|
||||
hisds sname;
|
||||
|
||||
/* Custom reply functions are not supported for pub/sub. This will fail
|
||||
* very hard when they are used... */
|
||||
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||
if (reply->type == REDIS_REPLY_ARRAY || reply->type == REDIS_REPLY_PUSH) {
|
||||
assert(reply->elements >= 2);
|
||||
assert(reply->element[0]->type == REDIS_REPLY_STRING);
|
||||
stype = reply->element[0]->str;
|
||||
@@ -381,7 +435,10 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
|
||||
|
||||
/* Locate the right callback */
|
||||
assert(reply->element[1]->type == REDIS_REPLY_STRING);
|
||||
sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
|
||||
sname = hi_sdsnewlen(reply->element[1]->str,reply->element[1]->len);
|
||||
if (sname == NULL)
|
||||
goto oom;
|
||||
|
||||
de = dictFind(callbacks,sname);
|
||||
if (de != NULL) {
|
||||
cb = dictGetEntryVal(de);
|
||||
@@ -409,12 +466,39 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
|
||||
c->flags &= ~REDIS_SUBSCRIBED;
|
||||
}
|
||||
}
|
||||
sdsfree(sname);
|
||||
hi_sdsfree(sname);
|
||||
} else {
|
||||
/* Shift callback for invalid commands. */
|
||||
__redisShiftCallback(&ac->sub.invalid,dstcb);
|
||||
}
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
#define redisIsSpontaneousPushReply(r) \
|
||||
(redisIsPushReply(r) && !redisIsSubscribeReply(r))
|
||||
|
||||
static int redisIsSubscribeReply(redisReply *reply) {
|
||||
char *str;
|
||||
size_t len, off;
|
||||
|
||||
/* We will always have at least one string with the subscribe/message type */
|
||||
if (reply->elements < 1 || reply->element[0]->type != REDIS_REPLY_STRING ||
|
||||
reply->element[0]->len < sizeof("message") - 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the string/len moving past 'p' if needed */
|
||||
off = tolower(reply->element[0]->str[0]) == 'p';
|
||||
str = reply->element[0]->str + off;
|
||||
len = reply->element[0]->len - off;
|
||||
|
||||
return !strncasecmp(str, "subscribe", len) ||
|
||||
!strncasecmp(str, "message", len);
|
||||
|
||||
}
|
||||
|
||||
void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||
@@ -427,7 +511,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||
if (reply == NULL) {
|
||||
/* When the connection is being disconnected and there are
|
||||
* no more replies, this is the cue to really disconnect. */
|
||||
if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0
|
||||
if (c->flags & REDIS_DISCONNECTING && hi_sdslen(c->obuf) == 0
|
||||
&& ac->replies.head == NULL) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
return;
|
||||
@@ -443,8 +527,18 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Even if the context is subscribed, pending regular callbacks will
|
||||
* get a reply before pub/sub messages arrive. */
|
||||
/* Send any non-subscribe related PUSH messages to our PUSH handler
|
||||
* while allowing subscribe related PUSH messages to pass through.
|
||||
* This allows existing code to be backward compatible and work in
|
||||
* either RESP2 or RESP3 mode. */
|
||||
if (redisIsSpontaneousPushReply(reply)) {
|
||||
__redisRunPushCallback(ac, reply);
|
||||
c->reader->fn->freeObject(reply);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Even if the context is subscribed, pending regular
|
||||
* callbacks will get a reply before pub/sub messages arrive. */
|
||||
if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
|
||||
/*
|
||||
* A spontaneous reply in a not-subscribed context can be the error
|
||||
@@ -497,20 +591,31 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
static void __redisAsyncHandleConnectFailure(redisAsyncContext *ac) {
|
||||
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
/* Internal helper function to detect socket status the first time a read or
|
||||
* write event fires. When connecting was not successful, the connect callback
|
||||
* is called with a REDIS_ERR status and the context is free'd. */
|
||||
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
|
||||
int completed = 0;
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (redisCheckConnectDone(c, &completed) == REDIS_ERR) {
|
||||
/* Error! */
|
||||
redisCheckSocketError(c);
|
||||
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
|
||||
__redisAsyncDisconnect(ac);
|
||||
__redisAsyncHandleConnectFailure(ac);
|
||||
return REDIS_ERR;
|
||||
} else if (completed == 1) {
|
||||
/* connected! */
|
||||
if (c->connection_type == REDIS_CONN_TCP &&
|
||||
redisSetTcpNoDelay(c) == REDIS_ERR) {
|
||||
__redisAsyncHandleConnectFailure(ac);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (ac->onConnect) ac->onConnect(ac, REDIS_OK);
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
return REDIS_OK;
|
||||
@@ -582,8 +687,6 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) {
|
||||
c->funcs->async_write(ac);
|
||||
}
|
||||
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
void redisAsyncHandleTimeout(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb;
|
||||
@@ -641,7 +744,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
const char *cstr, *astr;
|
||||
size_t clen, alen;
|
||||
const char *p;
|
||||
sds sname;
|
||||
hisds sname;
|
||||
int ret;
|
||||
|
||||
/* Don't accept new commands when the connection is about to be closed. */
|
||||
@@ -665,7 +768,10 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
|
||||
/* Add every channel/pattern to the list of subscription callbacks. */
|
||||
while ((p = nextArgument(p,&astr,&alen)) != NULL) {
|
||||
sname = sdsnewlen(astr,alen);
|
||||
sname = hi_sdsnewlen(astr,alen);
|
||||
if (sname == NULL)
|
||||
goto oom;
|
||||
|
||||
if (pvariant)
|
||||
cbdict = ac->sub.patterns;
|
||||
else
|
||||
@@ -680,7 +786,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
|
||||
ret = dictReplace(cbdict,sname,&cb);
|
||||
|
||||
if (ret == 0) sdsfree(sname);
|
||||
if (ret == 0) hi_sdsfree(sname);
|
||||
}
|
||||
} else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) {
|
||||
/* It is only useful to call (P)UNSUBSCRIBE when the context is
|
||||
@@ -709,6 +815,9 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
_EL_ADD_WRITE(ac);
|
||||
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) {
|
||||
@@ -722,7 +831,7 @@ int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdat
|
||||
return REDIS_ERR;
|
||||
|
||||
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -736,14 +845,14 @@ int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata
|
||||
}
|
||||
|
||||
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) {
|
||||
sds cmd;
|
||||
hisds cmd;
|
||||
int len;
|
||||
int status;
|
||||
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
|
||||
if (len < 0)
|
||||
return REDIS_ERR;
|
||||
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
|
||||
sdsfree(cmd);
|
||||
hi_sdsfree(cmd);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -752,15 +861,27 @@ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
return status;
|
||||
}
|
||||
|
||||
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
|
||||
if (!ac->c.timeout) {
|
||||
ac->c.timeout = calloc(1, sizeof(tv));
|
||||
}
|
||||
|
||||
if (tv.tv_sec == ac->c.timeout->tv_sec &&
|
||||
tv.tv_usec == ac->c.timeout->tv_usec) {
|
||||
return;
|
||||
}
|
||||
|
||||
*ac->c.timeout = tv;
|
||||
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn) {
|
||||
redisAsyncPushFn *old = ac->push_cb;
|
||||
ac->push_cb = fn;
|
||||
return old;
|
||||
}
|
||||
|
||||
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
|
||||
if (!ac->c.command_timeout) {
|
||||
ac->c.command_timeout = hi_calloc(1, sizeof(tv));
|
||||
if (ac->c.command_timeout == NULL) {
|
||||
__redisSetError(&ac->c, REDIS_ERR_OOM, "Out of memory");
|
||||
__redisAsyncCopyError(ac);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (tv.tv_sec != ac->c.command_timeout->tv_sec ||
|
||||
tv.tv_usec != ac->c.command_timeout->tv_usec)
|
||||
{
|
||||
*ac->c.command_timeout = tv;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
Vendored
+6
-1
@@ -70,6 +70,7 @@ typedef struct redisAsyncContext {
|
||||
|
||||
/* Not used by hiredis */
|
||||
void *data;
|
||||
void (*dataCleanup)(void *privdata);
|
||||
|
||||
/* Event library data and hooks */
|
||||
struct {
|
||||
@@ -105,6 +106,9 @@ typedef struct redisAsyncContext {
|
||||
struct dict *channels;
|
||||
struct dict *patterns;
|
||||
} sub;
|
||||
|
||||
/* Any configured RESP3 PUSH handler */
|
||||
redisAsyncPushFn *push_cb;
|
||||
} redisAsyncContext;
|
||||
|
||||
/* Functions that proxy to hiredis */
|
||||
@@ -117,7 +121,8 @@ redisAsyncContext *redisAsyncConnectUnix(const char *path);
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
|
||||
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
|
||||
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn);
|
||||
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
|
||||
void redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
void redisAsyncFree(redisAsyncContext *ac);
|
||||
|
||||
|
||||
Vendored
+13
-10
@@ -51,18 +51,21 @@
|
||||
#define _EL_CLEANUP(ctx) do { \
|
||||
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
|
||||
ctx->ev.cleanup = NULL; \
|
||||
} while(0);
|
||||
} while(0)
|
||||
|
||||
static inline void refreshTimeout(redisAsyncContext *ctx) {
|
||||
if (ctx->c.timeout && ctx->ev.scheduleTimer &&
|
||||
(ctx->c.timeout->tv_sec || ctx->c.timeout->tv_usec)) {
|
||||
ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.timeout);
|
||||
// } else {
|
||||
// printf("Not scheduling timer.. (tmo=%p)\n", ctx->c.timeout);
|
||||
// if (ctx->c.timeout){
|
||||
// printf("tv_sec: %u. tv_usec: %u\n", ctx->c.timeout->tv_sec,
|
||||
// ctx->c.timeout->tv_usec);
|
||||
// }
|
||||
#define REDIS_TIMER_ISSET(tvp) \
|
||||
(tvp && ((tvp)->tv_sec || (tvp)->tv_usec))
|
||||
|
||||
#define REDIS_EL_TIMER(ac, tvp) \
|
||||
if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \
|
||||
(ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \
|
||||
}
|
||||
|
||||
if (ctx->c.flags & REDIS_CONNECTED) {
|
||||
REDIS_EL_TIMER(ctx, ctx->c.command_timeout);
|
||||
} else {
|
||||
REDIS_EL_TIMER(ctx, ctx->c.connect_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+25
-11
@@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include "alloc.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
@@ -71,7 +72,10 @@ static void _dictReset(dict *ht) {
|
||||
|
||||
/* Create a new hash table */
|
||||
static dict *dictCreate(dictType *type, void *privDataPtr) {
|
||||
dict *ht = malloc(sizeof(*ht));
|
||||
dict *ht = hi_malloc(sizeof(*ht));
|
||||
if (ht == NULL)
|
||||
return NULL;
|
||||
|
||||
_dictInit(ht,type,privDataPtr);
|
||||
return ht;
|
||||
}
|
||||
@@ -97,7 +101,9 @@ static int dictExpand(dict *ht, unsigned long size) {
|
||||
_dictInit(&n, ht->type, ht->privdata);
|
||||
n.size = realsize;
|
||||
n.sizemask = realsize-1;
|
||||
n.table = calloc(realsize,sizeof(dictEntry*));
|
||||
n.table = hi_calloc(realsize,sizeof(dictEntry*));
|
||||
if (n.table == NULL)
|
||||
return DICT_ERR;
|
||||
|
||||
/* Copy all the elements from the old to the new table:
|
||||
* note that if the old hash table is empty ht->size is zero,
|
||||
@@ -124,7 +130,7 @@ static int dictExpand(dict *ht, unsigned long size) {
|
||||
}
|
||||
}
|
||||
assert(ht->used == 0);
|
||||
free(ht->table);
|
||||
hi_free(ht->table);
|
||||
|
||||
/* Remap the new hashtable in the old */
|
||||
*ht = n;
|
||||
@@ -142,7 +148,10 @@ static int dictAdd(dict *ht, void *key, void *val) {
|
||||
return DICT_ERR;
|
||||
|
||||
/* Allocates the memory and stores key */
|
||||
entry = malloc(sizeof(*entry));
|
||||
entry = hi_malloc(sizeof(*entry));
|
||||
if (entry == NULL)
|
||||
return DICT_ERR;
|
||||
|
||||
entry->next = ht->table[index];
|
||||
ht->table[index] = entry;
|
||||
|
||||
@@ -166,6 +175,9 @@ static int dictReplace(dict *ht, void *key, void *val) {
|
||||
return 1;
|
||||
/* It already exists, get the entry */
|
||||
entry = dictFind(ht, key);
|
||||
if (entry == NULL)
|
||||
return 0;
|
||||
|
||||
/* Free the old value and set the new one */
|
||||
/* Set the new value and free the old one. Note that it is important
|
||||
* to do that in this order, as the value may just be exactly the same
|
||||
@@ -199,7 +211,7 @@ static int dictDelete(dict *ht, const void *key) {
|
||||
|
||||
dictFreeEntryKey(ht,de);
|
||||
dictFreeEntryVal(ht,de);
|
||||
free(de);
|
||||
hi_free(de);
|
||||
ht->used--;
|
||||
return DICT_OK;
|
||||
}
|
||||
@@ -222,13 +234,13 @@ static int _dictClear(dict *ht) {
|
||||
nextHe = he->next;
|
||||
dictFreeEntryKey(ht, he);
|
||||
dictFreeEntryVal(ht, he);
|
||||
free(he);
|
||||
hi_free(he);
|
||||
ht->used--;
|
||||
he = nextHe;
|
||||
}
|
||||
}
|
||||
/* Free the table and the allocated cache structure */
|
||||
free(ht->table);
|
||||
hi_free(ht->table);
|
||||
/* Re-initialize the table */
|
||||
_dictReset(ht);
|
||||
return DICT_OK; /* never fails */
|
||||
@@ -237,7 +249,7 @@ static int _dictClear(dict *ht) {
|
||||
/* Clear & Release the hash table */
|
||||
static void dictRelease(dict *ht) {
|
||||
_dictClear(ht);
|
||||
free(ht);
|
||||
hi_free(ht);
|
||||
}
|
||||
|
||||
static dictEntry *dictFind(dict *ht, const void *key) {
|
||||
@@ -256,7 +268,9 @@ static dictEntry *dictFind(dict *ht, const void *key) {
|
||||
}
|
||||
|
||||
static dictIterator *dictGetIterator(dict *ht) {
|
||||
dictIterator *iter = malloc(sizeof(*iter));
|
||||
dictIterator *iter = hi_malloc(sizeof(*iter));
|
||||
if (iter == NULL)
|
||||
return NULL;
|
||||
|
||||
iter->ht = ht;
|
||||
iter->index = -1;
|
||||
@@ -286,7 +300,7 @@ static dictEntry *dictNext(dictIterator *iter) {
|
||||
}
|
||||
|
||||
static void dictReleaseIterator(dictIterator *iter) {
|
||||
free(iter);
|
||||
hi_free(iter);
|
||||
}
|
||||
|
||||
/* ------------------------- private functions ------------------------------ */
|
||||
@@ -294,7 +308,7 @@ static void dictReleaseIterator(dictIterator *iter) {
|
||||
/* Expand the hash table if needed */
|
||||
static int _dictExpandIfNeeded(dict *ht) {
|
||||
/* If the hash table is empty expand it to the initial size,
|
||||
* if the table is "full" dobule its size. */
|
||||
* if the table is "full" double its size. */
|
||||
if (ht->size == 0)
|
||||
return dictExpand(ht, DICT_HT_INITIAL_SIZE);
|
||||
if (ht->used == ht->size)
|
||||
|
||||
Vendored
+3
@@ -44,3 +44,6 @@ ENDIF()
|
||||
|
||||
ADD_EXECUTABLE(example example.c)
|
||||
TARGET_LINK_LIBRARIES(example hiredis)
|
||||
|
||||
ADD_EXECUTABLE(example-push example-push.c)
|
||||
TARGET_LINK_LIBRARIES(example-push hiredis)
|
||||
+2
@@ -33,7 +33,9 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
iv_init();
|
||||
|
||||
|
||||
+2
@@ -33,7 +33,9 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (c->err) {
|
||||
|
||||
+18
-1
@@ -34,7 +34,10 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
struct event_base *base = event_base_new();
|
||||
if (argc < 5) {
|
||||
fprintf(stderr,
|
||||
@@ -52,13 +55,25 @@ int main (int argc, char **argv) {
|
||||
const char *certKey = argv[5];
|
||||
const char *caCert = argc > 5 ? argv[6] : NULL;
|
||||
|
||||
redisSSLContext *ssl;
|
||||
redisSSLContextError ssl_error;
|
||||
|
||||
redisInitOpenSSL();
|
||||
|
||||
ssl = redisCreateSSLContext(caCert, NULL,
|
||||
cert, certKey, NULL, &ssl_error);
|
||||
if (!ssl) {
|
||||
printf("Error: %s\n", redisSSLContextGetError(ssl_error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect(hostname, port);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
if (redisSecureConnection(&c->c, caCert, cert, certKey, "sni") != REDIS_OK) {
|
||||
if (redisInitiateSSLWithContext(&c->c, ssl) != REDIS_OK) {
|
||||
printf("SSL Error!\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -69,5 +84,7 @@ int main (int argc, char **argv) {
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue);
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
event_base_dispatch(base);
|
||||
|
||||
redisFreeSSLContext(ssl);
|
||||
return 0;
|
||||
}
|
||||
+4
-1
@@ -38,13 +38,16 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
struct event_base *base = event_base_new();
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||
struct timeval tv = {0};
|
||||
tv.tv_sec = 1;
|
||||
options.timeout = &tv;
|
||||
options.connect_timeout = &tv;
|
||||
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
|
||||
|
||||
+3
@@ -33,7 +33,10 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
|
||||
Vendored
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <hiredis.h>
|
||||
#include <win32.h>
|
||||
|
||||
#define KEY_COUNT 5
|
||||
|
||||
#define panicAbort(fmt, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); \
|
||||
exit(-1); \
|
||||
} while (0)
|
||||
|
||||
static void assertReplyAndFree(redisContext *context, redisReply *reply, int type) {
|
||||
if (reply == NULL)
|
||||
panicAbort("NULL reply from server (error: %s)", context->errstr);
|
||||
|
||||
if (reply->type != type) {
|
||||
if (reply->type == REDIS_REPLY_ERROR)
|
||||
fprintf(stderr, "Redis Error: %s\n", reply->str);
|
||||
|
||||
panicAbort("Expected reply type %d but got type %d", type, reply->type);
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Switch to the RESP3 protocol and enable client tracking */
|
||||
static void enableClientTracking(redisContext *c) {
|
||||
redisReply *reply = redisCommand(c, "HELLO 3");
|
||||
if (reply == NULL || c->err) {
|
||||
panicAbort("NULL reply or server error (error: %s)", c->errstr);
|
||||
}
|
||||
|
||||
if (reply->type != REDIS_REPLY_MAP) {
|
||||
fprintf(stderr, "Error: Can't send HELLO 3 command. Are you sure you're ");
|
||||
fprintf(stderr, "connected to redis-server >= 6.0.0?\nRedis error: %s\n",
|
||||
reply->type == REDIS_REPLY_ERROR ? reply->str : "(unknown)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Enable client tracking */
|
||||
reply = redisCommand(c, "CLIENT TRACKING ON");
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
|
||||
}
|
||||
|
||||
void pushReplyHandler(void *privdata, void *r) {
|
||||
redisReply *reply = r;
|
||||
int *invalidations = privdata;
|
||||
|
||||
/* Sanity check on the invalidation reply */
|
||||
if (reply->type != REDIS_REPLY_PUSH || reply->elements != 2 ||
|
||||
reply->element[1]->type != REDIS_REPLY_ARRAY ||
|
||||
reply->element[1]->element[0]->type != REDIS_REPLY_STRING)
|
||||
{
|
||||
panicAbort("%s", "Can't parse PUSH message!");
|
||||
}
|
||||
|
||||
/* Increment our invalidation count */
|
||||
*invalidations += 1;
|
||||
|
||||
printf("pushReplyHandler(): INVALIDATE '%s' (invalidation count: %d)\n",
|
||||
reply->element[1]->element[0]->str, *invalidations);
|
||||
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* We aren't actually freeing anything here, but it is included to show that we can
|
||||
* have hiredis call our data destructor when freeing the context */
|
||||
void privdata_dtor(void *privdata) {
|
||||
unsigned int *icount = privdata;
|
||||
printf("privdata_dtor(): In context privdata dtor (invalidations: %u)\n", *icount);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j, invalidations = 0;
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
|
||||
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
|
||||
int port = (argc > 2) ? atoi(argv[2]) : 6379;
|
||||
|
||||
redisOptions o = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&o, hostname, port);
|
||||
|
||||
/* Set our context privdata to the address of our invalidation counter. Each
|
||||
* time our PUSH handler is called, hiredis will pass the privdata for context.
|
||||
*
|
||||
* This could also be done after we create the context like so:
|
||||
*
|
||||
* c->privdata = &invalidations;
|
||||
* c->free_privdata = privdata_dtor;
|
||||
*/
|
||||
REDIS_OPTIONS_SET_PRIVDATA(&o, &invalidations, privdata_dtor);
|
||||
|
||||
/* Set our custom PUSH message handler */
|
||||
o.push_cb = pushReplyHandler;
|
||||
|
||||
c = redisConnectWithOptions(&o);
|
||||
if (c == NULL || c->err)
|
||||
panicAbort("Connection error: %s", c ? c->errstr : "OOM");
|
||||
|
||||
/* Enable RESP3 and turn on client tracking */
|
||||
enableClientTracking(c);
|
||||
|
||||
/* Set some keys and then read them back. Once we do that, Redis will deliver
|
||||
* invalidation push messages whenever the key is modified */
|
||||
for (j = 0; j < KEY_COUNT; j++) {
|
||||
reply = redisCommand(c, "SET key:%d initial:%d", j, j);
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
|
||||
|
||||
reply = redisCommand(c, "GET key:%d", j);
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STRING);
|
||||
}
|
||||
|
||||
/* Trigger invalidation messages by updating keys we just read */
|
||||
for (j = 0; j < KEY_COUNT; j++) {
|
||||
printf(" main(): SET key:%d update:%d\n", j, j);
|
||||
reply = redisCommand(c, "SET key:%d update:%d", j, j);
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
|
||||
printf(" main(): SET REPLY OK\n");
|
||||
}
|
||||
|
||||
printf("\nTotal detected invalidations: %d, expected: %d\n", invalidations, KEY_COUNT);
|
||||
|
||||
/* PING server */
|
||||
redisFree(c);
|
||||
}
|
||||
Vendored
+15
-2
@@ -4,9 +4,12 @@
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <hiredis_ssl.h>
|
||||
#include <win32.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j;
|
||||
redisSSLContext *ssl;
|
||||
redisSSLContextError ssl_error;
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
if (argc < 4) {
|
||||
@@ -19,10 +22,18 @@ int main(int argc, char **argv) {
|
||||
const char *key = argv[4];
|
||||
const char *ca = argc > 4 ? argv[5] : NULL;
|
||||
|
||||
redisInitOpenSSL();
|
||||
ssl = redisCreateSSLContext(ca, NULL, cert, key, NULL, &ssl_error);
|
||||
if (!ssl) {
|
||||
printf("SSL Context error: %s\n",
|
||||
redisSSLContextGetError(ssl_error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct timeval tv = { 1, 500000 }; // 1.5 seconds
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
|
||||
options.timeout = &tv;
|
||||
options.connect_timeout = &tv;
|
||||
c = redisConnectWithOptions(&options);
|
||||
|
||||
if (c == NULL || c->err) {
|
||||
@@ -35,7 +46,7 @@ int main(int argc, char **argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (redisSecureConnection(c, ca, cert, key, "sni") != REDIS_OK) {
|
||||
if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
|
||||
printf("Couldn't initialize SSL!\n");
|
||||
printf("Error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
@@ -93,5 +104,7 @@ int main(int argc, char **argv) {
|
||||
/* Disconnects and frees the context */
|
||||
redisFree(c);
|
||||
|
||||
redisFreeSSLContext(ssl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
+1
-1
@@ -1,8 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <win32.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j, isunix = 0;
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
|
||||
IF (NOT TARGET hiredis::hiredis)
|
||||
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake)
|
||||
ENDIF()
|
||||
|
||||
SET(hiredis_LIBRARIES hiredis::hiredis)
|
||||
SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR})
|
||||
|
||||
check_required_components(hiredis)
|
||||
|
||||
Vendored
+203
-114
@@ -44,8 +44,11 @@
|
||||
#include "async.h"
|
||||
#include "win32.h"
|
||||
|
||||
extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout);
|
||||
extern int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout);
|
||||
|
||||
static redisContextFuncs redisContextDefaultFuncs = {
|
||||
.free_privdata = NULL,
|
||||
.free_privctx = NULL,
|
||||
.async_read = redisAsyncRead,
|
||||
.async_write = redisAsyncWrite,
|
||||
.read = redisNetRead,
|
||||
@@ -74,7 +77,7 @@ static redisReplyObjectFunctions defaultFunctions = {
|
||||
|
||||
/* Create a reply object */
|
||||
static redisReply *createReplyObject(int type) {
|
||||
redisReply *r = calloc(1,sizeof(*r));
|
||||
redisReply *r = hi_calloc(1,sizeof(*r));
|
||||
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
@@ -97,20 +100,22 @@ void freeReplyObject(void *reply) {
|
||||
case REDIS_REPLY_ARRAY:
|
||||
case REDIS_REPLY_MAP:
|
||||
case REDIS_REPLY_SET:
|
||||
case REDIS_REPLY_PUSH:
|
||||
if (r->element != NULL) {
|
||||
for (j = 0; j < r->elements; j++)
|
||||
freeReplyObject(r->element[j]);
|
||||
free(r->element);
|
||||
hi_free(r->element);
|
||||
}
|
||||
break;
|
||||
case REDIS_REPLY_ERROR:
|
||||
case REDIS_REPLY_STATUS:
|
||||
case REDIS_REPLY_STRING:
|
||||
case REDIS_REPLY_DOUBLE:
|
||||
free(r->str);
|
||||
case REDIS_REPLY_VERB:
|
||||
hi_free(r->str);
|
||||
break;
|
||||
}
|
||||
free(r);
|
||||
hi_free(r);
|
||||
}
|
||||
|
||||
static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
|
||||
@@ -128,22 +133,18 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
|
||||
|
||||
/* Copy string value */
|
||||
if (task->type == REDIS_REPLY_VERB) {
|
||||
buf = malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */
|
||||
if (buf == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
}
|
||||
buf = hi_malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */
|
||||
if (buf == NULL) goto oom;
|
||||
|
||||
memcpy(r->vtype,str,3);
|
||||
r->vtype[3] = '\0';
|
||||
memcpy(buf,str+4,len-4);
|
||||
buf[len-4] = '\0';
|
||||
r->len = len-4;
|
||||
r->len = len - 4;
|
||||
} else {
|
||||
buf = malloc(len+1);
|
||||
if (buf == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
}
|
||||
buf = hi_malloc(len+1);
|
||||
if (buf == NULL) goto oom;
|
||||
|
||||
memcpy(buf,str,len);
|
||||
buf[len] = '\0';
|
||||
r->len = len;
|
||||
@@ -154,10 +155,15 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->type == REDIS_REPLY_SET ||
|
||||
parent->type == REDIS_REPLY_PUSH);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
|
||||
oom:
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *createArrayObject(const redisReadTask *task, size_t elements) {
|
||||
@@ -168,7 +174,8 @@ static void *createArrayObject(const redisReadTask *task, size_t elements) {
|
||||
return NULL;
|
||||
|
||||
if (elements > 0) {
|
||||
r->element = calloc(elements,sizeof(redisReply*));
|
||||
if (SIZE_MAX / sizeof(redisReply*) < elements) return NULL; /* Don't overflow */
|
||||
r->element = hi_calloc(elements,sizeof(redisReply*));
|
||||
if (r->element == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
@@ -181,7 +188,8 @@ static void *createArrayObject(const redisReadTask *task, size_t elements) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->type == REDIS_REPLY_SET ||
|
||||
parent->type == REDIS_REPLY_PUSH);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
@@ -200,7 +208,8 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->type == REDIS_REPLY_SET ||
|
||||
parent->type == REDIS_REPLY_PUSH);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
@@ -214,7 +223,7 @@ static void *createDoubleObject(const redisReadTask *task, double value, char *s
|
||||
return NULL;
|
||||
|
||||
r->dval = value;
|
||||
r->str = malloc(len+1);
|
||||
r->str = hi_malloc(len+1);
|
||||
if (r->str == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
@@ -249,7 +258,8 @@ static void *createNilObject(const redisReadTask *task) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->type == REDIS_REPLY_SET ||
|
||||
parent->type == REDIS_REPLY_PUSH);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
@@ -297,7 +307,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
||||
const char *c = format;
|
||||
char *cmd = NULL; /* final command */
|
||||
int pos; /* position in final command */
|
||||
sds curarg, newarg; /* current argument */
|
||||
hisds curarg, newarg; /* current argument */
|
||||
int touched = 0; /* was the current argument touched? */
|
||||
char **curargv = NULL, **newargv = NULL;
|
||||
int argc = 0;
|
||||
@@ -310,7 +320,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
||||
return -1;
|
||||
|
||||
/* Build the command string accordingly to protocol */
|
||||
curarg = sdsempty();
|
||||
curarg = hi_sdsempty();
|
||||
if (curarg == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -318,19 +328,19 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
||||
if (*c != '%' || c[1] == '\0') {
|
||||
if (*c == ' ') {
|
||||
if (touched) {
|
||||
newargv = realloc(curargv,sizeof(char*)*(argc+1));
|
||||
newargv = hi_realloc(curargv,sizeof(char*)*(argc+1));
|
||||
if (newargv == NULL) goto memory_err;
|
||||
curargv = newargv;
|
||||
curargv[argc++] = curarg;
|
||||
totlen += bulklen(sdslen(curarg));
|
||||
totlen += bulklen(hi_sdslen(curarg));
|
||||
|
||||
/* curarg is put in argv so it can be overwritten. */
|
||||
curarg = sdsempty();
|
||||
curarg = hi_sdsempty();
|
||||
if (curarg == NULL) goto memory_err;
|
||||
touched = 0;
|
||||
}
|
||||
} else {
|
||||
newarg = sdscatlen(curarg,c,1);
|
||||
newarg = hi_sdscatlen(curarg,c,1);
|
||||
if (newarg == NULL) goto memory_err;
|
||||
curarg = newarg;
|
||||
touched = 1;
|
||||
@@ -347,16 +357,16 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
||||
arg = va_arg(ap,char*);
|
||||
size = strlen(arg);
|
||||
if (size > 0)
|
||||
newarg = sdscatlen(curarg,arg,size);
|
||||
newarg = hi_sdscatlen(curarg,arg,size);
|
||||
break;
|
||||
case 'b':
|
||||
arg = va_arg(ap,char*);
|
||||
size = va_arg(ap,size_t);
|
||||
if (size > 0)
|
||||
newarg = sdscatlen(curarg,arg,size);
|
||||
newarg = hi_sdscatlen(curarg,arg,size);
|
||||
break;
|
||||
case '%':
|
||||
newarg = sdscat(curarg,"%");
|
||||
newarg = hi_sdscat(curarg,"%");
|
||||
break;
|
||||
default:
|
||||
/* Try to detect printf format */
|
||||
@@ -444,7 +454,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
||||
if (_l < sizeof(_format)-2) {
|
||||
memcpy(_format,c,_l);
|
||||
_format[_l] = '\0';
|
||||
newarg = sdscatvprintf(curarg,_format,_cpy);
|
||||
newarg = hi_sdscatvprintf(curarg,_format,_cpy);
|
||||
|
||||
/* Update current position (note: outer blocks
|
||||
* increment c twice so compensate here) */
|
||||
@@ -467,13 +477,13 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
||||
|
||||
/* Add the last argument if needed */
|
||||
if (touched) {
|
||||
newargv = realloc(curargv,sizeof(char*)*(argc+1));
|
||||
newargv = hi_realloc(curargv,sizeof(char*)*(argc+1));
|
||||
if (newargv == NULL) goto memory_err;
|
||||
curargv = newargv;
|
||||
curargv[argc++] = curarg;
|
||||
totlen += bulklen(sdslen(curarg));
|
||||
totlen += bulklen(hi_sdslen(curarg));
|
||||
} else {
|
||||
sdsfree(curarg);
|
||||
hi_sdsfree(curarg);
|
||||
}
|
||||
|
||||
/* Clear curarg because it was put in curargv or was free'd. */
|
||||
@@ -483,22 +493,22 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
||||
totlen += 1+countDigits(argc)+2;
|
||||
|
||||
/* Build the command at protocol level */
|
||||
cmd = malloc(totlen+1);
|
||||
cmd = hi_malloc(totlen+1);
|
||||
if (cmd == NULL) goto memory_err;
|
||||
|
||||
pos = sprintf(cmd,"*%d\r\n",argc);
|
||||
for (j = 0; j < argc; j++) {
|
||||
pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
|
||||
memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
|
||||
pos += sdslen(curargv[j]);
|
||||
sdsfree(curargv[j]);
|
||||
pos += sprintf(cmd+pos,"$%zu\r\n",hi_sdslen(curargv[j]));
|
||||
memcpy(cmd+pos,curargv[j],hi_sdslen(curargv[j]));
|
||||
pos += hi_sdslen(curargv[j]);
|
||||
hi_sdsfree(curargv[j]);
|
||||
cmd[pos++] = '\r';
|
||||
cmd[pos++] = '\n';
|
||||
}
|
||||
assert(pos == totlen);
|
||||
cmd[pos] = '\0';
|
||||
|
||||
free(curargv);
|
||||
hi_free(curargv);
|
||||
*target = cmd;
|
||||
return totlen;
|
||||
|
||||
@@ -513,12 +523,12 @@ memory_err:
|
||||
cleanup:
|
||||
if (curargv) {
|
||||
while(argc--)
|
||||
sdsfree(curargv[argc]);
|
||||
free(curargv);
|
||||
hi_sdsfree(curargv[argc]);
|
||||
hi_free(curargv);
|
||||
}
|
||||
|
||||
sdsfree(curarg);
|
||||
free(cmd);
|
||||
hi_sdsfree(curarg);
|
||||
hi_free(cmd);
|
||||
|
||||
return error_type;
|
||||
}
|
||||
@@ -550,16 +560,16 @@ int redisFormatCommand(char **target, const char *format, ...) {
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Format a command according to the Redis protocol using an sds string and
|
||||
* sdscatfmt for the processing of arguments. This function takes the
|
||||
/* Format a command according to the Redis protocol using an hisds string and
|
||||
* hi_sdscatfmt for the processing of arguments. This function takes the
|
||||
* number of arguments, an array with arguments and an array with their
|
||||
* lengths. If the latter is set to NULL, strlen will be used to compute the
|
||||
* argument lengths.
|
||||
*/
|
||||
int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
|
||||
int redisFormatSdsCommandArgv(hisds *target, int argc, const char **argv,
|
||||
const size_t *argvlen)
|
||||
{
|
||||
sds cmd;
|
||||
hisds cmd, aux;
|
||||
unsigned long long totlen;
|
||||
int j;
|
||||
size_t len;
|
||||
@@ -576,32 +586,36 @@ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
|
||||
}
|
||||
|
||||
/* Use an SDS string for command construction */
|
||||
cmd = sdsempty();
|
||||
cmd = hi_sdsempty();
|
||||
if (cmd == NULL)
|
||||
return -1;
|
||||
|
||||
/* We already know how much storage we need */
|
||||
cmd = sdsMakeRoomFor(cmd, totlen);
|
||||
if (cmd == NULL)
|
||||
aux = hi_sdsMakeRoomFor(cmd, totlen);
|
||||
if (aux == NULL) {
|
||||
hi_sdsfree(cmd);
|
||||
return -1;
|
||||
|
||||
/* Construct command */
|
||||
cmd = sdscatfmt(cmd, "*%i\r\n", argc);
|
||||
for (j=0; j < argc; j++) {
|
||||
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
||||
cmd = sdscatfmt(cmd, "$%u\r\n", len);
|
||||
cmd = sdscatlen(cmd, argv[j], len);
|
||||
cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
|
||||
}
|
||||
|
||||
assert(sdslen(cmd)==totlen);
|
||||
cmd = aux;
|
||||
|
||||
/* Construct command */
|
||||
cmd = hi_sdscatfmt(cmd, "*%i\r\n", argc);
|
||||
for (j=0; j < argc; j++) {
|
||||
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
||||
cmd = hi_sdscatfmt(cmd, "$%u\r\n", len);
|
||||
cmd = hi_sdscatlen(cmd, argv[j], len);
|
||||
cmd = hi_sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
|
||||
}
|
||||
|
||||
assert(hi_sdslen(cmd)==totlen);
|
||||
|
||||
*target = cmd;
|
||||
return totlen;
|
||||
}
|
||||
|
||||
void redisFreeSdsCommand(sds cmd) {
|
||||
sdsfree(cmd);
|
||||
void redisFreeSdsCommand(hisds cmd) {
|
||||
hi_sdsfree(cmd);
|
||||
}
|
||||
|
||||
/* Format a command according to the Redis protocol. This function takes the
|
||||
@@ -627,7 +641,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
|
||||
}
|
||||
|
||||
/* Build the command at protocol level */
|
||||
cmd = malloc(totlen+1);
|
||||
cmd = hi_malloc(totlen+1);
|
||||
if (cmd == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -648,7 +662,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
|
||||
}
|
||||
|
||||
void redisFreeCommand(char *cmd) {
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
}
|
||||
|
||||
void __redisSetError(redisContext *c, int type, const char *str) {
|
||||
@@ -671,15 +685,21 @@ redisReader *redisReaderCreate(void) {
|
||||
return redisReaderCreateWithFunctions(&defaultFunctions);
|
||||
}
|
||||
|
||||
static redisContext *redisContextInit(const redisOptions *options) {
|
||||
static void redisPushAutoFree(void *privdata, void *reply) {
|
||||
(void)privdata;
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
static redisContext *redisContextInit(void) {
|
||||
redisContext *c;
|
||||
|
||||
c = calloc(1, sizeof(*c));
|
||||
c = hi_calloc(1, sizeof(*c));
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->funcs = &redisContextDefaultFuncs;
|
||||
c->obuf = sdsempty();
|
||||
|
||||
c->obuf = hi_sdsempty();
|
||||
c->reader = redisReaderCreate();
|
||||
c->fd = REDIS_INVALID_FD;
|
||||
|
||||
@@ -687,7 +707,7 @@ static redisContext *redisContextInit(const redisOptions *options) {
|
||||
redisFree(c);
|
||||
return NULL;
|
||||
}
|
||||
(void)options; /* options are used in other functions */
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -696,18 +716,23 @@ void redisFree(redisContext *c) {
|
||||
return;
|
||||
redisNetClose(c);
|
||||
|
||||
sdsfree(c->obuf);
|
||||
hi_sdsfree(c->obuf);
|
||||
redisReaderFree(c->reader);
|
||||
free(c->tcp.host);
|
||||
free(c->tcp.source_addr);
|
||||
free(c->unix_sock.path);
|
||||
free(c->timeout);
|
||||
free(c->saddr);
|
||||
if (c->funcs->free_privdata) {
|
||||
c->funcs->free_privdata(c->privdata);
|
||||
}
|
||||
hi_free(c->tcp.host);
|
||||
hi_free(c->tcp.source_addr);
|
||||
hi_free(c->unix_sock.path);
|
||||
hi_free(c->connect_timeout);
|
||||
hi_free(c->command_timeout);
|
||||
hi_free(c->saddr);
|
||||
|
||||
if (c->privdata && c->free_privdata)
|
||||
c->free_privdata(c->privdata);
|
||||
|
||||
if (c->funcs->free_privctx)
|
||||
c->funcs->free_privctx(c->privctx);
|
||||
|
||||
memset(c, 0xff, sizeof(*c));
|
||||
free(c);
|
||||
hi_free(c);
|
||||
}
|
||||
|
||||
redisFD redisFreeKeepFd(redisContext *c) {
|
||||
@@ -721,35 +746,46 @@ int redisReconnect(redisContext *c) {
|
||||
c->err = 0;
|
||||
memset(c->errstr, '\0', strlen(c->errstr));
|
||||
|
||||
if (c->privdata && c->funcs->free_privdata) {
|
||||
c->funcs->free_privdata(c->privdata);
|
||||
c->privdata = NULL;
|
||||
if (c->privctx && c->funcs->free_privctx) {
|
||||
c->funcs->free_privctx(c->privctx);
|
||||
c->privctx = NULL;
|
||||
}
|
||||
|
||||
redisNetClose(c);
|
||||
|
||||
sdsfree(c->obuf);
|
||||
hi_sdsfree(c->obuf);
|
||||
redisReaderFree(c->reader);
|
||||
|
||||
c->obuf = sdsempty();
|
||||
c->obuf = hi_sdsempty();
|
||||
c->reader = redisReaderCreate();
|
||||
|
||||
if (c->obuf == NULL || c->reader == NULL) {
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int ret = REDIS_ERR;
|
||||
if (c->connection_type == REDIS_CONN_TCP) {
|
||||
return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
|
||||
c->timeout, c->tcp.source_addr);
|
||||
ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
|
||||
c->connect_timeout, c->tcp.source_addr);
|
||||
} else if (c->connection_type == REDIS_CONN_UNIX) {
|
||||
return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
|
||||
ret = redisContextConnectUnix(c, c->unix_sock.path, c->connect_timeout);
|
||||
} else {
|
||||
/* Something bad happened here and shouldn't have. There isn't
|
||||
enough information in the context to reconnect. */
|
||||
__redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
|
||||
ret = REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_ERR;
|
||||
if (c->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
||||
redisContextSetTimeout(c, *c->command_timeout);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
redisContext *redisConnectWithOptions(const redisOptions *options) {
|
||||
redisContext *c = redisContextInit(options);
|
||||
redisContext *c = redisContextInit();
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -760,16 +796,32 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
|
||||
c->flags |= REDIS_REUSEADDR;
|
||||
}
|
||||
if (options->options & REDIS_OPT_NOAUTOFREE) {
|
||||
c->flags |= REDIS_NO_AUTO_FREE;
|
||||
c->flags |= REDIS_NO_AUTO_FREE;
|
||||
}
|
||||
|
||||
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject
|
||||
* as a default unless specifically flagged that we don't want one. */
|
||||
if (options->push_cb != NULL)
|
||||
redisSetPushCallback(c, options->push_cb);
|
||||
else if (!(options->options & REDIS_OPT_NO_PUSH_AUTOFREE))
|
||||
redisSetPushCallback(c, redisPushAutoFree);
|
||||
|
||||
c->privdata = options->privdata;
|
||||
c->free_privdata = options->free_privdata;
|
||||
|
||||
if (redisContextUpdateConnectTimeout(c, options->connect_timeout) != REDIS_OK ||
|
||||
redisContextUpdateCommandTimeout(c, options->command_timeout) != REDIS_OK) {
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
return c;
|
||||
}
|
||||
|
||||
if (options->type == REDIS_CONN_TCP) {
|
||||
redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
|
||||
options->endpoint.tcp.port, options->timeout,
|
||||
options->endpoint.tcp.port, options->connect_timeout,
|
||||
options->endpoint.tcp.source_addr);
|
||||
} else if (options->type == REDIS_CONN_UNIX) {
|
||||
redisContextConnectUnix(c, options->endpoint.unix_socket,
|
||||
options->timeout);
|
||||
options->connect_timeout);
|
||||
} else if (options->type == REDIS_CONN_USERFD) {
|
||||
c->fd = options->endpoint.fd;
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
@@ -777,9 +829,11 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
|
||||
// Unknown type - FIXME - FREE
|
||||
return NULL;
|
||||
}
|
||||
if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
||||
redisContextSetTimeout(c, *options->timeout);
|
||||
|
||||
if (options->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
||||
redisContextSetTimeout(c, *options->command_timeout);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -795,7 +849,7 @@ redisContext *redisConnect(const char *ip, int port) {
|
||||
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.timeout = &tv;
|
||||
options.connect_timeout = &tv;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
@@ -833,7 +887,7 @@ redisContext *redisConnectUnix(const char *path) {
|
||||
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_UNIX(&options, path);
|
||||
options.timeout = &tv;
|
||||
options.connect_timeout = &tv;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
@@ -865,6 +919,13 @@ int redisEnableKeepAlive(redisContext *c) {
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
/* Set a user provided RESP3 PUSH handler and return any old one set. */
|
||||
redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) {
|
||||
redisPushFn *old = c->push_cb;
|
||||
c->push_cb = fn;
|
||||
return old;
|
||||
}
|
||||
|
||||
/* Use this function to handle a read event on the descriptor. It will try
|
||||
* and read some bytes from the socket and feed them to the reply parser.
|
||||
*
|
||||
@@ -906,21 +967,27 @@ int redisBufferWrite(redisContext *c, int *done) {
|
||||
if (c->err)
|
||||
return REDIS_ERR;
|
||||
|
||||
if (sdslen(c->obuf) > 0) {
|
||||
int nwritten = c->funcs->write(c);
|
||||
if (hi_sdslen(c->obuf) > 0) {
|
||||
ssize_t nwritten = c->funcs->write(c);
|
||||
if (nwritten < 0) {
|
||||
return REDIS_ERR;
|
||||
} else if (nwritten > 0) {
|
||||
if (nwritten == (signed)sdslen(c->obuf)) {
|
||||
sdsfree(c->obuf);
|
||||
c->obuf = sdsempty();
|
||||
if (nwritten == (ssize_t)hi_sdslen(c->obuf)) {
|
||||
hi_sdsfree(c->obuf);
|
||||
c->obuf = hi_sdsempty();
|
||||
if (c->obuf == NULL)
|
||||
goto oom;
|
||||
} else {
|
||||
sdsrange(c->obuf,nwritten,-1);
|
||||
if (hi_sdsrange(c->obuf,nwritten,-1) < 0) goto oom;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (done != NULL) *done = (sdslen(c->obuf) == 0);
|
||||
if (done != NULL) *done = (hi_sdslen(c->obuf) == 0);
|
||||
return REDIS_OK;
|
||||
|
||||
oom:
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* Internal helper function to try and get a reply from the reader,
|
||||
@@ -930,9 +997,21 @@ int redisGetReplyFromReader(redisContext *c, void **reply) {
|
||||
__redisSetError(c,c->reader->err,c->reader->errstr);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
/* Internal helper that returns 1 if the reply was a RESP3 PUSH
|
||||
* message and we handled it with a user-provided callback. */
|
||||
static int redisHandledPushReply(redisContext *c, void *reply) {
|
||||
if (reply && c->push_cb && redisIsPushReply(reply)) {
|
||||
c->push_cb(c->privdata, reply);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redisGetReply(redisContext *c, void **reply) {
|
||||
int wdone = 0;
|
||||
void *aux = NULL;
|
||||
@@ -953,13 +1032,23 @@ int redisGetReply(redisContext *c, void **reply) {
|
||||
do {
|
||||
if (redisBufferRead(c) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* We loop here in case the user has specified a RESP3
|
||||
* PUSH handler (e.g. for client tracking). */
|
||||
do {
|
||||
if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
} while (redisHandledPushReply(c, aux));
|
||||
} while (aux == NULL);
|
||||
}
|
||||
|
||||
/* Set reply object */
|
||||
if (reply != NULL) *reply = aux;
|
||||
/* Set reply or free it if we were passed NULL */
|
||||
if (reply != NULL) {
|
||||
*reply = aux;
|
||||
} else {
|
||||
freeReplyObject(aux);
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
@@ -971,9 +1060,9 @@ int redisGetReply(redisContext *c, void **reply) {
|
||||
* the reply (or replies in pub/sub).
|
||||
*/
|
||||
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
|
||||
sds newbuf;
|
||||
hisds newbuf;
|
||||
|
||||
newbuf = sdscatlen(c->obuf,cmd,len);
|
||||
newbuf = hi_sdscatlen(c->obuf,cmd,len);
|
||||
if (newbuf == NULL) {
|
||||
__redisSetError(c,REDIS_ERR_OOM,"Out of memory");
|
||||
return REDIS_ERR;
|
||||
@@ -1006,11 +1095,11 @@ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
|
||||
}
|
||||
|
||||
if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
@@ -1025,7 +1114,7 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
|
||||
}
|
||||
|
||||
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
|
||||
sds cmd;
|
||||
hisds cmd;
|
||||
int len;
|
||||
|
||||
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
|
||||
@@ -1035,11 +1124,11 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s
|
||||
}
|
||||
|
||||
if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
|
||||
sdsfree(cmd);
|
||||
hi_sdsfree(cmd);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
sdsfree(cmd);
|
||||
hi_sdsfree(cmd);
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+53
-16
@@ -39,14 +39,16 @@
|
||||
#include <sys/time.h> /* for struct timeval */
|
||||
#else
|
||||
struct timeval; /* forward declaration */
|
||||
typedef long long ssize_t;
|
||||
#endif
|
||||
#include <stdint.h> /* uintXX_t, etc */
|
||||
#include "sds.h" /* for sds */
|
||||
#include "sds.h" /* for hisds */
|
||||
#include "alloc.h" /* for allocation wrappers */
|
||||
|
||||
#define HIREDIS_MAJOR 0
|
||||
#define HIREDIS_MINOR 14
|
||||
#define HIREDIS_MAJOR 1
|
||||
#define HIREDIS_MINOR 0
|
||||
#define HIREDIS_PATCH 0
|
||||
#define HIREDIS_SONAME 0.14
|
||||
#define HIREDIS_SONAME 1.0.0
|
||||
|
||||
/* Connection type can be blocking or non-blocking and is set in the
|
||||
* least significant bit of the flags field in redisContext. */
|
||||
@@ -90,6 +92,15 @@ struct timeval; /* forward declaration */
|
||||
* SO_REUSEADDR is being used. */
|
||||
#define REDIS_CONNECT_RETRIES 10
|
||||
|
||||
/* Forward declarations for structs defined elsewhere */
|
||||
struct redisAsyncContext;
|
||||
struct redisContext;
|
||||
|
||||
/* RESP3 push helpers and callback prototypes */
|
||||
#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH)
|
||||
typedef void (redisPushFn)(void *, void *);
|
||||
typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -101,7 +112,7 @@ typedef struct redisReply {
|
||||
double dval; /* The double when type is REDIS_REPLY_DOUBLE */
|
||||
size_t len; /* Length of string */
|
||||
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
|
||||
and REDIS_REPLY_DOUBLE (in additionl to dval). */
|
||||
REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */
|
||||
char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null
|
||||
terminated 3 character content type, such as "txt". */
|
||||
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
|
||||
@@ -117,9 +128,9 @@ void freeReplyObject(void *reply);
|
||||
int redisvFormatCommand(char **target, const char *format, va_list ap);
|
||||
int redisFormatCommand(char **target, const char *format, ...);
|
||||
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
|
||||
int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
|
||||
int redisFormatSdsCommandArgv(hisds *target, int argc, const char ** argv, const size_t *argvlen);
|
||||
void redisFreeCommand(char *cmd);
|
||||
void redisFreeSdsCommand(sds cmd);
|
||||
void redisFreeSdsCommand(hisds cmd);
|
||||
|
||||
enum redisConnectionType {
|
||||
REDIS_CONN_TCP,
|
||||
@@ -138,6 +149,9 @@ struct redisSsl;
|
||||
*/
|
||||
#define REDIS_OPT_NOAUTOFREE 0x04
|
||||
|
||||
/* Don't automatically intercept and free RESP3 PUSH replies. */
|
||||
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
|
||||
|
||||
/* In Unix systems a file descriptor is a regular signed int, with -1
|
||||
* representing an invalid descriptor. In Windows it is a SOCKET
|
||||
* (32- or 64-bit unsigned integer depending on the architecture), where
|
||||
@@ -162,8 +176,11 @@ typedef struct {
|
||||
int type;
|
||||
/* bit field of REDIS_OPT_xxx */
|
||||
int options;
|
||||
/* timeout value. if NULL, no timeout is used */
|
||||
const struct timeval *timeout;
|
||||
/* timeout value for connect operation. If NULL, no timeout is used */
|
||||
const struct timeval *connect_timeout;
|
||||
/* timeout value for commands. If NULL, no timeout is used. This can be
|
||||
* updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */
|
||||
const struct timeval *command_timeout;
|
||||
union {
|
||||
/** use this field for tcp/ip connections */
|
||||
struct {
|
||||
@@ -178,6 +195,14 @@ typedef struct {
|
||||
* file descriptor */
|
||||
redisFD fd;
|
||||
} endpoint;
|
||||
|
||||
/* Optional user defined data/destructor */
|
||||
void *privdata;
|
||||
void (*free_privdata)(void *);
|
||||
|
||||
/* A user defined PUSH message callback */
|
||||
redisPushFn *push_cb;
|
||||
redisAsyncPushFn *async_push_cb;
|
||||
} redisOptions;
|
||||
|
||||
/**
|
||||
@@ -192,15 +217,16 @@ typedef struct {
|
||||
(opts)->type = REDIS_CONN_UNIX; \
|
||||
(opts)->endpoint.unix_socket = path;
|
||||
|
||||
struct redisAsyncContext;
|
||||
struct redisContext;
|
||||
#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \
|
||||
(opts)->privdata = data; \
|
||||
(opts)->free_privdata = dtor; \
|
||||
|
||||
typedef struct redisContextFuncs {
|
||||
void (*free_privdata)(void *);
|
||||
void (*free_privctx)(void *);
|
||||
void (*async_read)(struct redisAsyncContext *);
|
||||
void (*async_write)(struct redisAsyncContext *);
|
||||
int (*read)(struct redisContext *, char *, size_t);
|
||||
int (*write)(struct redisContext *);
|
||||
ssize_t (*read)(struct redisContext *, char *, size_t);
|
||||
ssize_t (*write)(struct redisContext *);
|
||||
} redisContextFuncs;
|
||||
|
||||
/* Context for a connection to Redis */
|
||||
@@ -215,7 +241,8 @@ typedef struct redisContext {
|
||||
redisReader *reader; /* Protocol reader */
|
||||
|
||||
enum redisConnectionType connection_type;
|
||||
struct timeval *timeout;
|
||||
struct timeval *connect_timeout;
|
||||
struct timeval *command_timeout;
|
||||
|
||||
struct {
|
||||
char *host;
|
||||
@@ -231,8 +258,17 @@ typedef struct redisContext {
|
||||
struct sockadr *saddr;
|
||||
size_t addrlen;
|
||||
|
||||
/* Additional private data for hiredis addons such as SSL */
|
||||
/* Optional data and corresponding destructor users can use to provide
|
||||
* context to a given redisContext. Not used by hiredis. */
|
||||
void *privdata;
|
||||
void (*free_privdata)(void *);
|
||||
|
||||
/* Internal context pointer presently used by hiredis to manage
|
||||
* SSL connections. */
|
||||
void *privctx;
|
||||
|
||||
/* An optional RESP3 PUSH handler */
|
||||
redisPushFn *push_cb;
|
||||
} redisContext;
|
||||
|
||||
redisContext *redisConnectWithOptions(const redisOptions *options);
|
||||
@@ -259,6 +295,7 @@ redisContext *redisConnectFd(redisFD fd);
|
||||
*/
|
||||
int redisReconnect(redisContext *c);
|
||||
|
||||
redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn);
|
||||
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
||||
int redisEnableKeepAlive(redisContext *c);
|
||||
void redisFree(redisContext *c);
|
||||
|
||||
Vendored
+2
-1
@@ -1,6 +1,7 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
install_libdir=@CMAKE_INSTALL_LIBDIR@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
libdir=${exec_prefix}/${install_libdir}
|
||||
includedir=${prefix}/include
|
||||
pkgincludedir=${includedir}/hiredis
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set_and_check(hiredis_ssl_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
|
||||
IF (NOT TARGET hiredis::hiredis_ssl)
|
||||
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis_ssl-targets.cmake)
|
||||
ENDIF()
|
||||
|
||||
SET(hiredis_ssl_LIBRARIES hiredis::hiredis_ssl)
|
||||
SET(hiredis_ssl_INCLUDE_DIRS ${hiredis_ssl_INCLUDEDIR})
|
||||
|
||||
check_required_components(hiredis_ssl)
|
||||
|
||||
Vendored
+80
-6
@@ -32,22 +32,96 @@
|
||||
#ifndef __HIREDIS_SSL_H
|
||||
#define __HIREDIS_SSL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is the underlying struct for SSL in ssl.h, which is not included to
|
||||
* keep build dependencies short here.
|
||||
*/
|
||||
struct ssl_st;
|
||||
|
||||
/**
|
||||
* Secure the connection using SSL. This should be done before any command is
|
||||
* executed on the connection.
|
||||
/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly
|
||||
* calling OpenSSL.
|
||||
*/
|
||||
int redisSecureConnection(redisContext *c, const char *capath, const char *certpath,
|
||||
const char *keypath, const char *servername);
|
||||
typedef struct redisSSLContext redisSSLContext;
|
||||
|
||||
/**
|
||||
* Initiate SSL/TLS negotiation on a provided context.
|
||||
* Initialization errors that redisCreateSSLContext() may return.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
REDIS_SSL_CTX_NONE = 0, /* No Error */
|
||||
REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */
|
||||
REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */
|
||||
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */
|
||||
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */
|
||||
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED /* Failed to load private key */
|
||||
} redisSSLContextError;
|
||||
|
||||
/**
|
||||
* Return the error message corresponding with the specified error code.
|
||||
*/
|
||||
|
||||
const char *redisSSLContextGetError(redisSSLContextError error);
|
||||
|
||||
/**
|
||||
* Helper function to initialize the OpenSSL library.
|
||||
*
|
||||
* OpenSSL requires one-time initialization before it can be used. Callers should
|
||||
* call this function only once, and only if OpenSSL is not directly initialized
|
||||
* elsewhere.
|
||||
*/
|
||||
int redisInitOpenSSL(void);
|
||||
|
||||
/**
|
||||
* Helper function to initialize an OpenSSL context that can be used
|
||||
* to initiate SSL connections.
|
||||
*
|
||||
* cacert_filename is an optional name of a CA certificate/bundle file to load
|
||||
* and use for validation.
|
||||
*
|
||||
* capath is an optional directory path where trusted CA certificate files are
|
||||
* stored in an OpenSSL-compatible structure.
|
||||
*
|
||||
* cert_filename and private_key_filename are optional names of a client side
|
||||
* certificate and private key files to use for authentication. They need to
|
||||
* be both specified or omitted.
|
||||
*
|
||||
* server_name is an optional and will be used as a server name indication
|
||||
* (SNI) TLS extension.
|
||||
*
|
||||
* If error is non-null, it will be populated in case the context creation fails
|
||||
* (returning a NULL).
|
||||
*/
|
||||
|
||||
redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath,
|
||||
const char *cert_filename, const char *private_key_filename,
|
||||
const char *server_name, redisSSLContextError *error);
|
||||
|
||||
/**
|
||||
* Free a previously created OpenSSL context.
|
||||
*/
|
||||
void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx);
|
||||
|
||||
/**
|
||||
* Initiate SSL on an existing redisContext.
|
||||
*
|
||||
* This is similar to redisInitiateSSL() but does not require the caller
|
||||
* to directly interact with OpenSSL, and instead uses a redisSSLContext
|
||||
* previously created using redisCreateSSLContext().
|
||||
*/
|
||||
|
||||
int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx);
|
||||
|
||||
/**
|
||||
* Initiate SSL/TLS negotiation on a provided OpenSSL SSL object.
|
||||
*/
|
||||
|
||||
int redisInitiateSSL(redisContext *c, struct ssl_st *ssl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HIREDIS_SSL_H */
|
||||
Vendored
+80
-39
@@ -57,8 +57,8 @@ void redisNetClose(redisContext *c) {
|
||||
}
|
||||
}
|
||||
|
||||
int redisNetRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
int nread = recv(c->fd, buf, bufcap, 0);
|
||||
ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
ssize_t nread = recv(c->fd, buf, bufcap, 0);
|
||||
if (nread == -1) {
|
||||
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
@@ -79,8 +79,8 @@ int redisNetRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
}
|
||||
}
|
||||
|
||||
int redisNetWrite(redisContext *c) {
|
||||
int nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0);
|
||||
ssize_t redisNetWrite(redisContext *c) {
|
||||
ssize_t nwritten = send(c->fd, c->obuf, hi_sdslen(c->obuf), 0);
|
||||
if (nwritten < 0) {
|
||||
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
@@ -203,7 +203,7 @@ int redisKeepAlive(redisContext *c, int interval) {
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int redisSetTcpNoDelay(redisContext *c) {
|
||||
int redisSetTcpNoDelay(redisContext *c) {
|
||||
int yes = 1;
|
||||
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
|
||||
@@ -217,7 +217,7 @@ static int redisSetTcpNoDelay(redisContext *c) {
|
||||
|
||||
static int redisContextTimeoutMsec(redisContext *c, long *result)
|
||||
{
|
||||
const struct timeval *timeout = c->timeout;
|
||||
const struct timeval *timeout = c->connect_timeout;
|
||||
long msec = -1;
|
||||
|
||||
/* Only use timeout when not NULL. */
|
||||
@@ -316,11 +316,7 @@ int redisCheckSocketError(redisContext *c) {
|
||||
int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
||||
const void *to_ptr = &tv;
|
||||
size_t to_sz = sizeof(tv);
|
||||
#ifdef _WIN32
|
||||
DWORD timeout_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
to_ptr = &timeout_msec;
|
||||
to_sz = sizeof(timeout_msec);
|
||||
#endif
|
||||
|
||||
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
|
||||
return REDIS_ERR;
|
||||
@@ -332,6 +328,38 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout) {
|
||||
/* Same timeval struct, short circuit */
|
||||
if (c->connect_timeout == timeout)
|
||||
return REDIS_OK;
|
||||
|
||||
/* Allocate context timeval if we need to */
|
||||
if (c->connect_timeout == NULL) {
|
||||
c->connect_timeout = hi_malloc(sizeof(*c->connect_timeout));
|
||||
if (c->connect_timeout == NULL)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
memcpy(c->connect_timeout, timeout, sizeof(*c->connect_timeout));
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout) {
|
||||
/* Same timeval struct, short circuit */
|
||||
if (c->command_timeout == timeout)
|
||||
return REDIS_OK;
|
||||
|
||||
/* Allocate context timeval if we need to */
|
||||
if (c->command_timeout == NULL) {
|
||||
c->command_timeout = hi_malloc(sizeof(*c->command_timeout));
|
||||
if (c->command_timeout == NULL)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
memcpy(c->command_timeout, timeout, sizeof(*c->command_timeout));
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
const struct timeval *timeout,
|
||||
const char *source_addr) {
|
||||
@@ -356,21 +384,19 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
* This is a bit ugly, but atleast it works and doesn't leak memory.
|
||||
**/
|
||||
if (c->tcp.host != addr) {
|
||||
free(c->tcp.host);
|
||||
hi_free(c->tcp.host);
|
||||
|
||||
c->tcp.host = strdup(addr);
|
||||
c->tcp.host = hi_strdup(addr);
|
||||
if (c->tcp.host == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
if (c->timeout != timeout) {
|
||||
if (c->timeout == NULL)
|
||||
c->timeout = malloc(sizeof(struct timeval));
|
||||
|
||||
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
||||
}
|
||||
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
|
||||
goto oom;
|
||||
} else {
|
||||
free(c->timeout);
|
||||
c->timeout = NULL;
|
||||
hi_free(c->connect_timeout);
|
||||
c->connect_timeout = NULL;
|
||||
}
|
||||
|
||||
if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
|
||||
@@ -379,11 +405,11 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
}
|
||||
|
||||
if (source_addr == NULL) {
|
||||
free(c->tcp.source_addr);
|
||||
hi_free(c->tcp.source_addr);
|
||||
c->tcp.source_addr = NULL;
|
||||
} else if (c->tcp.source_addr != source_addr) {
|
||||
free(c->tcp.source_addr);
|
||||
c->tcp.source_addr = strdup(source_addr);
|
||||
hi_free(c->tcp.source_addr);
|
||||
c->tcp.source_addr = hi_strdup(source_addr);
|
||||
}
|
||||
|
||||
snprintf(_port, 6, "%d", port);
|
||||
@@ -446,8 +472,11 @@ addrretry:
|
||||
}
|
||||
|
||||
/* For repeat connection */
|
||||
free(c->saddr);
|
||||
c->saddr = malloc(p->ai_addrlen);
|
||||
hi_free(c->saddr);
|
||||
c->saddr = hi_malloc(p->ai_addrlen);
|
||||
if (c->saddr == NULL)
|
||||
goto oom;
|
||||
|
||||
memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
|
||||
c->addrlen = p->ai_addrlen;
|
||||
|
||||
@@ -474,12 +503,12 @@ addrretry:
|
||||
wait_for_ready:
|
||||
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
|
||||
goto error;
|
||||
if (redisSetTcpNoDelay(c) != REDIS_OK)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
|
||||
goto error;
|
||||
if (redisSetTcpNoDelay(c) != REDIS_OK)
|
||||
goto error;
|
||||
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
rv = REDIS_OK;
|
||||
@@ -492,6 +521,8 @@ addrretry:
|
||||
goto error;
|
||||
}
|
||||
|
||||
oom:
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
error:
|
||||
rv = REDIS_ERR;
|
||||
end:
|
||||
@@ -525,25 +556,32 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
|
||||
return REDIS_ERR;
|
||||
|
||||
c->connection_type = REDIS_CONN_UNIX;
|
||||
if (c->unix_sock.path != path)
|
||||
c->unix_sock.path = strdup(path);
|
||||
if (c->unix_sock.path != path) {
|
||||
hi_free(c->unix_sock.path);
|
||||
|
||||
c->unix_sock.path = hi_strdup(path);
|
||||
if (c->unix_sock.path == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
if (c->timeout != timeout) {
|
||||
if (c->timeout == NULL)
|
||||
c->timeout = malloc(sizeof(struct timeval));
|
||||
|
||||
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
||||
}
|
||||
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
|
||||
goto oom;
|
||||
} else {
|
||||
free(c->timeout);
|
||||
c->timeout = NULL;
|
||||
hi_free(c->connect_timeout);
|
||||
c->connect_timeout = NULL;
|
||||
}
|
||||
|
||||
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
|
||||
return REDIS_ERR;
|
||||
|
||||
sa = (struct sockaddr_un*)(c->saddr = malloc(sizeof(struct sockaddr_un)));
|
||||
/* Don't leak sockaddr if we're reconnecting */
|
||||
if (c->saddr) hi_free(c->saddr);
|
||||
|
||||
sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un)));
|
||||
if (sa == NULL)
|
||||
goto oom;
|
||||
|
||||
c->addrlen = sizeof(struct sockaddr_un);
|
||||
sa->sun_family = AF_UNIX;
|
||||
strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1);
|
||||
@@ -568,4 +606,7 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
|
||||
errno = EPROTONOSUPPORT;
|
||||
return REDIS_ERR;
|
||||
#endif /* _WIN32 */
|
||||
oom:
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
Vendored
+4
-2
@@ -38,8 +38,8 @@
|
||||
#include "hiredis.h"
|
||||
|
||||
void redisNetClose(redisContext *c);
|
||||
int redisNetRead(redisContext *c, char *buf, size_t bufcap);
|
||||
int redisNetWrite(redisContext *c);
|
||||
ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap);
|
||||
ssize_t redisNetWrite(redisContext *c);
|
||||
|
||||
int redisCheckSocketError(redisContext *c);
|
||||
int redisContextSetTimeout(redisContext *c, const struct timeval tv);
|
||||
@@ -51,4 +51,6 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
|
||||
int redisKeepAlive(redisContext *c, int interval);
|
||||
int redisCheckConnectDone(redisContext *c, int *completed);
|
||||
|
||||
int redisSetTcpNoDelay(redisContext *c);
|
||||
|
||||
#endif
|
||||
Vendored
+108
-50
@@ -42,10 +42,14 @@
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "alloc.h"
|
||||
#include "read.h"
|
||||
#include "sds.h"
|
||||
#include "win32.h"
|
||||
|
||||
/* Initial size of our nested reply stack and how much we grow it when needd */
|
||||
#define REDIS_READER_STACK_SIZE 9
|
||||
|
||||
static void __redisReaderSetError(redisReader *r, int type, const char *str) {
|
||||
size_t len;
|
||||
|
||||
@@ -55,7 +59,7 @@ static void __redisReaderSetError(redisReader *r, int type, const char *str) {
|
||||
}
|
||||
|
||||
/* Clear input buffer on errors. */
|
||||
sdsfree(r->buf);
|
||||
hi_sdsfree(r->buf);
|
||||
r->buf = NULL;
|
||||
r->pos = r->len = 0;
|
||||
|
||||
@@ -243,11 +247,12 @@ static void moveToNextTask(redisReader *r) {
|
||||
return;
|
||||
}
|
||||
|
||||
cur = &(r->rstack[r->ridx]);
|
||||
prv = &(r->rstack[r->ridx-1]);
|
||||
cur = r->task[r->ridx];
|
||||
prv = r->task[r->ridx-1];
|
||||
assert(prv->type == REDIS_REPLY_ARRAY ||
|
||||
prv->type == REDIS_REPLY_MAP ||
|
||||
prv->type == REDIS_REPLY_SET);
|
||||
prv->type == REDIS_REPLY_SET ||
|
||||
prv->type == REDIS_REPLY_PUSH);
|
||||
if (cur->idx == prv->elements-1) {
|
||||
r->ridx--;
|
||||
} else {
|
||||
@@ -262,7 +267,7 @@ static void moveToNextTask(redisReader *r) {
|
||||
}
|
||||
|
||||
static int processLineItem(redisReader *r) {
|
||||
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
void *obj;
|
||||
char *p;
|
||||
int len;
|
||||
@@ -297,7 +302,7 @@ static int processLineItem(redisReader *r) {
|
||||
if (strcasecmp(buf,",inf") == 0) {
|
||||
d = INFINITY; /* Positive infinite. */
|
||||
} else if (strcasecmp(buf,",-inf") == 0) {
|
||||
d = -INFINITY; /* Nevative infinite. */
|
||||
d = -INFINITY; /* Negative infinite. */
|
||||
} else {
|
||||
d = strtod((char*)buf,&eptr);
|
||||
if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) {
|
||||
@@ -344,7 +349,7 @@ static int processLineItem(redisReader *r) {
|
||||
}
|
||||
|
||||
static int processBulkItem(redisReader *r) {
|
||||
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
void *obj = NULL;
|
||||
char *p, *s;
|
||||
long long len;
|
||||
@@ -415,19 +420,43 @@ static int processBulkItem(redisReader *r) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int redisReaderGrow(redisReader *r) {
|
||||
redisReadTask **aux;
|
||||
int newlen;
|
||||
|
||||
/* Grow our stack size */
|
||||
newlen = r->tasks + REDIS_READER_STACK_SIZE;
|
||||
aux = hi_realloc(r->task, sizeof(*r->task) * newlen);
|
||||
if (aux == NULL)
|
||||
goto oom;
|
||||
|
||||
r->task = aux;
|
||||
|
||||
/* Allocate new tasks */
|
||||
for (; r->tasks < newlen; r->tasks++) {
|
||||
r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
|
||||
if (r->task[r->tasks] == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* Process the array, map and set types. */
|
||||
static int processAggregateItem(redisReader *r) {
|
||||
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
void *obj;
|
||||
char *p;
|
||||
long long elements;
|
||||
int root = 0, len;
|
||||
|
||||
/* Set error for nested multi bulks with depth > 7 */
|
||||
if (r->ridx == 8) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"No support for nested multi bulk replies with depth > 7");
|
||||
return REDIS_ERR;
|
||||
if (r->ridx == r->tasks - 1) {
|
||||
if (redisReaderGrow(r) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if ((p = readLine(r,&len)) != NULL) {
|
||||
@@ -439,7 +468,9 @@ static int processAggregateItem(redisReader *r) {
|
||||
|
||||
root = (r->ridx == 0);
|
||||
|
||||
if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) {
|
||||
if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX) ||
|
||||
(r->maxelements > 0 && elements > r->maxelements))
|
||||
{
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Multi-bulk length out of range");
|
||||
return REDIS_ERR;
|
||||
@@ -475,12 +506,12 @@ static int processAggregateItem(redisReader *r) {
|
||||
cur->elements = elements;
|
||||
cur->obj = obj;
|
||||
r->ridx++;
|
||||
r->rstack[r->ridx].type = -1;
|
||||
r->rstack[r->ridx].elements = -1;
|
||||
r->rstack[r->ridx].idx = 0;
|
||||
r->rstack[r->ridx].obj = NULL;
|
||||
r->rstack[r->ridx].parent = cur;
|
||||
r->rstack[r->ridx].privdata = r->privdata;
|
||||
r->task[r->ridx]->type = -1;
|
||||
r->task[r->ridx]->elements = -1;
|
||||
r->task[r->ridx]->idx = 0;
|
||||
r->task[r->ridx]->obj = NULL;
|
||||
r->task[r->ridx]->parent = cur;
|
||||
r->task[r->ridx]->privdata = r->privdata;
|
||||
} else {
|
||||
moveToNextTask(r);
|
||||
}
|
||||
@@ -495,7 +526,7 @@ static int processAggregateItem(redisReader *r) {
|
||||
}
|
||||
|
||||
static int processItem(redisReader *r) {
|
||||
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
char *p;
|
||||
|
||||
/* check if we need to read type */
|
||||
@@ -535,6 +566,9 @@ static int processItem(redisReader *r) {
|
||||
case '=':
|
||||
cur->type = REDIS_REPLY_VERB;
|
||||
break;
|
||||
case '>':
|
||||
cur->type = REDIS_REPLY_PUSH;
|
||||
break;
|
||||
default:
|
||||
__redisReaderSetErrorProtocolByte(r,*p);
|
||||
return REDIS_ERR;
|
||||
@@ -560,6 +594,7 @@ static int processItem(redisReader *r) {
|
||||
case REDIS_REPLY_ARRAY:
|
||||
case REDIS_REPLY_MAP:
|
||||
case REDIS_REPLY_SET:
|
||||
case REDIS_REPLY_PUSH:
|
||||
return processAggregateItem(r);
|
||||
default:
|
||||
assert(NULL);
|
||||
@@ -570,33 +605,57 @@ static int processItem(redisReader *r) {
|
||||
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
|
||||
redisReader *r;
|
||||
|
||||
r = calloc(1,sizeof(redisReader));
|
||||
r = hi_calloc(1,sizeof(redisReader));
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
r->fn = fn;
|
||||
r->buf = sdsempty();
|
||||
r->maxbuf = REDIS_READER_MAX_BUF;
|
||||
if (r->buf == NULL) {
|
||||
free(r);
|
||||
return NULL;
|
||||
r->buf = hi_sdsempty();
|
||||
if (r->buf == NULL)
|
||||
goto oom;
|
||||
|
||||
r->task = hi_calloc(REDIS_READER_STACK_SIZE, sizeof(*r->task));
|
||||
if (r->task == NULL)
|
||||
goto oom;
|
||||
|
||||
for (; r->tasks < REDIS_READER_STACK_SIZE; r->tasks++) {
|
||||
r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
|
||||
if (r->task[r->tasks] == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
r->fn = fn;
|
||||
r->maxbuf = REDIS_READER_MAX_BUF;
|
||||
r->maxelements = REDIS_READER_MAX_ARRAY_ELEMENTS;
|
||||
r->ridx = -1;
|
||||
|
||||
return r;
|
||||
oom:
|
||||
redisReaderFree(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void redisReaderFree(redisReader *r) {
|
||||
if (r == NULL)
|
||||
return;
|
||||
|
||||
if (r->reply != NULL && r->fn && r->fn->freeObject)
|
||||
r->fn->freeObject(r->reply);
|
||||
sdsfree(r->buf);
|
||||
free(r);
|
||||
|
||||
if (r->task) {
|
||||
/* We know r->task[i] is allocated if i < r->tasks */
|
||||
for (int i = 0; i < r->tasks; i++) {
|
||||
hi_free(r->task[i]);
|
||||
}
|
||||
|
||||
hi_free(r->task);
|
||||
}
|
||||
|
||||
hi_sdsfree(r->buf);
|
||||
hi_free(r);
|
||||
}
|
||||
|
||||
int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
|
||||
sds newbuf;
|
||||
hisds newbuf;
|
||||
|
||||
/* Return early when this reader is in an erroneous state. */
|
||||
if (r->err)
|
||||
@@ -605,26 +664,25 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
|
||||
/* Copy the provided buffer. */
|
||||
if (buf != NULL && len >= 1) {
|
||||
/* Destroy internal buffer when it is empty and is quite large. */
|
||||
if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
|
||||
sdsfree(r->buf);
|
||||
r->buf = sdsempty();
|
||||
if (r->len == 0 && r->maxbuf != 0 && hi_sdsavail(r->buf) > r->maxbuf) {
|
||||
hi_sdsfree(r->buf);
|
||||
r->buf = hi_sdsempty();
|
||||
if (r->buf == 0) goto oom;
|
||||
|
||||
r->pos = 0;
|
||||
|
||||
/* r->buf should not be NULL since we just free'd a larger one. */
|
||||
assert(r->buf != NULL);
|
||||
}
|
||||
|
||||
newbuf = sdscatlen(r->buf,buf,len);
|
||||
if (newbuf == NULL) {
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
newbuf = hi_sdscatlen(r->buf,buf,len);
|
||||
if (newbuf == NULL) goto oom;
|
||||
|
||||
r->buf = newbuf;
|
||||
r->len = sdslen(r->buf);
|
||||
r->len = hi_sdslen(r->buf);
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisReaderGetReply(redisReader *r, void **reply) {
|
||||
@@ -642,12 +700,12 @@ int redisReaderGetReply(redisReader *r, void **reply) {
|
||||
|
||||
/* Set first item to process when the stack is empty. */
|
||||
if (r->ridx == -1) {
|
||||
r->rstack[0].type = -1;
|
||||
r->rstack[0].elements = -1;
|
||||
r->rstack[0].idx = -1;
|
||||
r->rstack[0].obj = NULL;
|
||||
r->rstack[0].parent = NULL;
|
||||
r->rstack[0].privdata = r->privdata;
|
||||
r->task[0]->type = -1;
|
||||
r->task[0]->elements = -1;
|
||||
r->task[0]->idx = -1;
|
||||
r->task[0]->obj = NULL;
|
||||
r->task[0]->parent = NULL;
|
||||
r->task[0]->privdata = r->privdata;
|
||||
r->ridx = 0;
|
||||
}
|
||||
|
||||
@@ -663,9 +721,9 @@ int redisReaderGetReply(redisReader *r, void **reply) {
|
||||
/* Discard part of the buffer when we've consumed at least 1k, to avoid
|
||||
* doing unnecessary calls to memmove() in sds.c. */
|
||||
if (r->pos >= 1024) {
|
||||
sdsrange(r->buf,r->pos,-1);
|
||||
if (hi_sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR;
|
||||
r->pos = 0;
|
||||
r->len = sdslen(r->buf);
|
||||
r->len = hi_sdslen(r->buf);
|
||||
}
|
||||
|
||||
/* Emit a reply when there is one. */
|
||||
|
||||
Vendored
+10
-3
@@ -63,7 +63,11 @@
|
||||
#define REDIS_REPLY_BIGNUM 13
|
||||
#define REDIS_REPLY_VERB 14
|
||||
|
||||
#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */
|
||||
/* Default max unused reader buffer. */
|
||||
#define REDIS_READER_MAX_BUF (1024*16)
|
||||
|
||||
/* Default multi-bulk element limit */
|
||||
#define REDIS_READER_MAX_ARRAY_ELEMENTS ((1LL<<32) - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -71,7 +75,7 @@ extern "C" {
|
||||
|
||||
typedef struct redisReadTask {
|
||||
int type;
|
||||
int elements; /* number of elements in multibulk container */
|
||||
long long elements; /* number of elements in multibulk container */
|
||||
int idx; /* index in parent (array) object */
|
||||
void *obj; /* holds user-generated value for a read task */
|
||||
struct redisReadTask *parent; /* parent task */
|
||||
@@ -96,8 +100,11 @@ typedef struct redisReader {
|
||||
size_t pos; /* Buffer cursor */
|
||||
size_t len; /* Buffer length */
|
||||
size_t maxbuf; /* Max length of unused buffer */
|
||||
long long maxelements; /* Max multi-bulk elements */
|
||||
|
||||
redisReadTask **task;
|
||||
int tasks;
|
||||
|
||||
redisReadTask rstack[9];
|
||||
int ridx; /* Index of current read task */
|
||||
void *reply; /* Temporary reply pointer */
|
||||
|
||||
|
||||
Vendored
+413
-415
File diff suppressed because it is too large.
Load diff
Vendored
+133
-131
@@ -30,29 +30,31 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SDS_H
|
||||
#define __SDS_H
|
||||
#ifndef HIREDIS_SDS_H
|
||||
#define HIREDIS_SDS_H
|
||||
|
||||
#define SDS_MAX_PREALLOC (1024*1024)
|
||||
#define HI_SDS_MAX_PREALLOC (1024*1024)
|
||||
#ifdef _MSC_VER
|
||||
#define __attribute__(x)
|
||||
typedef long long ssize_t;
|
||||
#define SSIZE_MAX (LLONG_MAX >> 1)
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef char *sds;
|
||||
typedef char *hisds;
|
||||
|
||||
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||
* However is here to document the layout of type 5 SDS strings. */
|
||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||
struct __attribute__ ((__packed__)) hisdshdr5 {
|
||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
struct __attribute__ ((__packed__)) hisdshdr8 {
|
||||
uint8_t len; /* used */
|
||||
uint8_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
@@ -60,7 +62,7 @@ struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
struct __attribute__ ((__packed__)) hisdshdr16 {
|
||||
uint16_t len; /* used */
|
||||
uint16_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
@@ -68,7 +70,7 @@ struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
struct __attribute__ ((__packed__)) hisdshdr32 {
|
||||
uint32_t len; /* used */
|
||||
uint32_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
@@ -76,7 +78,7 @@ struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
struct __attribute__ ((__packed__)) hisdshdr64 {
|
||||
uint64_t len; /* used */
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
@@ -85,203 +87,203 @@ struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SDS_TYPE_5 0
|
||||
#define SDS_TYPE_8 1
|
||||
#define SDS_TYPE_16 2
|
||||
#define SDS_TYPE_32 3
|
||||
#define SDS_TYPE_64 4
|
||||
#define SDS_TYPE_MASK 7
|
||||
#define SDS_TYPE_BITS 3
|
||||
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)));
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
#define HI_SDS_TYPE_5 0
|
||||
#define HI_SDS_TYPE_8 1
|
||||
#define HI_SDS_TYPE_16 2
|
||||
#define HI_SDS_TYPE_32 3
|
||||
#define HI_SDS_TYPE_64 4
|
||||
#define HI_SDS_TYPE_MASK 7
|
||||
#define HI_SDS_TYPE_BITS 3
|
||||
#define HI_SDS_HDR_VAR(T,s) struct hisdshdr##T *sh = (struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T)));
|
||||
#define HI_SDS_HDR(T,s) ((struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T))))
|
||||
#define HI_SDS_TYPE_5_LEN(f) ((f)>>HI_SDS_TYPE_BITS)
|
||||
|
||||
static inline size_t sdslen(const sds s) {
|
||||
static inline size_t hi_sdslen(const hisds s) {
|
||||
unsigned char flags = s[-1];
|
||||
|
||||
switch(__builtin_expect((flags&SDS_TYPE_MASK), SDS_TYPE_5)) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->len;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->len;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->len;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->len;
|
||||
switch(__builtin_expect((flags&HI_SDS_TYPE_MASK), HI_SDS_TYPE_5)) {
|
||||
case HI_SDS_TYPE_5:
|
||||
return HI_SDS_TYPE_5_LEN(flags);
|
||||
case HI_SDS_TYPE_8:
|
||||
return HI_SDS_HDR(8,s)->len;
|
||||
case HI_SDS_TYPE_16:
|
||||
return HI_SDS_HDR(16,s)->len;
|
||||
case HI_SDS_TYPE_32:
|
||||
return HI_SDS_HDR(32,s)->len;
|
||||
case HI_SDS_TYPE_64:
|
||||
return HI_SDS_HDR(64,s)->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t sdsavail(const sds s) {
|
||||
static inline size_t hi_sdsavail(const hisds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5: {
|
||||
switch(flags&HI_SDS_TYPE_MASK) {
|
||||
case HI_SDS_TYPE_5: {
|
||||
return 0;
|
||||
}
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
case HI_SDS_TYPE_8: {
|
||||
HI_SDS_HDR_VAR(8,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_16: {
|
||||
SDS_HDR_VAR(16,s);
|
||||
case HI_SDS_TYPE_16: {
|
||||
HI_SDS_HDR_VAR(16,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_32: {
|
||||
SDS_HDR_VAR(32,s);
|
||||
case HI_SDS_TYPE_32: {
|
||||
HI_SDS_HDR_VAR(32,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_64: {
|
||||
SDS_HDR_VAR(64,s);
|
||||
case HI_SDS_TYPE_64: {
|
||||
HI_SDS_HDR_VAR(64,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetlen(sds s, size_t newlen) {
|
||||
static inline void hi_sdssetlen(hisds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
switch(flags&HI_SDS_TYPE_MASK) {
|
||||
case HI_SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
|
||||
*fp = (unsigned char)(HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS));
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len = (uint8_t)newlen;
|
||||
case HI_SDS_TYPE_8:
|
||||
HI_SDS_HDR(8,s)->len = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len = (uint16_t)newlen;
|
||||
case HI_SDS_TYPE_16:
|
||||
HI_SDS_HDR(16,s)->len = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len = (uint32_t)newlen;
|
||||
case HI_SDS_TYPE_32:
|
||||
HI_SDS_HDR(32,s)->len = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len = (uint64_t)newlen;
|
||||
case HI_SDS_TYPE_64:
|
||||
HI_SDS_HDR(64,s)->len = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sdsinclen(sds s, size_t inc) {
|
||||
static inline void hi_sdsinclen(hisds s, size_t inc) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
switch(flags&HI_SDS_TYPE_MASK) {
|
||||
case HI_SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
unsigned char newlen = HI_SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
|
||||
*fp = HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len += (uint8_t)inc;
|
||||
case HI_SDS_TYPE_8:
|
||||
HI_SDS_HDR(8,s)->len += (uint8_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len += (uint16_t)inc;
|
||||
case HI_SDS_TYPE_16:
|
||||
HI_SDS_HDR(16,s)->len += (uint16_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len += (uint32_t)inc;
|
||||
case HI_SDS_TYPE_32:
|
||||
HI_SDS_HDR(32,s)->len += (uint32_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len += (uint64_t)inc;
|
||||
case HI_SDS_TYPE_64:
|
||||
HI_SDS_HDR(64,s)->len += (uint64_t)inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* sdsalloc() = sdsavail() + sdslen() */
|
||||
static inline size_t sdsalloc(const sds s) {
|
||||
/* hi_sdsalloc() = hi_sdsavail() + hi_sdslen() */
|
||||
static inline size_t hi_sdsalloc(const hisds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->alloc;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->alloc;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->alloc;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->alloc;
|
||||
switch(flags & HI_SDS_TYPE_MASK) {
|
||||
case HI_SDS_TYPE_5:
|
||||
return HI_SDS_TYPE_5_LEN(flags);
|
||||
case HI_SDS_TYPE_8:
|
||||
return HI_SDS_HDR(8,s)->alloc;
|
||||
case HI_SDS_TYPE_16:
|
||||
return HI_SDS_HDR(16,s)->alloc;
|
||||
case HI_SDS_TYPE_32:
|
||||
return HI_SDS_HDR(32,s)->alloc;
|
||||
case HI_SDS_TYPE_64:
|
||||
return HI_SDS_HDR(64,s)->alloc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
static inline void hi_sdssetalloc(hisds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
switch(flags&HI_SDS_TYPE_MASK) {
|
||||
case HI_SDS_TYPE_5:
|
||||
/* Nothing to do, this type has no total allocation info. */
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->alloc = (uint8_t)newlen;
|
||||
case HI_SDS_TYPE_8:
|
||||
HI_SDS_HDR(8,s)->alloc = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->alloc = (uint16_t)newlen;
|
||||
case HI_SDS_TYPE_16:
|
||||
HI_SDS_HDR(16,s)->alloc = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->alloc = (uint32_t)newlen;
|
||||
case HI_SDS_TYPE_32:
|
||||
HI_SDS_HDR(32,s)->alloc = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->alloc = (uint64_t)newlen;
|
||||
case HI_SDS_TYPE_64:
|
||||
HI_SDS_HDR(64,s)->alloc = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sds sdsnewlen(const void *init, size_t initlen);
|
||||
sds sdsnew(const char *init);
|
||||
sds sdsempty(void);
|
||||
sds sdsdup(const sds s);
|
||||
void sdsfree(sds s);
|
||||
sds sdsgrowzero(sds s, size_t len);
|
||||
sds sdscatlen(sds s, const void *t, size_t len);
|
||||
sds sdscat(sds s, const char *t);
|
||||
sds sdscatsds(sds s, const sds t);
|
||||
sds sdscpylen(sds s, const char *t, size_t len);
|
||||
sds sdscpy(sds s, const char *t);
|
||||
hisds hi_sdsnewlen(const void *init, size_t initlen);
|
||||
hisds hi_sdsnew(const char *init);
|
||||
hisds hi_sdsempty(void);
|
||||
hisds hi_sdsdup(const hisds s);
|
||||
void hi_sdsfree(hisds s);
|
||||
hisds hi_sdsgrowzero(hisds s, size_t len);
|
||||
hisds hi_sdscatlen(hisds s, const void *t, size_t len);
|
||||
hisds hi_sdscat(hisds s, const char *t);
|
||||
hisds hi_sdscatsds(hisds s, const hisds t);
|
||||
hisds hi_sdscpylen(hisds s, const char *t, size_t len);
|
||||
hisds hi_sdscpy(hisds s, const char *t);
|
||||
|
||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
||||
hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap);
|
||||
#ifdef __GNUC__
|
||||
sds sdscatprintf(sds s, const char *fmt, ...)
|
||||
hisds hi_sdscatprintf(hisds s, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
sds sdscatprintf(sds s, const char *fmt, ...);
|
||||
hisds hi_sdscatprintf(hisds s, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
sds sdscatfmt(sds s, char const *fmt, ...);
|
||||
sds sdstrim(sds s, const char *cset);
|
||||
void sdsrange(sds s, int start, int end);
|
||||
void sdsupdatelen(sds s);
|
||||
void sdsclear(sds s);
|
||||
int sdscmp(const sds s1, const sds s2);
|
||||
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
|
||||
void sdsfreesplitres(sds *tokens, int count);
|
||||
void sdstolower(sds s);
|
||||
void sdstoupper(sds s);
|
||||
sds sdsfromlonglong(long long value);
|
||||
sds sdscatrepr(sds s, const char *p, size_t len);
|
||||
sds *sdssplitargs(const char *line, int *argc);
|
||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
||||
sds sdsjoin(char **argv, int argc, char *sep);
|
||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
||||
hisds hi_sdscatfmt(hisds s, char const *fmt, ...);
|
||||
hisds hi_sdstrim(hisds s, const char *cset);
|
||||
int hi_sdsrange(hisds s, ssize_t start, ssize_t end);
|
||||
void hi_sdsupdatelen(hisds s);
|
||||
void hi_sdsclear(hisds s);
|
||||
int hi_sdscmp(const hisds s1, const hisds s2);
|
||||
hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
|
||||
void hi_sdsfreesplitres(hisds *tokens, int count);
|
||||
void hi_sdstolower(hisds s);
|
||||
void hi_sdstoupper(hisds s);
|
||||
hisds hi_sdsfromlonglong(long long value);
|
||||
hisds hi_sdscatrepr(hisds s, const char *p, size_t len);
|
||||
hisds *hi_sdssplitargs(const char *line, int *argc);
|
||||
hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen);
|
||||
hisds hi_sdsjoin(char **argv, int argc, char *sep);
|
||||
hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen);
|
||||
|
||||
/* Low level functions exposed to the user API */
|
||||
sds sdsMakeRoomFor(sds s, size_t addlen);
|
||||
void sdsIncrLen(sds s, int incr);
|
||||
sds sdsRemoveFreeSpace(sds s);
|
||||
size_t sdsAllocSize(sds s);
|
||||
void *sdsAllocPtr(sds s);
|
||||
hisds hi_sdsMakeRoomFor(hisds s, size_t addlen);
|
||||
void hi_sdsIncrLen(hisds s, int incr);
|
||||
hisds hi_sdsRemoveFreeSpace(hisds s);
|
||||
size_t hi_sdsAllocSize(hisds s);
|
||||
void *hi_sdsAllocPtr(hisds s);
|
||||
|
||||
/* Export the allocator used by SDS to the program using SDS.
|
||||
* Sometimes the program SDS is linked to, may use a different set of
|
||||
* allocators, but may want to allocate or free things that SDS will
|
||||
* respectively free or allocate. */
|
||||
void *sds_malloc(size_t size);
|
||||
void *sds_realloc(void *ptr, size_t size);
|
||||
void sds_free(void *ptr);
|
||||
void *hi_sds_malloc(size_t size);
|
||||
void *hi_sds_realloc(void *ptr, size_t size);
|
||||
void hi_sds_free(void *ptr);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int sdsTest(int argc, char *argv[]);
|
||||
int hi_sdsTest(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* HIREDIS_SDS_H */
|
||||
Vendored
+5
-3
@@ -37,6 +37,8 @@
|
||||
* the include of your alternate allocator if needed (not needed in order
|
||||
* to use the default libc allocator). */
|
||||
|
||||
#define s_malloc malloc
|
||||
#define s_realloc realloc
|
||||
#define s_free free
|
||||
#include "alloc.h"
|
||||
|
||||
#define hi_s_malloc hi_malloc
|
||||
#define hi_s_realloc hi_realloc
|
||||
#define hi_s_free hi_free
|
||||
Vendored
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SDS compatibility header.
|
||||
*
|
||||
* This simple file maps sds types and calls to their unique hiredis symbol names.
|
||||
* It's useful when we build Hiredis as a dependency of Redis and want to call
|
||||
* Hiredis' sds symbols rather than the ones built into Redis, as the libraries
|
||||
* have slightly diverged and could cause hard to track down ABI incompatibility
|
||||
* bugs.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HIREDIS_SDS_COMPAT
|
||||
#define HIREDIS_SDS_COMPAT
|
||||
|
||||
#define sds hisds
|
||||
|
||||
#define sdslen hi_sdslen
|
||||
#define sdsavail hi_sdsavail
|
||||
#define sdssetlen hi_sdssetlen
|
||||
#define sdsinclen hi_sdsinclen
|
||||
#define sdsalloc hi_sdsalloc
|
||||
#define sdssetalloc hi_sdssetalloc
|
||||
|
||||
#define sdsAllocPtr hi_sdsAllocPtr
|
||||
#define sdsAllocSize hi_sdsAllocSize
|
||||
#define sdscat hi_sdscat
|
||||
#define sdscatfmt hi_sdscatfmt
|
||||
#define sdscatlen hi_sdscatlen
|
||||
#define sdscatprintf hi_sdscatprintf
|
||||
#define sdscatrepr hi_sdscatrepr
|
||||
#define sdscatsds hi_sdscatsds
|
||||
#define sdscatvprintf hi_sdscatvprintf
|
||||
#define sdsclear hi_sdsclear
|
||||
#define sdscmp hi_sdscmp
|
||||
#define sdscpy hi_sdscpy
|
||||
#define sdscpylen hi_sdscpylen
|
||||
#define sdsdup hi_sdsdup
|
||||
#define sdsempty hi_sdsempty
|
||||
#define sds_free hi_sds_free
|
||||
#define sdsfree hi_sdsfree
|
||||
#define sdsfreesplitres hi_sdsfreesplitres
|
||||
#define sdsfromlonglong hi_sdsfromlonglong
|
||||
#define sdsgrowzero hi_sdsgrowzero
|
||||
#define sdsIncrLen hi_sdsIncrLen
|
||||
#define sdsjoin hi_sdsjoin
|
||||
#define sdsjoinsds hi_sdsjoinsds
|
||||
#define sdsll2str hi_sdsll2str
|
||||
#define sdsMakeRoomFor hi_sdsMakeRoomFor
|
||||
#define sds_malloc hi_sds_malloc
|
||||
#define sdsmapchars hi_sdsmapchars
|
||||
#define sdsnew hi_sdsnew
|
||||
#define sdsnewlen hi_sdsnewlen
|
||||
#define sdsrange hi_sdsrange
|
||||
#define sds_realloc hi_sds_realloc
|
||||
#define sdsRemoveFreeSpace hi_sdsRemoveFreeSpace
|
||||
#define sdssplitargs hi_sdssplitargs
|
||||
#define sdssplitlen hi_sdssplitlen
|
||||
#define sdstolower hi_sdstolower
|
||||
#define sdstoupper hi_sdstoupper
|
||||
#define sdstrim hi_sdstrim
|
||||
#define sdsull2str hi_sdsull2str
|
||||
#define sdsupdatelen hi_sdsupdatelen
|
||||
|
||||
#endif /* HIREDIS_SDS_COMPAT */
|
||||
Vendored
+1
-1
@@ -212,7 +212,7 @@ int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, sockle
|
||||
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
int ret = 0;
|
||||
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
|
||||
struct timeval *tv = optval;
|
||||
const struct timeval *tv = optval;
|
||||
DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
|
||||
ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD));
|
||||
} else {
|
||||
|
||||
Vendored
+2
-1
@@ -49,9 +49,10 @@
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef signed long ssize_t;
|
||||
typedef long long ssize_t;
|
||||
#endif
|
||||
|
||||
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
|
||||
|
||||
Vendored
+198
-120
@@ -34,25 +34,33 @@
|
||||
#include "async.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "win32.h"
|
||||
#include "async_private.h"
|
||||
#include "hiredis_ssl.h"
|
||||
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
/* The SSL context is attached to SSL/TLS connections as a privdata. */
|
||||
typedef struct redisSSLContext {
|
||||
/**
|
||||
* OpenSSL SSL_CTX; It is optional and will not be set when using
|
||||
* user-supplied SSL.
|
||||
*/
|
||||
struct redisSSLContext {
|
||||
/* Associated OpenSSL SSL_CTX as created by redisCreateSSLContext() */
|
||||
SSL_CTX *ssl_ctx;
|
||||
|
||||
/* Requested SNI, or NULL */
|
||||
char *server_name;
|
||||
};
|
||||
|
||||
/* The SSL connection context is attached to SSL/TLS connections as a privdata. */
|
||||
typedef struct redisSSL {
|
||||
/**
|
||||
* OpenSSL SSL object.
|
||||
*/
|
||||
@@ -72,43 +80,11 @@ typedef struct redisSSLContext {
|
||||
* should resume whenever a read takes place, if possible
|
||||
*/
|
||||
int pendingWrite;
|
||||
} redisSSLContext;
|
||||
} redisSSL;
|
||||
|
||||
/* Forward declaration */
|
||||
redisContextFuncs redisContextSSLFuncs;
|
||||
|
||||
#ifdef HIREDIS_SSL_TRACE
|
||||
/**
|
||||
* Callback used for debugging
|
||||
*/
|
||||
static void sslLogCallback(const SSL *ssl, int where, int ret) {
|
||||
const char *retstr = "";
|
||||
int should_log = 1;
|
||||
/* Ignore low-level SSL stuff */
|
||||
|
||||
if (where & SSL_CB_ALERT) {
|
||||
should_log = 1;
|
||||
}
|
||||
if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) {
|
||||
should_log = 1;
|
||||
}
|
||||
if ((where & SSL_CB_EXIT) && ret == 0) {
|
||||
should_log = 1;
|
||||
}
|
||||
|
||||
if (!should_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
retstr = SSL_alert_type_string(ret);
|
||||
printf("ST(0x%x). %s. R(0x%x)%s\n", where, SSL_state_string_long(ssl), ret, retstr);
|
||||
|
||||
if (where == SSL_CB_HANDSHAKE_DONE) {
|
||||
printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* OpenSSL global initialization and locking handling callbacks.
|
||||
* Note that this is only required for OpenSSL < 1.1.0.
|
||||
@@ -119,6 +95,18 @@ static void sslLogCallback(const SSL *ssl, int where, int ret) {
|
||||
#endif
|
||||
|
||||
#ifdef HIREDIS_USE_CRYPTO_LOCKS
|
||||
#ifdef _WIN32
|
||||
typedef CRITICAL_SECTION sslLockType;
|
||||
static void sslLockInit(sslLockType* l) {
|
||||
InitializeCriticalSection(l);
|
||||
}
|
||||
static void sslLockAcquire(sslLockType* l) {
|
||||
EnterCriticalSection(l);
|
||||
}
|
||||
static void sslLockRelease(sslLockType* l) {
|
||||
LeaveCriticalSection(l);
|
||||
}
|
||||
#else
|
||||
typedef pthread_mutex_t sslLockType;
|
||||
static void sslLockInit(sslLockType *l) {
|
||||
pthread_mutex_init(l, NULL);
|
||||
@@ -129,7 +117,9 @@ static void sslLockAcquire(sslLockType *l) {
|
||||
static void sslLockRelease(sslLockType *l) {
|
||||
pthread_mutex_unlock(l);
|
||||
}
|
||||
static pthread_mutex_t *ossl_locks;
|
||||
#endif
|
||||
|
||||
static sslLockType* ossl_locks;
|
||||
|
||||
static void opensslDoLock(int mode, int lkid, const char *f, int line) {
|
||||
sslLockType *l = ossl_locks + lkid;
|
||||
@@ -144,36 +134,151 @@ static void opensslDoLock(int mode, int lkid, const char *f, int line) {
|
||||
(void)line;
|
||||
}
|
||||
|
||||
static void initOpensslLocks(void) {
|
||||
static int initOpensslLocks(void) {
|
||||
unsigned ii, nlocks;
|
||||
if (CRYPTO_get_locking_callback() != NULL) {
|
||||
/* Someone already set the callback before us. Don't destroy it! */
|
||||
return;
|
||||
return REDIS_OK;
|
||||
}
|
||||
nlocks = CRYPTO_num_locks();
|
||||
ossl_locks = malloc(sizeof(*ossl_locks) * nlocks);
|
||||
ossl_locks = hi_malloc(sizeof(*ossl_locks) * nlocks);
|
||||
if (ossl_locks == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
for (ii = 0; ii < nlocks; ii++) {
|
||||
sslLockInit(ossl_locks + ii);
|
||||
}
|
||||
CRYPTO_set_locking_callback(opensslDoLock);
|
||||
return REDIS_OK;
|
||||
}
|
||||
#endif /* HIREDIS_USE_CRYPTO_LOCKS */
|
||||
|
||||
int redisInitOpenSSL(void)
|
||||
{
|
||||
SSL_library_init();
|
||||
#ifdef HIREDIS_USE_CRYPTO_LOCKS
|
||||
initOpensslLocks();
|
||||
#endif
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* redisSSLContext helper context destruction.
|
||||
*/
|
||||
|
||||
const char *redisSSLContextGetError(redisSSLContextError error)
|
||||
{
|
||||
switch (error) {
|
||||
case REDIS_SSL_CTX_NONE:
|
||||
return "No Error";
|
||||
case REDIS_SSL_CTX_CREATE_FAILED:
|
||||
return "Failed to create OpenSSL SSL_CTX";
|
||||
case REDIS_SSL_CTX_CERT_KEY_REQUIRED:
|
||||
return "Client cert and key must both be specified or skipped";
|
||||
case REDIS_SSL_CTX_CA_CERT_LOAD_FAILED:
|
||||
return "Failed to load CA Certificate or CA Path";
|
||||
case REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED:
|
||||
return "Failed to load client certificate";
|
||||
case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED:
|
||||
return "Failed to load private key";
|
||||
default:
|
||||
return "Unknown error code";
|
||||
}
|
||||
}
|
||||
|
||||
void redisFreeSSLContext(redisSSLContext *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (ctx->server_name) {
|
||||
hi_free(ctx->server_name);
|
||||
ctx->server_name = NULL;
|
||||
}
|
||||
|
||||
if (ctx->ssl_ctx) {
|
||||
SSL_CTX_free(ctx->ssl_ctx);
|
||||
ctx->ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
hi_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* redisSSLContext helper context initialization.
|
||||
*/
|
||||
|
||||
redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath,
|
||||
const char *cert_filename, const char *private_key_filename,
|
||||
const char *server_name, redisSSLContextError *error)
|
||||
{
|
||||
redisSSLContext *ctx = hi_calloc(1, sizeof(redisSSLContext));
|
||||
if (ctx == NULL)
|
||||
goto error;
|
||||
|
||||
ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ctx->ssl_ctx) {
|
||||
if (error) *error = REDIS_SSL_CTX_CREATE_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
|
||||
if ((cert_filename != NULL && private_key_filename == NULL) ||
|
||||
(private_key_filename != NULL && cert_filename == NULL)) {
|
||||
if (error) *error = REDIS_SSL_CTX_CERT_KEY_REQUIRED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (capath || cacert_filename) {
|
||||
if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cacert_filename, capath)) {
|
||||
if (error) *error = REDIS_SSL_CTX_CA_CERT_LOAD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (cert_filename) {
|
||||
if (!SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, cert_filename)) {
|
||||
if (error) *error = REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, private_key_filename, SSL_FILETYPE_PEM)) {
|
||||
if (error) *error = REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_name)
|
||||
ctx->server_name = hi_strdup(server_name);
|
||||
|
||||
return ctx;
|
||||
|
||||
error:
|
||||
redisFreeSSLContext(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* SSL Connection initialization.
|
||||
*/
|
||||
|
||||
static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
|
||||
if (c->privdata) {
|
||||
|
||||
static int redisSSLConnect(redisContext *c, SSL *ssl) {
|
||||
if (c->privctx) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
c->privdata = calloc(1, sizeof(redisSSLContext));
|
||||
|
||||
redisSSL *rssl = hi_calloc(1, sizeof(redisSSL));
|
||||
if (rssl == NULL) {
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
c->funcs = &redisContextSSLFuncs;
|
||||
redisSSLContext *rssl = c->privdata;
|
||||
|
||||
rssl->ssl_ctx = ssl_ctx;
|
||||
rssl->ssl = ssl;
|
||||
|
||||
SSL_set_mode(rssl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
@@ -183,12 +288,14 @@ static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
|
||||
ERR_clear_error();
|
||||
int rv = SSL_connect(rssl->ssl);
|
||||
if (rv == 1) {
|
||||
c->privctx = rssl;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
rv = SSL_get_error(rssl->ssl, rv);
|
||||
if (((c->flags & REDIS_BLOCK) == 0) &&
|
||||
(rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) {
|
||||
c->privctx = rssl;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
@@ -203,83 +310,58 @@ static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
|
||||
}
|
||||
__redisSetError(c, REDIS_ERR_IO, err);
|
||||
}
|
||||
|
||||
hi_free(rssl);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around redisSSLConnect() for users who manage their own context and
|
||||
* create their own SSL object.
|
||||
*/
|
||||
|
||||
int redisInitiateSSL(redisContext *c, SSL *ssl) {
|
||||
return redisSSLConnect(c, NULL, ssl);
|
||||
return redisSSLConnect(c, ssl);
|
||||
}
|
||||
|
||||
int redisSecureConnection(redisContext *c, const char *capath,
|
||||
const char *certpath, const char *keypath, const char *servername) {
|
||||
/**
|
||||
* A wrapper around redisSSLConnect() for users who use redisSSLContext and don't
|
||||
* manage their own SSL objects.
|
||||
*/
|
||||
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
SSL *ssl = NULL;
|
||||
int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx)
|
||||
{
|
||||
if (!c || !redis_ssl_ctx)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Initialize global OpenSSL stuff */
|
||||
static int isInit = 0;
|
||||
if (!isInit) {
|
||||
isInit = 1;
|
||||
SSL_library_init();
|
||||
#ifdef HIREDIS_USE_CRYPTO_LOCKS
|
||||
initOpensslLocks();
|
||||
#endif
|
||||
}
|
||||
/* We want to verify that redisSSLConnect() won't fail on this, as it will
|
||||
* not own the SSL object in that case and we'll end up leaking.
|
||||
*/
|
||||
if (c->privctx)
|
||||
return REDIS_ERR;
|
||||
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ssl_ctx) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Failed to create SSL_CTX");
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef HIREDIS_SSL_TRACE
|
||||
SSL_CTX_set_info_callback(ssl_ctx, sslLogCallback);
|
||||
#endif
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
if ((certpath != NULL && keypath == NULL) || (keypath != NULL && certpath == NULL)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "certpath and keypath must be specified together");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (capath) {
|
||||
if (!SSL_CTX_load_verify_locations(ssl_ctx, capath, NULL)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Invalid CA certificate");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (certpath) {
|
||||
if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, certpath)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client certificate");
|
||||
goto error;
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, keypath, SSL_FILETYPE_PEM)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client key");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
SSL *ssl = SSL_new(redis_ssl_ctx->ssl_ctx);
|
||||
if (!ssl) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance");
|
||||
goto error;
|
||||
}
|
||||
if (servername) {
|
||||
if (!SSL_set_tlsext_host_name(ssl, servername)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't set server name indication");
|
||||
|
||||
if (redis_ssl_ctx->server_name) {
|
||||
if (!SSL_set_tlsext_host_name(ssl, redis_ssl_ctx->server_name)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Failed to set server_name/SNI");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return redisSSLConnect(c, ssl_ctx, ssl);
|
||||
return redisSSLConnect(c, ssl);
|
||||
|
||||
error:
|
||||
if (ssl) SSL_free(ssl);
|
||||
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
|
||||
if (ssl)
|
||||
SSL_free(ssl);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int maybeCheckWant(redisSSLContext *rssl, int rv) {
|
||||
static int maybeCheckWant(redisSSL *rssl, int rv) {
|
||||
/**
|
||||
* If the error is WANT_READ or WANT_WRITE, the appropriate flags are set
|
||||
* and true is returned. False is returned otherwise
|
||||
@@ -299,23 +381,19 @@ static int maybeCheckWant(redisSSLContext *rssl, int rv) {
|
||||
* Implementation of redisContextFuncs for SSL connections.
|
||||
*/
|
||||
|
||||
static void redisSSLFreeContext(void *privdata){
|
||||
redisSSLContext *rsc = privdata;
|
||||
static void redisSSLFree(void *privctx){
|
||||
redisSSL *rsc = privctx;
|
||||
|
||||
if (!rsc) return;
|
||||
if (rsc->ssl) {
|
||||
SSL_free(rsc->ssl);
|
||||
rsc->ssl = NULL;
|
||||
}
|
||||
if (rsc->ssl_ctx) {
|
||||
SSL_CTX_free(rsc->ssl_ctx);
|
||||
rsc->ssl_ctx = NULL;
|
||||
}
|
||||
free(rsc);
|
||||
hi_free(rsc);
|
||||
}
|
||||
|
||||
static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
redisSSLContext *rssl = c->privdata;
|
||||
static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
redisSSL *rssl = c->privctx;
|
||||
|
||||
int nread = SSL_read(rssl->ssl, buf, bufcap);
|
||||
if (nread > 0) {
|
||||
@@ -356,10 +434,10 @@ static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
}
|
||||
}
|
||||
|
||||
static int redisSSLWrite(redisContext *c) {
|
||||
redisSSLContext *rssl = c->privdata;
|
||||
static ssize_t redisSSLWrite(redisContext *c) {
|
||||
redisSSL *rssl = c->privctx;
|
||||
|
||||
size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
|
||||
size_t len = rssl->lastLen ? rssl->lastLen : hi_sdslen(c->obuf);
|
||||
int rv = SSL_write(rssl->ssl, c->obuf, len);
|
||||
|
||||
if (rv > 0) {
|
||||
@@ -380,7 +458,7 @@ static int redisSSLWrite(redisContext *c) {
|
||||
|
||||
static void redisSSLAsyncRead(redisAsyncContext *ac) {
|
||||
int rv;
|
||||
redisSSLContext *rssl = ac->c.privdata;
|
||||
redisSSL *rssl = ac->c.privctx;
|
||||
redisContext *c = &ac->c;
|
||||
|
||||
rssl->wantRead = 0;
|
||||
@@ -410,7 +488,7 @@ static void redisSSLAsyncRead(redisAsyncContext *ac) {
|
||||
|
||||
static void redisSSLAsyncWrite(redisAsyncContext *ac) {
|
||||
int rv, done = 0;
|
||||
redisSSLContext *rssl = ac->c.privdata;
|
||||
redisSSL *rssl = ac->c.privctx;
|
||||
redisContext *c = &ac->c;
|
||||
|
||||
rssl->pendingWrite = 0;
|
||||
@@ -439,7 +517,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
|
||||
}
|
||||
|
||||
redisContextFuncs redisContextSSLFuncs = {
|
||||
.free_privdata = redisSSLFreeContext,
|
||||
.free_privctx = redisSSLFree,
|
||||
.async_read = redisSSLAsyncRead,
|
||||
.async_write = redisSSLAsyncWrite,
|
||||
.read = redisSSLRead,
|
||||
|
||||
Vendored
+504
-91
@@ -1,22 +1,24 @@
|
||||
#include "fmacros.h"
|
||||
#include "sockcompat.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef _WIN32
|
||||
#include <strings.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "hiredis.h"
|
||||
#include "async.h"
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
#include "hiredis_ssl.h"
|
||||
#endif
|
||||
#include "net.h"
|
||||
#include "win32.h"
|
||||
|
||||
enum connection_type {
|
||||
CONN_TCP,
|
||||
@@ -47,15 +49,35 @@ struct config {
|
||||
} ssl;
|
||||
};
|
||||
|
||||
struct privdata {
|
||||
int dtor_counter;
|
||||
};
|
||||
|
||||
struct pushCounters {
|
||||
int nil;
|
||||
int str;
|
||||
};
|
||||
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
redisSSLContext *_ssl_ctx = NULL;
|
||||
#endif
|
||||
|
||||
/* The following lines make up our testing "framework" :) */
|
||||
static int tests = 0, fails = 0;
|
||||
static int tests = 0, fails = 0, skips = 0;
|
||||
#define test(_s) { printf("#%02d ", ++tests); printf(_s); }
|
||||
#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;}
|
||||
#define test_skipped() { printf("\033[01;33mSKIPPED\033[0;0m\n"); skips++; }
|
||||
|
||||
static long long usec(void) {
|
||||
#ifndef _MSC_VER
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
|
||||
#else
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return (((long long)ft.dwHighDateTime << 32) | ft.dwLowDateTime) / 10;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The assert() calls below have side effects, so we need assert()
|
||||
@@ -65,6 +87,43 @@ static long long usec(void) {
|
||||
#define assert(e) (void)(e)
|
||||
#endif
|
||||
|
||||
/* Helper to extract Redis version information. Aborts on any failure. */
|
||||
#define REDIS_VERSION_FIELD "redis_version:"
|
||||
void get_redis_version(redisContext *c, int *majorptr, int *minorptr) {
|
||||
redisReply *reply;
|
||||
char *eptr, *s, *e;
|
||||
int major, minor;
|
||||
|
||||
reply = redisCommand(c, "INFO");
|
||||
if (reply == NULL || c->err || reply->type != REDIS_REPLY_STRING)
|
||||
goto abort;
|
||||
if ((s = strstr(reply->str, REDIS_VERSION_FIELD)) == NULL)
|
||||
goto abort;
|
||||
|
||||
s += strlen(REDIS_VERSION_FIELD);
|
||||
|
||||
/* We need a field terminator and at least 'x.y.z' (5) bytes of data */
|
||||
if ((e = strstr(s, "\r\n")) == NULL || (e - s) < 5)
|
||||
goto abort;
|
||||
|
||||
/* Extract version info */
|
||||
major = strtol(s, &eptr, 10);
|
||||
if (*eptr != '.') goto abort;
|
||||
minor = strtol(eptr+1, NULL, 10);
|
||||
|
||||
/* Push info the caller wants */
|
||||
if (majorptr) *majorptr = major;
|
||||
if (minorptr) *minorptr = minor;
|
||||
|
||||
freeReplyObject(reply);
|
||||
return;
|
||||
|
||||
abort:
|
||||
freeReplyObject(reply);
|
||||
fprintf(stderr, "Error: Cannot determine Redis version, aborting\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static redisContext *select_database(redisContext *c) {
|
||||
redisReply *reply;
|
||||
|
||||
@@ -87,6 +146,26 @@ static redisContext *select_database(redisContext *c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Switch protocol */
|
||||
static void send_hello(redisContext *c, int version) {
|
||||
redisReply *reply;
|
||||
int expected;
|
||||
|
||||
reply = redisCommand(c, "HELLO %d", version);
|
||||
expected = version == 3 ? REDIS_REPLY_MAP : REDIS_REPLY_ARRAY;
|
||||
assert(reply != NULL && reply->type == expected);
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Togggle client tracking */
|
||||
static void send_client_tracking(redisContext *c, const char *str) {
|
||||
redisReply *reply;
|
||||
|
||||
reply = redisCommand(c, "CLIENT TRACKING %s", str);
|
||||
assert(reply != NULL && reply->type == REDIS_REPLY_STATUS);
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
static int disconnect(redisContext *c, int keep_fd) {
|
||||
redisReply *reply;
|
||||
|
||||
@@ -105,9 +184,9 @@ static int disconnect(redisContext *c, int keep_fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void do_ssl_handshake(redisContext *c, struct config config) {
|
||||
static void do_ssl_handshake(redisContext *c) {
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
redisSecureConnection(c, config.ssl.ca_cert, config.ssl.cert, config.ssl.key, NULL);
|
||||
redisInitiateSSLWithContext(c, _ssl_ctx);
|
||||
if (c->err) {
|
||||
printf("SSL error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
@@ -115,7 +194,6 @@ static void do_ssl_handshake(redisContext *c, struct config config) {
|
||||
}
|
||||
#else
|
||||
(void) c;
|
||||
(void) config;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -150,7 +228,7 @@ static redisContext *do_connect(struct config config) {
|
||||
}
|
||||
|
||||
if (config.type == CONN_SSL) {
|
||||
do_ssl_handshake(c, config);
|
||||
do_ssl_handshake(c);
|
||||
}
|
||||
|
||||
return select_database(c);
|
||||
@@ -160,7 +238,7 @@ static void do_reconnect(redisContext *c, struct config config) {
|
||||
redisReconnect(c);
|
||||
|
||||
if (config.type == CONN_SSL) {
|
||||
do_ssl_handshake(c, config);
|
||||
do_ssl_handshake(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,43 +250,43 @@ static void test_format_commands(void) {
|
||||
len = redisFormatCommand(&cmd,"SET foo bar");
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
test("Format command with %%s string interpolation: ");
|
||||
len = redisFormatCommand(&cmd,"SET %s %s","foo","bar");
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
test("Format command with %%s and an empty string: ");
|
||||
len = redisFormatCommand(&cmd,"SET %s %s","foo","");
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(0+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
test("Format command with an empty string in between proper interpolations: ");
|
||||
len = redisFormatCommand(&cmd,"SET %s %s","","foo");
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(0+2)+4+(3+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
test("Format command with %%b string interpolation: ");
|
||||
len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3);
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
test("Format command with %%b and an empty string: ");
|
||||
len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0);
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(0+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
test("Format command with literal %%: ");
|
||||
len = redisFormatCommand(&cmd,"SET %% %%");
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(1+2)+4+(1+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
/* Vararg width depends on the type. These tests make sure that the
|
||||
* width is correctly determined using the format and subsequent varargs
|
||||
@@ -219,7 +297,7 @@ static void test_format_commands(void) {
|
||||
len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \
|
||||
test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \
|
||||
len == 4+5+(12+2)+4+(9+2)); \
|
||||
free(cmd); \
|
||||
hi_free(cmd); \
|
||||
} while(0)
|
||||
|
||||
#define FLOAT_WIDTH_TEST(type) do { \
|
||||
@@ -228,7 +306,7 @@ static void test_format_commands(void) {
|
||||
len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \
|
||||
test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \
|
||||
len == 4+5+(12+2)+4+(9+2)); \
|
||||
free(cmd); \
|
||||
hi_free(cmd); \
|
||||
} while(0)
|
||||
|
||||
INTEGER_WIDTH_TEST("d", int);
|
||||
@@ -259,29 +337,29 @@ static void test_format_commands(void) {
|
||||
len = redisFormatCommandArgv(&cmd,argc,argv,NULL);
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
test("Format command by passing argc/argv with lengths: ");
|
||||
len = redisFormatCommandArgv(&cmd,argc,argv,lens);
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
|
||||
sds sds_cmd;
|
||||
hisds sds_cmd;
|
||||
|
||||
sds_cmd = sdsempty();
|
||||
test("Format command into sds by passing argc/argv without lengths: ");
|
||||
sds_cmd = NULL;
|
||||
test("Format command into hisds by passing argc/argv without lengths: ");
|
||||
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL);
|
||||
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
sdsfree(sds_cmd);
|
||||
hi_sdsfree(sds_cmd);
|
||||
|
||||
sds_cmd = sdsempty();
|
||||
test("Format command into sds by passing argc/argv with lengths: ");
|
||||
sds_cmd = NULL;
|
||||
test("Format command into hisds by passing argc/argv with lengths: ");
|
||||
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens);
|
||||
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
|
||||
sdsfree(sds_cmd);
|
||||
hi_sdsfree(sds_cmd);
|
||||
}
|
||||
|
||||
static void test_append_formatted_commands(struct config config) {
|
||||
@@ -300,7 +378,7 @@ static void test_append_formatted_commands(struct config config) {
|
||||
|
||||
assert(redisGetReply(c, (void*)&reply) == REDIS_OK);
|
||||
|
||||
free(cmd);
|
||||
hi_free(cmd);
|
||||
freeReplyObject(reply);
|
||||
|
||||
disconnect(c, 0);
|
||||
@@ -308,7 +386,7 @@ static void test_append_formatted_commands(struct config config) {
|
||||
|
||||
static void test_reply_reader(void) {
|
||||
redisReader *reader;
|
||||
void *reply;
|
||||
void *reply, *root;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
@@ -332,16 +410,26 @@ static void test_reply_reader(void) {
|
||||
strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Set error on nested multi bulks with depth > 7: ");
|
||||
reader = redisReaderCreate();
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
redisReaderFeed(reader,(char*)"*1\r\n",4);
|
||||
test("Can handle arbitrarily nested multi-bulks: ");
|
||||
for (i = 0; i < 128; i++) {
|
||||
redisReaderFeed(reader,(char*)"*1\r\n", 4);
|
||||
}
|
||||
redisReaderFeed(reader,(char*)"$6\r\nLOLWUT\r\n",12);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
root = reply; /* Keep track of the root reply */
|
||||
test_cond(ret == REDIS_OK &&
|
||||
((redisReply*)reply)->type == REDIS_REPLY_ARRAY &&
|
||||
((redisReply*)reply)->elements == 1);
|
||||
|
||||
ret = redisReaderGetReply(reader,NULL);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strncasecmp(reader->errstr,"No support for",14) == 0);
|
||||
test("Can parse arbitrarily nested multi-bulks correctly: ");
|
||||
while(i--) {
|
||||
assert(reply != NULL && ((redisReply*)reply)->type == REDIS_REPLY_ARRAY);
|
||||
reply = ((redisReply*)reply)->element[0];
|
||||
}
|
||||
test_cond(((redisReply*)reply)->type == REDIS_REPLY_STRING &&
|
||||
!memcmp(((redisReply*)reply)->str, "LOLWUT", 6));
|
||||
freeReplyObject(root);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Correctly parses LLONG_MAX: ");
|
||||
@@ -400,6 +488,30 @@ static void test_reply_reader(void) {
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Can configure maximum multi-bulk elements: ");
|
||||
reader = redisReaderCreate();
|
||||
reader->maxelements = 1024;
|
||||
redisReaderFeed(reader, "*1025\r\n", 7);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strcasecmp(reader->errstr, "Multi-bulk length out of range") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Multi-bulk never overflows regardless of maxelements: ");
|
||||
size_t bad_mbulk_len = (SIZE_MAX / sizeof(void *)) + 3;
|
||||
char bad_mbulk_reply[100];
|
||||
snprintf(bad_mbulk_reply, sizeof(bad_mbulk_reply), "*%llu\r\n+asdf\r\n",
|
||||
(unsigned long long) bad_mbulk_len);
|
||||
|
||||
reader = redisReaderCreate();
|
||||
reader->maxelements = 0; /* Don't rely on default limit */
|
||||
redisReaderFeed(reader, bad_mbulk_reply, strlen(bad_mbulk_reply));
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR && strcasecmp(reader->errstr, "Out of memory") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
#if LLONG_MAX > SIZE_MAX
|
||||
test("Set error when array > SIZE_MAX: ");
|
||||
reader = redisReaderCreate();
|
||||
@@ -459,6 +571,32 @@ static void test_reply_reader(void) {
|
||||
((redisReply*)reply)->elements == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
/* RESP3 verbatim strings (GitHub issue #802) */
|
||||
test("Can parse RESP3 verbatim strings: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader,(char*)"=10\r\ntxt:LOLWUT\r\n",17);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_OK &&
|
||||
((redisReply*)reply)->type == REDIS_REPLY_VERB &&
|
||||
!memcmp(((redisReply*)reply)->str,"LOLWUT", 6));
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
/* RESP3 push messages (Github issue #815) */
|
||||
test("Can parse RESP3 push messages: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader,(char*)">2\r\n$6\r\nLOLWUT\r\n:42\r\n",21);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_OK &&
|
||||
((redisReply*)reply)->type == REDIS_REPLY_PUSH &&
|
||||
((redisReply*)reply)->elements == 2 &&
|
||||
((redisReply*)reply)->element[0]->type == REDIS_REPLY_STRING &&
|
||||
!memcmp(((redisReply*)reply)->element[0]->str,"LOLWUT",6) &&
|
||||
((redisReply*)reply)->element[1]->type == REDIS_REPLY_INTEGER &&
|
||||
((redisReply*)reply)->element[1]->integer == 42);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
}
|
||||
|
||||
static void test_free_null(void) {
|
||||
@@ -474,6 +612,47 @@ static void test_free_null(void) {
|
||||
test_cond(reply == NULL);
|
||||
}
|
||||
|
||||
static void *hi_malloc_fail(size_t size) {
|
||||
(void)size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *hi_calloc_fail(size_t nmemb, size_t size) {
|
||||
(void)nmemb;
|
||||
(void)size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *hi_realloc_fail(void *ptr, size_t size) {
|
||||
(void)ptr;
|
||||
(void)size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_allocator_injection(void) {
|
||||
hiredisAllocFuncs ha = {
|
||||
.mallocFn = hi_malloc_fail,
|
||||
.callocFn = hi_calloc_fail,
|
||||
.reallocFn = hi_realloc_fail,
|
||||
.strdupFn = strdup,
|
||||
.freeFn = free,
|
||||
};
|
||||
|
||||
// Override hiredis allocators
|
||||
hiredisSetAllocators(&ha);
|
||||
|
||||
test("redisContext uses injected allocators: ");
|
||||
redisContext *c = redisConnect("localhost", 6379);
|
||||
test_cond(c == NULL);
|
||||
|
||||
test("redisReader uses injected allocators: ");
|
||||
redisReader *reader = redisReaderCreate();
|
||||
test_cond(reader == NULL);
|
||||
|
||||
// Return allocators to default
|
||||
hiredisResetAllocators();
|
||||
}
|
||||
|
||||
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
|
||||
static void test_blocking_connection_errors(void) {
|
||||
redisContext *c;
|
||||
@@ -491,19 +670,19 @@ static void test_blocking_connection_errors(void) {
|
||||
(strcmp(c->errstr, "Name or service not known") == 0 ||
|
||||
strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 ||
|
||||
strcmp(c->errstr, "Name does not resolve") == 0 ||
|
||||
strcmp(c->errstr,
|
||||
"nodename nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr, "nodename nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr, "No address associated with hostname") == 0 ||
|
||||
strcmp(c->errstr, "Temporary failure in name resolution") == 0 ||
|
||||
strcmp(c->errstr,
|
||||
"hostname nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr, "no address associated with name") == 0));
|
||||
strcmp(c->errstr, "hostname nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr, "no address associated with name") == 0 ||
|
||||
strcmp(c->errstr, "No such host is known. ") == 0));
|
||||
redisFree(c);
|
||||
} else {
|
||||
printf("Skipping NXDOMAIN test. Found evil ISP!\n");
|
||||
freeaddrinfo(ai_tmp);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
test("Returns error when the port is not open: ");
|
||||
c = redisConnect((char*)"localhost", 1);
|
||||
test_cond(c->err == REDIS_ERR_IO &&
|
||||
@@ -514,11 +693,166 @@ static void test_blocking_connection_errors(void) {
|
||||
c = redisConnectUnix((char*)"/tmp/idontexist.sock");
|
||||
test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */
|
||||
redisFree(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Test push handler */
|
||||
void push_handler(void *privdata, void *r) {
|
||||
struct pushCounters *pcounts = privdata;
|
||||
redisReply *reply = r, *payload;
|
||||
|
||||
assert(reply && reply->type == REDIS_REPLY_PUSH && reply->elements == 2);
|
||||
|
||||
payload = reply->element[1];
|
||||
if (payload->type == REDIS_REPLY_ARRAY) {
|
||||
payload = payload->element[0];
|
||||
}
|
||||
|
||||
if (payload->type == REDIS_REPLY_STRING) {
|
||||
pcounts->str++;
|
||||
} else if (payload->type == REDIS_REPLY_NIL) {
|
||||
pcounts->nil++;
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Dummy function just to test setting a callback with redisOptions */
|
||||
void push_handler_async(redisAsyncContext *ac, void *reply) {
|
||||
(void)ac;
|
||||
(void)reply;
|
||||
}
|
||||
|
||||
static void test_resp3_push_handler(redisContext *c) {
|
||||
struct pushCounters pc = {0};
|
||||
redisPushFn *old = NULL;
|
||||
redisReply *reply;
|
||||
void *privdata;
|
||||
|
||||
/* Switch to RESP3 and turn on client tracking */
|
||||
send_hello(c, 3);
|
||||
send_client_tracking(c, "ON");
|
||||
privdata = c->privdata;
|
||||
c->privdata = &pc;
|
||||
|
||||
reply = redisCommand(c, "GET key:0");
|
||||
assert(reply != NULL);
|
||||
freeReplyObject(reply);
|
||||
|
||||
test("RESP3 PUSH messages are handled out of band by default: ");
|
||||
reply = redisCommand(c, "SET key:0 val:0");
|
||||
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS);
|
||||
freeReplyObject(reply);
|
||||
|
||||
assert((reply = redisCommand(c, "GET key:0")) != NULL);
|
||||
freeReplyObject(reply);
|
||||
|
||||
old = redisSetPushCallback(c, push_handler);
|
||||
test("We can set a custom RESP3 PUSH handler: ");
|
||||
reply = redisCommand(c, "SET key:0 val:0");
|
||||
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.str == 1);
|
||||
freeReplyObject(reply);
|
||||
|
||||
test("We properly handle a NIL invalidation payload: ");
|
||||
reply = redisCommand(c, "FLUSHDB");
|
||||
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.nil == 1);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Unset the push callback and generate an invalidate message making
|
||||
* sure it is not handled out of band. */
|
||||
test("With no handler, PUSH replies come in-band: ");
|
||||
redisSetPushCallback(c, NULL);
|
||||
assert((reply = redisCommand(c, "GET key:0")) != NULL);
|
||||
freeReplyObject(reply);
|
||||
assert((reply = redisCommand(c, "SET key:0 invalid")) != NULL);
|
||||
test_cond(reply->type == REDIS_REPLY_PUSH);
|
||||
freeReplyObject(reply);
|
||||
|
||||
test("With no PUSH handler, no replies are lost: ");
|
||||
assert(redisGetReply(c, (void**)&reply) == REDIS_OK);
|
||||
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Return to the originally set PUSH handler */
|
||||
assert(old != NULL);
|
||||
redisSetPushCallback(c, old);
|
||||
|
||||
/* Switch back to RESP2 and disable tracking */
|
||||
c->privdata = privdata;
|
||||
send_client_tracking(c, "OFF");
|
||||
send_hello(c, 2);
|
||||
}
|
||||
|
||||
redisOptions get_redis_tcp_options(struct config config) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, config.tcp.host, config.tcp.port);
|
||||
return options;
|
||||
}
|
||||
|
||||
static void test_resp3_push_options(struct config config) {
|
||||
redisAsyncContext *ac;
|
||||
redisContext *c;
|
||||
redisOptions options;
|
||||
|
||||
test("We set a default RESP3 handler for redisContext: ");
|
||||
options = get_redis_tcp_options(config);
|
||||
assert((c = redisConnectWithOptions(&options)) != NULL);
|
||||
test_cond(c->push_cb != NULL);
|
||||
redisFree(c);
|
||||
|
||||
test("We don't set a default RESP3 push handler for redisAsyncContext: ");
|
||||
options = get_redis_tcp_options(config);
|
||||
assert((ac = redisAsyncConnectWithOptions(&options)) != NULL);
|
||||
test_cond(ac->c.push_cb == NULL);
|
||||
redisAsyncFree(ac);
|
||||
|
||||
test("Our REDIS_OPT_NO_PUSH_AUTOFREE flag works: ");
|
||||
options = get_redis_tcp_options(config);
|
||||
options.options |= REDIS_OPT_NO_PUSH_AUTOFREE;
|
||||
assert((c = redisConnectWithOptions(&options)) != NULL);
|
||||
test_cond(c->push_cb == NULL);
|
||||
redisFree(c);
|
||||
|
||||
test("We can use redisOptions to set a custom PUSH handler for redisContext: ");
|
||||
options = get_redis_tcp_options(config);
|
||||
options.push_cb = push_handler;
|
||||
assert((c = redisConnectWithOptions(&options)) != NULL);
|
||||
test_cond(c->push_cb == push_handler);
|
||||
redisFree(c);
|
||||
|
||||
test("We can use redisOptions to set a custom PUSH handler for redisAsyncContext: ");
|
||||
options = get_redis_tcp_options(config);
|
||||
options.async_push_cb = push_handler_async;
|
||||
assert((ac = redisAsyncConnectWithOptions(&options)) != NULL);
|
||||
test_cond(ac->push_cb == push_handler_async);
|
||||
redisAsyncFree(ac);
|
||||
}
|
||||
|
||||
void free_privdata(void *privdata) {
|
||||
struct privdata *data = privdata;
|
||||
data->dtor_counter++;
|
||||
}
|
||||
|
||||
static void test_privdata_hooks(struct config config) {
|
||||
struct privdata data = {0};
|
||||
redisOptions options;
|
||||
redisContext *c;
|
||||
|
||||
test("We can use redisOptions to set privdata: ");
|
||||
options = get_redis_tcp_options(config);
|
||||
REDIS_OPTIONS_SET_PRIVDATA(&options, &data, free_privdata);
|
||||
assert((c = redisConnectWithOptions(&options)) != NULL);
|
||||
test_cond(c->privdata == &data);
|
||||
|
||||
test("Our privdata destructor fires when we free the context: ");
|
||||
redisFree(c);
|
||||
test_cond(data.dtor_counter == 1);
|
||||
}
|
||||
|
||||
static void test_blocking_connection(struct config config) {
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
int major;
|
||||
|
||||
c = do_connect(config);
|
||||
|
||||
@@ -591,14 +925,42 @@ static void test_blocking_connection(struct config config) {
|
||||
strcasecmp(reply->element[1]->str,"pong") == 0);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Make sure passing NULL to redisGetReply is safe */
|
||||
test("Can pass NULL to redisGetReply: ");
|
||||
assert(redisAppendCommand(c, "PING") == REDIS_OK);
|
||||
test_cond(redisGetReply(c, NULL) == REDIS_OK);
|
||||
|
||||
get_redis_version(c, &major, NULL);
|
||||
if (major >= 6) test_resp3_push_handler(c);
|
||||
test_resp3_push_options(config);
|
||||
|
||||
test_privdata_hooks(config);
|
||||
|
||||
disconnect(c, 0);
|
||||
}
|
||||
|
||||
/* Send DEBUG SLEEP 0 to detect if we have this command */
|
||||
static int detect_debug_sleep(redisContext *c) {
|
||||
int detected;
|
||||
redisReply *reply = redisCommand(c, "DEBUG SLEEP 0\r\n");
|
||||
|
||||
if (reply == NULL || c->err) {
|
||||
const char *cause = c->err ? c->errstr : "(none)";
|
||||
fprintf(stderr, "Error testing for DEBUG SLEEP (Redis error: %s), exiting\n", cause);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
detected = reply->type == REDIS_REPLY_STATUS;
|
||||
freeReplyObject(reply);
|
||||
|
||||
return detected;
|
||||
}
|
||||
|
||||
static void test_blocking_connection_timeouts(struct config config) {
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
ssize_t s;
|
||||
const char *cmd = "DEBUG SLEEP 3\r\n";
|
||||
const char *sleep_cmd = "DEBUG SLEEP 3\r\n";
|
||||
struct timeval tv;
|
||||
|
||||
c = do_connect(config);
|
||||
@@ -615,14 +977,24 @@ static void test_blocking_connection_timeouts(struct config config) {
|
||||
|
||||
c = do_connect(config);
|
||||
test("Does not return a reply when the command times out: ");
|
||||
redisAppendFormattedCommand(c, cmd, strlen(cmd));
|
||||
s = c->funcs->write(c);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
redisSetTimeout(c, tv);
|
||||
reply = redisCommand(c, "GET foo");
|
||||
test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Resource temporarily unavailable") == 0);
|
||||
freeReplyObject(reply);
|
||||
if (detect_debug_sleep(c)) {
|
||||
redisAppendFormattedCommand(c, sleep_cmd, strlen(sleep_cmd));
|
||||
s = c->funcs->write(c);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
redisSetTimeout(c, tv);
|
||||
reply = redisCommand(c, "GET foo");
|
||||
#ifndef _WIN32
|
||||
test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO &&
|
||||
strcmp(c->errstr, "Resource temporarily unavailable") == 0);
|
||||
#else
|
||||
test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_TIMEOUT &&
|
||||
strcmp(c->errstr, "recv timeout") == 0);
|
||||
#endif
|
||||
freeReplyObject(reply);
|
||||
} else {
|
||||
test_skipped();
|
||||
}
|
||||
|
||||
test("Reconnect properly reconnects after a timeout: ");
|
||||
do_reconnect(c, config);
|
||||
@@ -649,18 +1021,7 @@ static void test_blocking_io_errors(struct config config) {
|
||||
|
||||
/* Connect to target given by config. */
|
||||
c = do_connect(config);
|
||||
{
|
||||
/* Find out Redis version to determine the path for the next test */
|
||||
const char *field = "redis_version:";
|
||||
char *p, *eptr;
|
||||
|
||||
reply = redisCommand(c,"INFO");
|
||||
p = strstr(reply->str,field);
|
||||
major = strtol(p+strlen(field),&eptr,10);
|
||||
p = eptr+1; /* char next to the first "." */
|
||||
minor = strtol(p,&eptr,10);
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
get_redis_version(c, &major, &minor);
|
||||
|
||||
test("Returns I/O error when the connection is lost: ");
|
||||
reply = redisCommand(c,"QUIT");
|
||||
@@ -674,6 +1035,7 @@ static void test_blocking_io_errors(struct config config) {
|
||||
test_cond(reply == NULL);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* On 2.0, QUIT will cause the connection to be closed immediately and
|
||||
* the read(2) for the reply on QUIT will set the error to EOF.
|
||||
* On >2.0, QUIT will return with OK and another read(2) needed to be
|
||||
@@ -681,14 +1043,19 @@ static void test_blocking_io_errors(struct config config) {
|
||||
* conditions, the error will be set to EOF. */
|
||||
assert(c->err == REDIS_ERR_EOF &&
|
||||
strcmp(c->errstr,"Server closed the connection") == 0);
|
||||
#endif
|
||||
redisFree(c);
|
||||
|
||||
c = do_connect(config);
|
||||
test("Returns I/O error on socket timeout: ");
|
||||
struct timeval tv = { 0, 1000 };
|
||||
assert(redisSetTimeout(c,tv) == REDIS_OK);
|
||||
test_cond(redisGetReply(c,&_reply) == REDIS_ERR &&
|
||||
c->err == REDIS_ERR_IO && errno == EAGAIN);
|
||||
int respcode = redisGetReply(c,&_reply);
|
||||
#ifndef _WIN32
|
||||
test_cond(respcode == REDIS_ERR && c->err == REDIS_ERR_IO && errno == EAGAIN);
|
||||
#else
|
||||
test_cond(respcode == REDIS_ERR && c->err == REDIS_ERR_TIMEOUT);
|
||||
#endif
|
||||
redisFree(c);
|
||||
}
|
||||
|
||||
@@ -716,6 +1083,18 @@ static void test_invalid_timeout_errors(struct config config) {
|
||||
redisFree(c);
|
||||
}
|
||||
|
||||
/* Wrap malloc to abort on failure so OOM checks don't make the test logic
|
||||
* harder to follow. */
|
||||
void *hi_malloc_safe(size_t size) {
|
||||
void *ptr = hi_malloc(size);
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Error: Out of memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void test_throughput(struct config config) {
|
||||
redisContext *c = do_connect(config);
|
||||
redisReply **replies;
|
||||
@@ -727,7 +1106,7 @@ static void test_throughput(struct config config) {
|
||||
freeReplyObject(redisCommand(c,"LPUSH mylist foo"));
|
||||
|
||||
num = 1000;
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
replies = hi_malloc_safe(sizeof(redisReply*)*num);
|
||||
t1 = usec();
|
||||
for (i = 0; i < num; i++) {
|
||||
replies[i] = redisCommand(c,"PING");
|
||||
@@ -735,10 +1114,10 @@ static void test_throughput(struct config config) {
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
hi_free(replies);
|
||||
printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
replies = hi_malloc_safe(sizeof(redisReply*)*num);
|
||||
t1 = usec();
|
||||
for (i = 0; i < num; i++) {
|
||||
replies[i] = redisCommand(c,"LRANGE mylist 0 499");
|
||||
@@ -747,10 +1126,10 @@ static void test_throughput(struct config config) {
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
hi_free(replies);
|
||||
printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
replies = hi_malloc_safe(sizeof(redisReply*)*num);
|
||||
t1 = usec();
|
||||
for (i = 0; i < num; i++) {
|
||||
replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000);
|
||||
@@ -758,11 +1137,11 @@ static void test_throughput(struct config config) {
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
hi_free(replies);
|
||||
printf("\t(%dx INCRBY: %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
num = 10000;
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
replies = hi_malloc_safe(sizeof(redisReply*)*num);
|
||||
for (i = 0; i < num; i++)
|
||||
redisAppendCommand(c,"PING");
|
||||
t1 = usec();
|
||||
@@ -772,10 +1151,10 @@ static void test_throughput(struct config config) {
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
hi_free(replies);
|
||||
printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
replies = hi_malloc_safe(sizeof(redisReply*)*num);
|
||||
for (i = 0; i < num; i++)
|
||||
redisAppendCommand(c,"LRANGE mylist 0 499");
|
||||
t1 = usec();
|
||||
@@ -786,10 +1165,10 @@ static void test_throughput(struct config config) {
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
hi_free(replies);
|
||||
printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
replies = hi_malloc_safe(sizeof(redisReply*)*num);
|
||||
for (i = 0; i < num; i++)
|
||||
redisAppendCommand(c,"INCRBY incrkey %d", 1000000);
|
||||
t1 = usec();
|
||||
@@ -799,7 +1178,7 @@ static void test_throughput(struct config config) {
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
hi_free(replies);
|
||||
printf("\t(%dx INCRBY (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
disconnect(c, 0);
|
||||
@@ -916,9 +1295,8 @@ int main(int argc, char **argv) {
|
||||
};
|
||||
int throughput = 1;
|
||||
int test_inherit_fd = 1;
|
||||
|
||||
/* Ignore broken pipe signal (for I/O error tests). */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
int skips_as_fails = 0;
|
||||
int test_unix_socket;
|
||||
|
||||
/* Parse command line options. */
|
||||
argv++; argc--;
|
||||
@@ -936,6 +1314,8 @@ int main(int argc, char **argv) {
|
||||
throughput = 0;
|
||||
} else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) {
|
||||
test_inherit_fd = 0;
|
||||
} else if (argc >= 1 && !strcmp(argv[0],"--skips-as-fails")) {
|
||||
skips_as_fails = 1;
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-port")) {
|
||||
argv++; argc--;
|
||||
@@ -960,6 +1340,19 @@ int main(int argc, char **argv) {
|
||||
argv++; argc--;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Ignore broken pipe signal (for I/O error tests). */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
test_unix_socket = access(cfg.unix_sock.path, F_OK) == 0;
|
||||
|
||||
#else
|
||||
/* Unix sockets don't exist in Windows */
|
||||
test_unix_socket = 0;
|
||||
#endif
|
||||
|
||||
test_allocator_injection();
|
||||
|
||||
test_format_commands();
|
||||
test_reply_reader();
|
||||
test_blocking_connection_errors();
|
||||
@@ -974,15 +1367,25 @@ int main(int argc, char **argv) {
|
||||
test_append_formatted_commands(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
|
||||
printf("\nTesting against Unix socket connection (%s):\n", cfg.unix_sock.path);
|
||||
cfg.type = CONN_UNIX;
|
||||
test_blocking_connection(cfg);
|
||||
test_blocking_connection_timeouts(cfg);
|
||||
test_blocking_io_errors(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
printf("\nTesting against Unix socket connection (%s): ", cfg.unix_sock.path);
|
||||
if (test_unix_socket) {
|
||||
printf("\n");
|
||||
cfg.type = CONN_UNIX;
|
||||
test_blocking_connection(cfg);
|
||||
test_blocking_connection_timeouts(cfg);
|
||||
test_blocking_io_errors(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
} else {
|
||||
test_skipped();
|
||||
}
|
||||
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
if (cfg.ssl.port && cfg.ssl.host) {
|
||||
|
||||
redisInitOpenSSL();
|
||||
_ssl_ctx = redisCreateSSLContext(cfg.ssl.ca_cert, NULL, cfg.ssl.cert, cfg.ssl.key, NULL, NULL);
|
||||
assert(_ssl_ctx != NULL);
|
||||
|
||||
printf("\nTesting against SSL connection (%s:%d):\n", cfg.ssl.host, cfg.ssl.port);
|
||||
cfg.type = CONN_SSL;
|
||||
|
||||
@@ -992,21 +1395,31 @@ int main(int argc, char **argv) {
|
||||
test_invalid_timeout_errors(cfg);
|
||||
test_append_formatted_commands(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
|
||||
redisFreeSSLContext(_ssl_ctx);
|
||||
_ssl_ctx = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (test_inherit_fd) {
|
||||
printf("\nTesting against inherited fd (%s):\n", cfg.unix_sock.path);
|
||||
cfg.type = CONN_FD;
|
||||
test_blocking_connection(cfg);
|
||||
printf("\nTesting against inherited fd (%s): ", cfg.unix_sock.path);
|
||||
if (test_unix_socket) {
|
||||
printf("\n");
|
||||
cfg.type = CONN_FD;
|
||||
test_blocking_connection(cfg);
|
||||
} else {
|
||||
test_skipped();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fails) {
|
||||
if (fails || (skips_as_fails && skips)) {
|
||||
printf("*** %d TESTS FAILED ***\n", fails);
|
||||
if (skips) {
|
||||
printf("*** %d TESTS SKIPPED ***\n", skips);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("ALL TESTS PASSED\n");
|
||||
printf("ALL TESTS PASSED (%d skipped)\n", skips);
|
||||
return 0;
|
||||
}
|
||||
Vendored
+9
-1
@@ -4,7 +4,9 @@ REDIS_SERVER=${REDIS_SERVER:-redis-server}
|
||||
REDIS_PORT=${REDIS_PORT:-56379}
|
||||
REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443}
|
||||
TEST_SSL=${TEST_SSL:-0}
|
||||
SKIPS_AS_FAILS=${SKIPS_AS_FAILS-:0}
|
||||
SSL_TEST_ARGS=
|
||||
SKIPS_ARG=
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
PID_FILE=${tmpdir}/hiredis-test-redis.pid
|
||||
@@ -67,4 +69,10 @@ fi
|
||||
cat ${tmpdir}/redis.conf
|
||||
${REDIS_SERVER} ${tmpdir}/redis.conf
|
||||
|
||||
${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS}
|
||||
# Wait until we detect the unix socket
|
||||
while [ ! -S "${SOCK_FILE}" ]; do sleep 1; done
|
||||
|
||||
# Treat skips as failures if directed
|
||||
[ "$SKIPS_AS_FAILS" = 1 ] && SKIPS_ARG="--skips-as-fails"
|
||||
|
||||
${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS} ${SKIPS_ARG}
|
||||
Vendored
+8
-8
@@ -5,27 +5,27 @@ environment:
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
MSVC: amd64
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
MSVC: x86
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
MSVC: amd64
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
MSVC: x86
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
|
||||
install:
|
||||
- set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH%
|
||||
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
env:
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
ARCH: amd64
|
||||
|
||||
task:
|
||||
freebsd_instance:
|
||||
matrix:
|
||||
image: freebsd-12-0-release-amd64
|
||||
image: freebsd-11-2-release-amd64
|
||||
install_script:
|
||||
- sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf
|
||||
- pkg upgrade -y
|
||||
- pkg install -y autoconf gmake
|
||||
script:
|
||||
- autoconf
|
||||
#- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
|
||||
- ./configure
|
||||
- export JFLAG=`sysctl -n kern.smp.cpus`
|
||||
- gmake -j${JFLAG}
|
||||
- gmake -j${JFLAG} tests
|
||||
- gmake check
|
||||
@@ -30,7 +30,6 @@
|
||||
/include/jemalloc/internal/public_namespace.h
|
||||
/include/jemalloc/internal/public_symbols.txt
|
||||
/include/jemalloc/internal/public_unnamespace.h
|
||||
/include/jemalloc/internal/size_classes.h
|
||||
/include/jemalloc/jemalloc.h
|
||||
/include/jemalloc/jemalloc_defs.h
|
||||
/include/jemalloc/jemalloc_macros.h
|
||||
|
||||
Vendored
+72
-33
@@ -11,7 +11,7 @@ matrix:
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
addons: &gcc_multilib
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
@@ -21,6 +21,10 @@ matrix:
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
@@ -37,20 +41,25 @@ matrix:
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
@@ -61,50 +70,39 @@ matrix:
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
addons: *gcc_multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
@@ -115,6 +113,10 @@ matrix:
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
@@ -123,6 +125,10 @@ matrix:
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
@@ -131,6 +137,24 @@ matrix:
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
@@ -143,10 +167,25 @@ matrix:
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
# Development build
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-cache-oblivious --enable-stats --enable-log --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
# --enable-expermental-smallocx:
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-experimental-smallocx --enable-stats --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
|
||||
# Valgrind
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- valgrind
|
||||
|
||||
|
||||
before_script:
|
||||
- autoconf
|
||||
- scripts/gen_travis.py > travis_script && diff .travis.yml travis_script
|
||||
- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
|
||||
- make -j3
|
||||
- make -j3 tests
|
||||
|
||||
Vendored
+2
-2
@@ -1,10 +1,10 @@
|
||||
Unless otherwise specified, files in the jemalloc source distribution are
|
||||
subject to the following license:
|
||||
--------------------------------------------------------------------------------
|
||||
Copyright (C) 2002-2018 Jason Evans <jasone@canonware.com>.
|
||||
Copyright (C) 2002-present Jason Evans <jasone@canonware.com>.
|
||||
All rights reserved.
|
||||
Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved.
|
||||
Copyright (C) 2009-2018 Facebook, Inc. All rights reserved.
|
||||
Copyright (C) 2009-present Facebook, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Vendored
+137
-1
@@ -4,7 +4,143 @@ brevity. Much more detail can be found in the git revision history:
|
||||
|
||||
https://github.com/jemalloc/jemalloc
|
||||
|
||||
* 5.1.0 (May 4th, 2018)
|
||||
* 5.2.1 (August 5, 2019)
|
||||
|
||||
This release is primarily about Windows. A critical virtual memory leak is
|
||||
resolved on all Windows platforms. The regression was present in all releases
|
||||
since 5.0.0.
|
||||
|
||||
Bug fixes:
|
||||
- Fix a severe virtual memory leak on Windows. This regression was first
|
||||
released in 5.0.0. (@Ignition, @j0t, @frederik-h, @davidtgoldblatt,
|
||||
@interwq)
|
||||
- Fix size 0 handling in posix_memalign(). This regression was first released
|
||||
in 5.2.0. (@interwq)
|
||||
- Fix the prof_log unit test which may observe unexpected backtraces from
|
||||
compiler optimizations. The test was first added in 5.2.0. (@marxin,
|
||||
@gnzlbg, @interwq)
|
||||
- Fix the declaration of the extent_avail tree. This regression was first
|
||||
released in 5.1.0. (@zoulasc)
|
||||
- Fix an incorrect reference in jeprof. This functionality was first released
|
||||
in 3.0.0. (@prehistoric-penguin)
|
||||
- Fix an assertion on the deallocation fast-path. This regression was first
|
||||
released in 5.2.0. (@yinan1048576)
|
||||
- Fix the TLS_MODEL attribute in headers. This regression was first released
|
||||
in 5.0.0. (@zoulasc, @interwq)
|
||||
|
||||
Optimizations and refactors:
|
||||
- Implement opt.retain on Windows and enable by default on 64-bit. (@interwq,
|
||||
@davidtgoldblatt)
|
||||
- Optimize away a branch on the operator delete[] path. (@mgrice)
|
||||
- Add format annotation to the format generator function. (@zoulasc)
|
||||
- Refactor and improve the size class header generation. (@yinan1048576)
|
||||
- Remove best fit. (@djwatson)
|
||||
- Avoid blocking on background thread locks for stats. (@oranagra, @interwq)
|
||||
|
||||
* 5.2.0 (April 2, 2019)
|
||||
|
||||
This release includes a few notable improvements, which are summarized below:
|
||||
1) improved fast-path performance from the optimizations by @djwatson; 2)
|
||||
reduced virtual memory fragmentation and metadata usage; and 3) bug fixes on
|
||||
setting the number of background threads. In addition, peak / spike memory
|
||||
usage is improved with certain allocation patterns. As usual, the release and
|
||||
prior dev versions have gone through large-scale production testing.
|
||||
|
||||
New features:
|
||||
- Implement oversize_threshold, which uses a dedicated arena for allocations
|
||||
crossing the specified threshold to reduce fragmentation. (@interwq)
|
||||
- Add extents usage information to stats. (@tyleretzel)
|
||||
- Log time information for sampled allocations. (@tyleretzel)
|
||||
- Support 0 size in sdallocx. (@djwatson)
|
||||
- Output rate for certain counters in malloc_stats. (@zinoale)
|
||||
- Add configure option --enable-readlinkat, which allows the use of readlinkat
|
||||
over readlink. (@davidtgoldblatt)
|
||||
- Add configure options --{enable,disable}-{static,shared} to allow not
|
||||
building unwanted libraries. (@Ericson2314)
|
||||
- Add configure option --disable-libdl to enable fully static builds.
|
||||
(@interwq)
|
||||
- Add mallctl interfaces:
|
||||
+ opt.oversize_threshold (@interwq)
|
||||
+ stats.arenas.<i>.extent_avail (@tyleretzel)
|
||||
+ stats.arenas.<i>.extents.<j>.n{dirty,muzzy,retained} (@tyleretzel)
|
||||
+ stats.arenas.<i>.extents.<j>.{dirty,muzzy,retained}_bytes
|
||||
(@tyleretzel)
|
||||
|
||||
Portability improvements:
|
||||
- Update MSVC builds. (@maksqwe, @rustyx)
|
||||
- Workaround a compiler optimizer bug on s390x. (@rkmisra)
|
||||
- Make use of pthread_set_name_np(3) on FreeBSD. (@trasz)
|
||||
- Implement malloc_getcpu() to enable percpu_arena for windows. (@santagada)
|
||||
- Link against -pthread instead of -lpthread. (@paravoid)
|
||||
- Make background_thread not dependent on libdl. (@interwq)
|
||||
- Add stringify to fix a linker directive issue on MSVC. (@daverigby)
|
||||
- Detect and fall back when 8-bit atomics are unavailable. (@interwq)
|
||||
- Fall back to the default pthread_create if dlsym(3) fails. (@interwq)
|
||||
|
||||
Optimizations and refactors:
|
||||
- Refactor the TSD module. (@davidtgoldblatt)
|
||||
- Avoid taking extents_muzzy mutex when muzzy is disabled. (@interwq)
|
||||
- Avoid taking large_mtx for auto arenas on the tcache flush path. (@interwq)
|
||||
- Optimize ixalloc by avoiding a size lookup. (@interwq)
|
||||
- Implement opt.oversize_threshold which uses a dedicated arena for requests
|
||||
crossing the threshold, also eagerly purges the oversize extents. Default
|
||||
the threshold to 8 MiB. (@interwq)
|
||||
- Clean compilation with -Wextra. (@gnzlbg, @jasone)
|
||||
- Refactor the size class module. (@davidtgoldblatt)
|
||||
- Refactor the stats emitter. (@tyleretzel)
|
||||
- Optimize pow2_ceil. (@rkmisra)
|
||||
- Avoid runtime detection of lazy purging on FreeBSD. (@trasz)
|
||||
- Optimize mmap(2) alignment handling on FreeBSD. (@trasz)
|
||||
- Improve error handling for THP state initialization. (@jsteemann)
|
||||
- Rework the malloc() fast path. (@djwatson)
|
||||
- Rework the free() fast path. (@djwatson)
|
||||
- Refactor and optimize the tcache fill / flush paths. (@djwatson)
|
||||
- Optimize sync / lwsync on PowerPC. (@chmeeedalf)
|
||||
- Bypass extent_dalloc() when retain is enabled. (@interwq)
|
||||
- Optimize the locking on large deallocation. (@interwq)
|
||||
- Reduce the number of pages committed from sanity checking in debug build.
|
||||
(@trasz, @interwq)
|
||||
- Deprecate OSSpinLock. (@interwq)
|
||||
- Lower the default number of background threads to 4 (when the feature
|
||||
is enabled). (@interwq)
|
||||
- Optimize the trylock spin wait. (@djwatson)
|
||||
- Use arena index for arena-matching checks. (@interwq)
|
||||
- Avoid forced decay on thread termination when using background threads.
|
||||
(@interwq)
|
||||
- Disable muzzy decay by default. (@djwatson, @interwq)
|
||||
- Only initialize libgcc unwinder when profiling is enabled. (@paravoid,
|
||||
@interwq)
|
||||
|
||||
Bug fixes (all only relevant to jemalloc 5.x):
|
||||
- Fix background thread index issues with max_background_threads. (@djwatson,
|
||||
@interwq)
|
||||
- Fix stats output for opt.lg_extent_max_active_fit. (@interwq)
|
||||
- Fix opt.prof_prefix initialization. (@davidtgoldblatt)
|
||||
- Properly trigger decay on tcache destroy. (@interwq, @amosbird)
|
||||
- Fix tcache.flush. (@interwq)
|
||||
- Detect whether explicit extent zero out is necessary with huge pages or
|
||||
custom extent hooks, which may change the purge semantics. (@interwq)
|
||||
- Fix a side effect caused by extent_max_active_fit combined with decay-based
|
||||
purging, where freed extents can accumulate and not be reused for an
|
||||
extended period of time. (@interwq, @mpghf)
|
||||
- Fix a missing unlock on extent register error handling. (@zoulasc)
|
||||
|
||||
Testing:
|
||||
- Simplify the Travis script output. (@gnzlbg)
|
||||
- Update the test scripts for FreeBSD. (@devnexen)
|
||||
- Add unit tests for the producer-consumer pattern. (@interwq)
|
||||
- Add Cirrus-CI config for FreeBSD builds. (@jasone)
|
||||
- Add size-matching sanity checks on tcache flush. (@davidtgoldblatt,
|
||||
@interwq)
|
||||
|
||||
Incompatible changes:
|
||||
- Remove --with-lg-page-sizes. (@davidtgoldblatt)
|
||||
|
||||
Documentation:
|
||||
- Attempt to build docs by default, however skip doc building when xsltproc
|
||||
is missing. (@interwq, @cmuellner)
|
||||
|
||||
* 5.1.0 (May 4, 2018)
|
||||
|
||||
This release is primarily about fine-tuning, ranging from several new features
|
||||
to numerous notable performance and portability enhancements. The release and
|
||||
|
||||
Vendored
+5
-7
@@ -221,13 +221,6 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
system page size may change between configuration and execution, e.g. when
|
||||
cross compiling.
|
||||
|
||||
* `--with-lg-page-sizes=<lg-page-sizes>`
|
||||
|
||||
Specify the comma-separated base 2 logs of the page sizes to support. This
|
||||
option may be useful when cross compiling in combination with
|
||||
`--with-lg-page`, but its primary use case is for integration with FreeBSD's
|
||||
libc, wherein jemalloc is embedded.
|
||||
|
||||
* `--with-lg-hugepage=<lg-hugepage>`
|
||||
|
||||
Specify the base 2 log of the system huge page size. This option is useful
|
||||
@@ -276,6 +269,11 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
in the same process, which will almost certainly result in confusing runtime
|
||||
crashes if pointers leak from one implementation to the other.
|
||||
|
||||
* `--disable-libdl`
|
||||
|
||||
Disable the usage of libdl, namely dlsym(3) which is required by the lazy
|
||||
lock option. This can allow building static binaries.
|
||||
|
||||
The following environment variables (not a definitive list) impact configure's
|
||||
behavior:
|
||||
|
||||
|
||||
Vendored
+62
-8
@@ -47,6 +47,7 @@ REV := @rev@
|
||||
install_suffix := @install_suffix@
|
||||
ABI := @abi@
|
||||
XSLTPROC := @XSLTPROC@
|
||||
XSLROOT := @XSLROOT@
|
||||
AUTOCONF := @AUTOCONF@
|
||||
_RPATH = @RPATH@
|
||||
RPATH = $(if $(1),$(call _RPATH,$(1)))
|
||||
@@ -55,8 +56,12 @@ cfghdrs_out := @cfghdrs_out@
|
||||
cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@)
|
||||
cfgoutputs_out := @cfgoutputs_out@
|
||||
enable_autogen := @enable_autogen@
|
||||
enable_doc := @enable_doc@
|
||||
enable_shared := @enable_shared@
|
||||
enable_static := @enable_static@
|
||||
enable_prof := @enable_prof@
|
||||
enable_zone_allocator := @enable_zone_allocator@
|
||||
enable_experimental_smallocx := @enable_experimental_smallocx@
|
||||
MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF
|
||||
link_whole_archive := @link_whole_archive@
|
||||
DSO_LDFLAGS = @DSO_LDFLAGS@
|
||||
@@ -102,7 +107,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \
|
||||
$(srcroot)src/extent_dss.c \
|
||||
$(srcroot)src/extent_mmap.c \
|
||||
$(srcroot)src/hash.c \
|
||||
$(srcroot)src/hooks.c \
|
||||
$(srcroot)src/hook.c \
|
||||
$(srcroot)src/large.c \
|
||||
$(srcroot)src/log.c \
|
||||
$(srcroot)src/malloc_io.c \
|
||||
@@ -113,9 +118,12 @@ C_SRCS := $(srcroot)src/jemalloc.c \
|
||||
$(srcroot)src/prng.c \
|
||||
$(srcroot)src/prof.c \
|
||||
$(srcroot)src/rtree.c \
|
||||
$(srcroot)src/safety_check.c \
|
||||
$(srcroot)src/stats.c \
|
||||
$(srcroot)src/sc.c \
|
||||
$(srcroot)src/sz.c \
|
||||
$(srcroot)src/tcache.c \
|
||||
$(srcroot)src/test_hooks.c \
|
||||
$(srcroot)src/ticker.c \
|
||||
$(srcroot)src/tsd.c \
|
||||
$(srcroot)src/witness.c
|
||||
@@ -165,14 +173,18 @@ TESTS_UNIT := \
|
||||
$(srcroot)test/unit/background_thread_enable.c \
|
||||
$(srcroot)test/unit/base.c \
|
||||
$(srcroot)test/unit/bitmap.c \
|
||||
$(srcroot)test/unit/bit_util.c \
|
||||
$(srcroot)test/unit/binshard.c \
|
||||
$(srcroot)test/unit/ckh.c \
|
||||
$(srcroot)test/unit/decay.c \
|
||||
$(srcroot)test/unit/div.c \
|
||||
$(srcroot)test/unit/emitter.c \
|
||||
$(srcroot)test/unit/extent_quantize.c \
|
||||
$(srcroot)test/unit/extent_util.c \
|
||||
$(srcroot)test/unit/fork.c \
|
||||
$(srcroot)test/unit/hash.c \
|
||||
$(srcroot)test/unit/hooks.c \
|
||||
$(srcroot)test/unit/hook.c \
|
||||
$(srcroot)test/unit/huge.c \
|
||||
$(srcroot)test/unit/junk.c \
|
||||
$(srcroot)test/unit/junk_alloc.c \
|
||||
$(srcroot)test/unit/junk_free.c \
|
||||
@@ -190,6 +202,7 @@ TESTS_UNIT := \
|
||||
$(srcroot)test/unit/prof_active.c \
|
||||
$(srcroot)test/unit/prof_gdump.c \
|
||||
$(srcroot)test/unit/prof_idump.c \
|
||||
$(srcroot)test/unit/prof_log.c \
|
||||
$(srcroot)test/unit/prof_reset.c \
|
||||
$(srcroot)test/unit/prof_tctx.c \
|
||||
$(srcroot)test/unit/prof_thread_name.c \
|
||||
@@ -198,13 +211,17 @@ TESTS_UNIT := \
|
||||
$(srcroot)test/unit/rb.c \
|
||||
$(srcroot)test/unit/retained.c \
|
||||
$(srcroot)test/unit/rtree.c \
|
||||
$(srcroot)test/unit/safety_check.c \
|
||||
$(srcroot)test/unit/seq.c \
|
||||
$(srcroot)test/unit/SFMT.c \
|
||||
$(srcroot)test/unit/sc.c \
|
||||
$(srcroot)test/unit/size_classes.c \
|
||||
$(srcroot)test/unit/slab.c \
|
||||
$(srcroot)test/unit/smoothstep.c \
|
||||
$(srcroot)test/unit/spin.c \
|
||||
$(srcroot)test/unit/stats.c \
|
||||
$(srcroot)test/unit/stats_print.c \
|
||||
$(srcroot)test/unit/test_hooks.c \
|
||||
$(srcroot)test/unit/ticker.c \
|
||||
$(srcroot)test/unit/nstime.c \
|
||||
$(srcroot)test/unit/tsd.c \
|
||||
@@ -217,15 +234,21 @@ endif
|
||||
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
|
||||
$(srcroot)test/integration/allocated.c \
|
||||
$(srcroot)test/integration/extent.c \
|
||||
$(srcroot)test/integration/malloc.c \
|
||||
$(srcroot)test/integration/mallocx.c \
|
||||
$(srcroot)test/integration/MALLOCX_ARENA.c \
|
||||
$(srcroot)test/integration/overflow.c \
|
||||
$(srcroot)test/integration/posix_memalign.c \
|
||||
$(srcroot)test/integration/rallocx.c \
|
||||
$(srcroot)test/integration/sdallocx.c \
|
||||
$(srcroot)test/integration/slab_sizes.c \
|
||||
$(srcroot)test/integration/thread_arena.c \
|
||||
$(srcroot)test/integration/thread_tcache_enabled.c \
|
||||
$(srcroot)test/integration/xallocx.c
|
||||
ifeq (@enable_experimental_smallocx@, 1)
|
||||
TESTS_INTEGRATION += \
|
||||
$(srcroot)test/integration/smallocx.c
|
||||
endif
|
||||
ifeq (@enable_cxx@, 1)
|
||||
CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp
|
||||
TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp
|
||||
@@ -233,7 +256,9 @@ else
|
||||
CPP_SRCS :=
|
||||
TESTS_INTEGRATION_CPP :=
|
||||
endif
|
||||
TESTS_STRESS := $(srcroot)test/stress/microbench.c
|
||||
TESTS_STRESS := $(srcroot)test/stress/microbench.c \
|
||||
$(srcroot)test/stress/hookbench.c
|
||||
|
||||
|
||||
TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS)
|
||||
|
||||
@@ -274,10 +299,24 @@ all: build_lib
|
||||
dist: build_doc
|
||||
|
||||
$(objroot)doc/%.html : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/html.xsl
|
||||
ifneq ($(XSLROOT),)
|
||||
$(XSLTPROC) -o $@ $(objroot)doc/html.xsl $<
|
||||
else
|
||||
ifeq ($(wildcard $(DOCS_HTML)),)
|
||||
@echo "<p>Missing xsltproc. Doc not built.</p>" > $@
|
||||
endif
|
||||
@echo "Missing xsltproc. "$@" not (re)built."
|
||||
endif
|
||||
|
||||
$(objroot)doc/%.3 : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/manpages.xsl
|
||||
ifneq ($(XSLROOT),)
|
||||
$(XSLTPROC) -o $@ $(objroot)doc/manpages.xsl $<
|
||||
else
|
||||
ifeq ($(wildcard $(DOCS_MAN3)),)
|
||||
@echo "Missing xsltproc. Doc not built." > $@
|
||||
endif
|
||||
@echo "Missing xsltproc. "$@" not (re)built."
|
||||
endif
|
||||
|
||||
build_doc_html: $(DOCS_HTML)
|
||||
build_doc_man: $(DOCS_MAN3)
|
||||
@@ -400,7 +439,7 @@ $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(C_JET_OBJS) $(C_TESTLI
|
||||
|
||||
$(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
|
||||
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -pthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
|
||||
|
||||
$(objroot)test/integration/cpp/%$(EXE): $(objroot)test/integration/cpp/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||
@mkdir -p $(@D)
|
||||
@@ -412,7 +451,12 @@ $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TE
|
||||
|
||||
build_lib_shared: $(DSOS)
|
||||
build_lib_static: $(STATIC_LIBS)
|
||||
build_lib: build_lib_shared build_lib_static
|
||||
ifeq ($(enable_shared), 1)
|
||||
build_lib: build_lib_shared
|
||||
endif
|
||||
ifeq ($(enable_static), 1)
|
||||
build_lib: build_lib_static
|
||||
endif
|
||||
|
||||
install_bin:
|
||||
$(INSTALL) -d $(BINDIR)
|
||||
@@ -449,7 +493,13 @@ install_lib_pc: $(PC)
|
||||
$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \
|
||||
done
|
||||
|
||||
install_lib: install_lib_shared install_lib_static install_lib_pc
|
||||
ifeq ($(enable_shared), 1)
|
||||
install_lib: install_lib_shared
|
||||
endif
|
||||
ifeq ($(enable_static), 1)
|
||||
install_lib: install_lib_static
|
||||
endif
|
||||
install_lib: install_lib_pc
|
||||
|
||||
install_doc_html:
|
||||
$(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix)
|
||||
@@ -465,9 +515,13 @@ install_doc_man:
|
||||
$(INSTALL) -m 644 $$d $(MANDIR)/man3; \
|
||||
done
|
||||
|
||||
install_doc: install_doc_html install_doc_man
|
||||
install_doc: build_doc install_doc_html install_doc_man
|
||||
|
||||
install: install_bin install_include install_lib install_doc
|
||||
install: install_bin install_include install_lib
|
||||
|
||||
ifeq ($(enable_doc), 1)
|
||||
install: install_doc
|
||||
endif
|
||||
|
||||
tests_unit: $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%$(EXE))
|
||||
tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE)) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%$(EXE))
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
5.1.0-0-g0
|
||||
5.2.1-0-g0
|
||||
Vendored
+2
-1
@@ -2909,6 +2909,7 @@ sub RemoveUninterestingFrames {
|
||||
'@JEMALLOC_PREFIX@xallocx',
|
||||
'@JEMALLOC_PREFIX@dallocx',
|
||||
'@JEMALLOC_PREFIX@sdallocx',
|
||||
'@JEMALLOC_PREFIX@sdallocx_noflags',
|
||||
'tc_calloc',
|
||||
'tc_cfree',
|
||||
'tc_malloc',
|
||||
@@ -5366,7 +5367,7 @@ sub GetProcedureBoundaries {
|
||||
my $demangle_flag = "";
|
||||
my $cppfilt_flag = "";
|
||||
my $to_devnull = ">$dev_null 2>&1";
|
||||
if (system(ShellEscape($nm, "--demangle", "image") . $to_devnull) == 0) {
|
||||
if (system(ShellEscape($nm, "--demangle", $image) . $to_devnull) == 0) {
|
||||
# In this mode, we do "nm --demangle <foo>"
|
||||
$demangle_flag = "--demangle";
|
||||
$cppfilt_flag = "";
|
||||
|
||||
Vendored
+623
-231
File diff suppressed because it is too large.
Load diff
Vendored
+251
-139
@@ -175,6 +175,9 @@ fi
|
||||
],
|
||||
XSLROOT="${DEFAULT_XSLROOT}"
|
||||
)
|
||||
if test "x$XSLTPROC" = "xfalse" ; then
|
||||
XSLROOT=""
|
||||
fi
|
||||
AC_SUBST([XSLROOT])
|
||||
|
||||
dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
|
||||
@@ -242,6 +245,7 @@ if test "x$GCC" = "xyes" ; then
|
||||
fi
|
||||
fi
|
||||
JE_CFLAGS_ADD([-Wall])
|
||||
JE_CFLAGS_ADD([-Wextra])
|
||||
JE_CFLAGS_ADD([-Wshorten-64-to-32])
|
||||
JE_CFLAGS_ADD([-Wsign-compare])
|
||||
JE_CFLAGS_ADD([-Wundef])
|
||||
@@ -289,6 +293,7 @@ if test "x$enable_cxx" = "x1" ; then
|
||||
AX_CXX_COMPILE_STDCXX([14], [noext], [optional])
|
||||
if test "x${HAVE_CXX14}" = "x1" ; then
|
||||
JE_CXXFLAGS_ADD([-Wall])
|
||||
JE_CXXFLAGS_ADD([-Wextra])
|
||||
JE_CXXFLAGS_ADD([-g3])
|
||||
|
||||
SAVED_LIBS="${LIBS}"
|
||||
@@ -512,7 +517,7 @@ CTARGET='-o $@'
|
||||
LDTARGET='-o $@'
|
||||
TEST_LD_MODE=
|
||||
EXTRA_LDFLAGS=
|
||||
ARFLAGS='crus'
|
||||
ARFLAGS='crs'
|
||||
AROUT=' $@'
|
||||
CC_MM=1
|
||||
|
||||
@@ -536,6 +541,66 @@ AC_PROG_NM
|
||||
|
||||
AC_PROG_AWK
|
||||
|
||||
dnl ============================================================================
|
||||
dnl jemalloc version.
|
||||
dnl
|
||||
|
||||
AC_ARG_WITH([version],
|
||||
[AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>],
|
||||
[Version string])],
|
||||
[
|
||||
echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null
|
||||
if test $? -eq 0 ; then
|
||||
echo "$with_version" > "${objroot}VERSION"
|
||||
else
|
||||
echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null
|
||||
if test $? -ne 0 ; then
|
||||
AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION])
|
||||
fi
|
||||
fi
|
||||
], [
|
||||
dnl Set VERSION if source directory is inside a git repository.
|
||||
if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then
|
||||
dnl Pattern globs aren't powerful enough to match both single- and
|
||||
dnl double-digit version numbers, so iterate over patterns to support up
|
||||
dnl to version 99.99.99 without any accidental matches.
|
||||
for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \
|
||||
'[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \
|
||||
'[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \
|
||||
'[0-9][0-9].[0-9][0-9].[0-9]' \
|
||||
'[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do
|
||||
(test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null
|
||||
if test $? -eq 0 ; then
|
||||
mv "${objroot}VERSION.tmp" "${objroot}VERSION"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
rm -f "${objroot}VERSION.tmp"
|
||||
])
|
||||
|
||||
if test ! -e "${objroot}VERSION" ; then
|
||||
if test ! -e "${srcroot}VERSION" ; then
|
||||
AC_MSG_RESULT(
|
||||
[Missing VERSION file, and unable to generate it; creating bogus VERSION])
|
||||
echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION"
|
||||
else
|
||||
cp ${srcroot}VERSION ${objroot}VERSION
|
||||
fi
|
||||
fi
|
||||
jemalloc_version=`cat "${objroot}VERSION"`
|
||||
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
|
||||
jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'`
|
||||
jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'`
|
||||
jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'`
|
||||
jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'`
|
||||
AC_SUBST([jemalloc_version])
|
||||
AC_SUBST([jemalloc_version_major])
|
||||
AC_SUBST([jemalloc_version_minor])
|
||||
AC_SUBST([jemalloc_version_bugfix])
|
||||
AC_SUBST([jemalloc_version_nrev])
|
||||
AC_SUBST([jemalloc_version_gid])
|
||||
|
||||
dnl Platform-specific settings. abi and RPATH can probably be determined
|
||||
dnl programmatically, but doing so is error-prone, which makes it generally
|
||||
dnl not worth the trouble.
|
||||
@@ -673,6 +738,9 @@ case "${host}" in
|
||||
libprefix=""
|
||||
SOREV="${so}"
|
||||
PIC_CFLAGS=""
|
||||
if test "${LG_SIZEOF_PTR}" = "3"; then
|
||||
default_retain="1"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([Unsupported operating system: ${host}])
|
||||
@@ -786,6 +854,18 @@ if test "x${je_cv_format_printf}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ])
|
||||
fi
|
||||
|
||||
dnl Check for format_arg(...) attribute support.
|
||||
JE_CFLAGS_SAVE()
|
||||
JE_CFLAGS_ADD([-Werror])
|
||||
JE_CFLAGS_ADD([-herror_on_warning])
|
||||
JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>],
|
||||
[const char * __attribute__((__format_arg__(1))) foo(const char *format);],
|
||||
[je_cv_format_arg])
|
||||
JE_CFLAGS_RESTORE()
|
||||
if test "x${je_cv_format_arg}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_ARG], [ ])
|
||||
fi
|
||||
|
||||
dnl Support optional additions to rpath.
|
||||
AC_ARG_WITH([rpath],
|
||||
[AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
|
||||
@@ -816,6 +896,49 @@ AC_PROG_RANLIB
|
||||
AC_PATH_PROG([LD], [ld], [false], [$PATH])
|
||||
AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH])
|
||||
|
||||
dnl Enable documentation
|
||||
AC_ARG_ENABLE([doc],
|
||||
[AS_HELP_STRING([--enable-documentation], [Build documentation])],
|
||||
if test "x$enable_doc" = "xno" ; then
|
||||
enable_doc="0"
|
||||
else
|
||||
enable_doc="1"
|
||||
fi
|
||||
,
|
||||
enable_doc="1"
|
||||
)
|
||||
AC_SUBST([enable_doc])
|
||||
|
||||
dnl Enable shared libs
|
||||
AC_ARG_ENABLE([shared],
|
||||
[AS_HELP_STRING([--enable-shared], [Build shared libaries])],
|
||||
if test "x$enable_shared" = "xno" ; then
|
||||
enable_shared="0"
|
||||
else
|
||||
enable_shared="1"
|
||||
fi
|
||||
,
|
||||
enable_shared="1"
|
||||
)
|
||||
AC_SUBST([enable_shared])
|
||||
|
||||
dnl Enable static libs
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static], [Build static libaries])],
|
||||
if test "x$enable_static" = "xno" ; then
|
||||
enable_static="0"
|
||||
else
|
||||
enable_static="1"
|
||||
fi
|
||||
,
|
||||
enable_static="1"
|
||||
)
|
||||
AC_SUBST([enable_static])
|
||||
|
||||
if test "$enable_shared$enable_static" = "00" ; then
|
||||
AC_MSG_ERROR([Please enable one of shared or static builds])
|
||||
fi
|
||||
|
||||
dnl Perform no name mangling by default.
|
||||
AC_ARG_WITH([mangling],
|
||||
[AS_HELP_STRING([--with-mangling=<map>], [Mangle symbols in <map>])],
|
||||
@@ -848,7 +971,7 @@ AC_ARG_WITH([export],
|
||||
fi]
|
||||
)
|
||||
|
||||
public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
|
||||
public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
|
||||
dnl Check for additional platform-specific public API functions.
|
||||
AC_CHECK_FUNC([memalign],
|
||||
[AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ])
|
||||
@@ -966,7 +1089,6 @@ cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.sh"
|
||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh"
|
||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh"
|
||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh"
|
||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/size_classes.sh"
|
||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh"
|
||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh"
|
||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh"
|
||||
@@ -979,7 +1101,6 @@ cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols_jet.awk"
|
||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt"
|
||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h"
|
||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h"
|
||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/size_classes.h"
|
||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h"
|
||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h"
|
||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h"
|
||||
@@ -991,6 +1112,10 @@ cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.i
|
||||
cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in"
|
||||
cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in"
|
||||
|
||||
dnl ============================================================================
|
||||
dnl jemalloc build options.
|
||||
dnl
|
||||
|
||||
dnl Do not compile with debugging by default.
|
||||
AC_ARG_ENABLE([debug],
|
||||
[AS_HELP_STRING([--enable-debug],
|
||||
@@ -1043,6 +1168,22 @@ if test "x$enable_stats" = "x1" ; then
|
||||
fi
|
||||
AC_SUBST([enable_stats])
|
||||
|
||||
dnl Do not enable smallocx by default.
|
||||
AC_ARG_ENABLE([experimental_smallocx],
|
||||
[AS_HELP_STRING([--enable-experimental-smallocx], [Enable experimental smallocx API])],
|
||||
[if test "x$enable_experimental_smallocx" = "xno" ; then
|
||||
enable_experimental_smallocx="0"
|
||||
else
|
||||
enable_experimental_smallocx="1"
|
||||
fi
|
||||
],
|
||||
[enable_experimental_smallocx="0"]
|
||||
)
|
||||
if test "x$enable_experimental_smallocx" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_EXPERIMENTAL_SMALLOCX_API])
|
||||
fi
|
||||
AC_SUBST([enable_experimental_smallocx])
|
||||
|
||||
dnl Do not enable profiling by default.
|
||||
AC_ARG_ENABLE([prof],
|
||||
[AS_HELP_STRING([--enable-prof], [Enable allocation profiling])],
|
||||
@@ -1277,6 +1418,38 @@ if test "x$enable_log" = "x1" ; then
|
||||
fi
|
||||
AC_SUBST([enable_log])
|
||||
|
||||
dnl Do not use readlinkat by default
|
||||
AC_ARG_ENABLE([readlinkat],
|
||||
[AS_HELP_STRING([--enable-readlinkat], [Use readlinkat over readlink])],
|
||||
[if test "x$enable_readlinkat" = "xno" ; then
|
||||
enable_readlinkat="0"
|
||||
else
|
||||
enable_readlinkat="1"
|
||||
fi
|
||||
],
|
||||
[enable_readlinkat="0"]
|
||||
)
|
||||
if test "x$enable_readlinkat" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_READLINKAT], [ ])
|
||||
fi
|
||||
AC_SUBST([enable_readlinkat])
|
||||
|
||||
dnl Avoid extra safety checks by default
|
||||
AC_ARG_ENABLE([opt-safety-checks],
|
||||
[AS_HELP_STRING([--enable-opt-safety-checks],
|
||||
[Perform certain low-overhead checks, even in opt mode])],
|
||||
[if test "x$enable_opt_safety_checks" = "xno" ; then
|
||||
enable_opt_safety_checks="0"
|
||||
else
|
||||
enable_opt_safety_checks="1"
|
||||
fi
|
||||
],
|
||||
[enable_opt_safety_checks="0"]
|
||||
)
|
||||
if test "x$enable_opt_safety_checks" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_OPT_SAFETY_CHECKS], [ ])
|
||||
fi
|
||||
AC_SUBST([enable_opt_safety_checks])
|
||||
|
||||
JE_COMPILABLE([a program using __builtin_unreachable], [
|
||||
void foo (void) {
|
||||
@@ -1333,6 +1506,21 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
JE_COMPILABLE([a program using __builtin_popcountl], [
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
], [
|
||||
{
|
||||
int rv = __builtin_popcountl(0x08);
|
||||
printf("%d\n", rv);
|
||||
}
|
||||
], [je_cv_gcc_builtin_popcountl])
|
||||
if test "x${je_cv_gcc_builtin_popcountl}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNT], [__builtin_popcount])
|
||||
AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNTL], [__builtin_popcountl])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH([lg_quantum],
|
||||
[AS_HELP_STRING([--with-lg-quantum=<lg-quantum>],
|
||||
[Base 2 log of minimum allocation alignment])],
|
||||
@@ -1430,70 +1618,20 @@ if test "x${LG_PAGE}" != "xundefined" -a \
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}])
|
||||
|
||||
AC_ARG_WITH([lg_page_sizes],
|
||||
[AS_HELP_STRING([--with-lg-page-sizes=<lg-page-sizes>],
|
||||
[Base 2 logs of system page sizes to support])],
|
||||
[LG_PAGE_SIZES="$with_lg_page_sizes"], [LG_PAGE_SIZES="$LG_PAGE"])
|
||||
|
||||
dnl ============================================================================
|
||||
dnl jemalloc configuration.
|
||||
dnl
|
||||
|
||||
AC_ARG_WITH([version],
|
||||
[AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>],
|
||||
[Version string])],
|
||||
[
|
||||
echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null
|
||||
if test $? -eq 0 ; then
|
||||
echo "$with_version" > "${objroot}VERSION"
|
||||
else
|
||||
echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null
|
||||
if test $? -ne 0 ; then
|
||||
AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION])
|
||||
fi
|
||||
fi
|
||||
], [
|
||||
dnl Set VERSION if source directory is inside a git repository.
|
||||
if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then
|
||||
dnl Pattern globs aren't powerful enough to match both single- and
|
||||
dnl double-digit version numbers, so iterate over patterns to support up
|
||||
dnl to version 99.99.99 without any accidental matches.
|
||||
for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \
|
||||
'[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \
|
||||
'[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \
|
||||
'[0-9][0-9].[0-9][0-9].[0-9]' \
|
||||
'[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do
|
||||
(test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null
|
||||
if test $? -eq 0 ; then
|
||||
mv "${objroot}VERSION.tmp" "${objroot}VERSION"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
rm -f "${objroot}VERSION.tmp"
|
||||
])
|
||||
|
||||
if test ! -e "${objroot}VERSION" ; then
|
||||
if test ! -e "${srcroot}VERSION" ; then
|
||||
AC_MSG_RESULT(
|
||||
[Missing VERSION file, and unable to generate it; creating bogus VERSION])
|
||||
echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION"
|
||||
else
|
||||
cp ${srcroot}VERSION ${objroot}VERSION
|
||||
fi
|
||||
dnl Enable libdl by default.
|
||||
AC_ARG_ENABLE([libdl],
|
||||
[AS_HELP_STRING([--disable-libdl],
|
||||
[Do not use libdl])],
|
||||
[if test "x$enable_libdl" = "xno" ; then
|
||||
enable_libdl="0"
|
||||
else
|
||||
enable_libdl="1"
|
||||
fi
|
||||
jemalloc_version=`cat "${objroot}VERSION"`
|
||||
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
|
||||
jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'`
|
||||
jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'`
|
||||
jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'`
|
||||
jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'`
|
||||
AC_SUBST([jemalloc_version])
|
||||
AC_SUBST([jemalloc_version_major])
|
||||
AC_SUBST([jemalloc_version_minor])
|
||||
AC_SUBST([jemalloc_version_bugfix])
|
||||
AC_SUBST([jemalloc_version_nrev])
|
||||
AC_SUBST([jemalloc_version_gid])
|
||||
],
|
||||
[enable_libdl="1"]
|
||||
)
|
||||
AC_SUBST([libdl])
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Configure pthreads.
|
||||
@@ -1503,20 +1641,26 @@ if test "x$abi" != "xpecoff" ; then
|
||||
AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])])
|
||||
dnl Some systems may embed pthreads functionality in libc; check for libpthread
|
||||
dnl first, but try libc too before failing.
|
||||
AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -lpthread)],
|
||||
AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -pthread)],
|
||||
[AC_SEARCH_LIBS([pthread_create], , ,
|
||||
AC_MSG_ERROR([libpthread is missing]))])
|
||||
wrap_syms="${wrap_syms} pthread_create"
|
||||
have_pthread="1"
|
||||
dnl Check if we have dlsym support.
|
||||
have_dlsym="1"
|
||||
AC_CHECK_HEADERS([dlfcn.h],
|
||||
AC_CHECK_FUNC([dlsym], [],
|
||||
[AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"])]),
|
||||
[have_dlsym="0"])
|
||||
if test "x$have_dlsym" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ])
|
||||
|
||||
dnl Check if we have dlsym support.
|
||||
if test "x$enable_libdl" = "x1" ; then
|
||||
have_dlsym="1"
|
||||
AC_CHECK_HEADERS([dlfcn.h],
|
||||
AC_CHECK_FUNC([dlsym], [],
|
||||
[AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"])]),
|
||||
[have_dlsym="0"])
|
||||
if test "x$have_dlsym" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ])
|
||||
fi
|
||||
else
|
||||
have_dlsym="0"
|
||||
fi
|
||||
|
||||
JE_COMPILABLE([pthread_atfork(3)], [
|
||||
#include <pthread.h>
|
||||
], [
|
||||
@@ -1780,6 +1924,19 @@ JE_COMPILABLE([GCC __atomic atomics], [
|
||||
], [je_cv_gcc_atomic_atomics])
|
||||
if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS])
|
||||
|
||||
dnl check for 8-bit atomic support
|
||||
JE_COMPILABLE([GCC 8-bit __atomic atomics], [
|
||||
], [
|
||||
unsigned char x = 0;
|
||||
int val = 1;
|
||||
int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED);
|
||||
int after_add = (int)x;
|
||||
return after_add == 1;
|
||||
], [je_cv_gcc_u8_atomic_atomics])
|
||||
if test "x${je_cv_gcc_u8_atomic_atomics}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_GCC_U8_ATOMIC_ATOMICS])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ============================================================================
|
||||
@@ -1794,12 +1951,24 @@ JE_COMPILABLE([GCC __sync atomics], [
|
||||
], [je_cv_gcc_sync_atomics])
|
||||
if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS])
|
||||
|
||||
dnl check for 8-bit atomic support
|
||||
JE_COMPILABLE([GCC 8-bit __sync atomics], [
|
||||
], [
|
||||
unsigned char x = 0;
|
||||
int before_add = __sync_fetch_and_add(&x, 1);
|
||||
int after_add = (int)x;
|
||||
return (before_add == 0) && (after_add == 1);
|
||||
], [je_cv_gcc_u8_sync_atomics])
|
||||
if test "x${je_cv_gcc_u8_sync_atomics}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_GCC_U8_SYNC_ATOMICS])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Check for atomic(3) operations as provided on Darwin.
|
||||
dnl We need this not for the atomic operations (which are provided above), but
|
||||
dnl rather for the OSSpinLock type it exposes.
|
||||
dnl rather for the OS_unfair_lock type it exposes.
|
||||
|
||||
JE_COMPILABLE([Darwin OSAtomic*()], [
|
||||
#include <libkern/OSAtomic.h>
|
||||
@@ -1870,7 +2039,7 @@ if test "x${je_cv_madvise}" = "xyes" ; then
|
||||
if test "x${je_cv_madv_dontdump}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_MADVISE_DONTDUMP], [ ])
|
||||
fi
|
||||
|
||||
|
||||
dnl Check for madvise(..., MADV_[NO]HUGEPAGE).
|
||||
JE_COMPILABLE([madvise(..., MADV_[[NO]]HUGEPAGE)], [
|
||||
#include <sys/mman.h>
|
||||
@@ -1889,40 +2058,6 @@ case "${host_cpu}" in
|
||||
esac
|
||||
fi
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Check whether __sync_{add,sub}_and_fetch() are available despite
|
||||
dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined.
|
||||
|
||||
AC_DEFUN([JE_SYNC_COMPARE_AND_SWAP_CHECK],[
|
||||
AC_CACHE_CHECK([whether to force $1-bit __sync_{add,sub}_and_fetch()],
|
||||
[je_cv_sync_compare_and_swap_$2],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
||||
#include <stdint.h>
|
||||
],
|
||||
[
|
||||
#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_$2
|
||||
{
|
||||
uint$1_t x$1 = 0;
|
||||
__sync_add_and_fetch(&x$1, 42);
|
||||
__sync_sub_and_fetch(&x$1, 1);
|
||||
}
|
||||
#else
|
||||
#error __GCC_HAVE_SYNC_COMPARE_AND_SWAP_$2 is defined, no need to force
|
||||
#endif
|
||||
])],
|
||||
[je_cv_sync_compare_and_swap_$2=yes],
|
||||
[je_cv_sync_compare_and_swap_$2=no])])
|
||||
|
||||
if test "x${je_cv_sync_compare_and_swap_$2}" = "xyes" ; then
|
||||
AC_DEFINE([JE_FORCE_SYNC_COMPARE_AND_SWAP_$2], [ ])
|
||||
fi
|
||||
])
|
||||
|
||||
if test "x${je_cv_atomic9}" != "xyes" -a "x${je_cv_osatomic}" != "xyes" ; then
|
||||
JE_SYNC_COMPARE_AND_SWAP_CHECK(32, 4)
|
||||
JE_SYNC_COMPARE_AND_SWAP_CHECK(64, 8)
|
||||
fi
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Check for __builtin_clz() and __builtin_clzl().
|
||||
|
||||
@@ -1965,21 +2100,6 @@ if test "x${je_cv_os_unfair_lock}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ])
|
||||
fi
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Check for spinlock(3) operations as provided on Darwin.
|
||||
|
||||
JE_COMPILABLE([Darwin OSSpin*()], [
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <inttypes.h>
|
||||
], [
|
||||
OSSpinLock lock = 0;
|
||||
OSSpinLockLock(&lock);
|
||||
OSSpinLockUnlock(&lock);
|
||||
], [je_cv_osspin])
|
||||
if test "x${je_cv_osspin}" = "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_OSSPIN], [ ])
|
||||
fi
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Darwin-related configuration.
|
||||
|
||||
@@ -2032,9 +2152,7 @@ fi
|
||||
dnl ============================================================================
|
||||
dnl Enable background threads if possible.
|
||||
|
||||
if test "x${have_pthread}" = "x1" -a "x${have_dlsym}" = "x1" \
|
||||
-a "x${je_cv_os_unfair_lock}" != "xyes" \
|
||||
-a "x${je_cv_osspin}" != "xyes" ; then
|
||||
if test "x${have_pthread}" = "x1" -a "x${je_cv_os_unfair_lock}" != "xyes" ; then
|
||||
AC_DEFINE([JEMALLOC_BACKGROUND_THREAD])
|
||||
fi
|
||||
|
||||
@@ -2175,16 +2293,6 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [
|
||||
srcdir="${srcdir}"
|
||||
objroot="${objroot}"
|
||||
])
|
||||
AC_CONFIG_COMMANDS([include/jemalloc/internal/size_classes.h], [
|
||||
mkdir -p "${objroot}include/jemalloc/internal"
|
||||
"${SHELL}" "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" 3 "${LG_PAGE_SIZES}" 2 > "${objroot}include/jemalloc/internal/size_classes.h"
|
||||
], [
|
||||
SHELL="${SHELL}"
|
||||
srcdir="${srcdir}"
|
||||
objroot="${objroot}"
|
||||
LG_QUANTA="${LG_QUANTA}"
|
||||
LG_PAGE_SIZES="${LG_PAGE_SIZES}"
|
||||
])
|
||||
AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [
|
||||
mkdir -p "${objroot}include/jemalloc"
|
||||
cat "${srcdir}/include/jemalloc/jemalloc_protos.h.in" | sed -e 's/@je_@/jet_/g' > "${objroot}include/jemalloc/jemalloc_protos_jet.h"
|
||||
@@ -2277,9 +2385,13 @@ AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE])
|
||||
AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}])
|
||||
AC_MSG_RESULT([install_suffix : ${install_suffix}])
|
||||
AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}])
|
||||
AC_MSG_RESULT([documentation : ${enable_doc}])
|
||||
AC_MSG_RESULT([shared libs : ${enable_shared}])
|
||||
AC_MSG_RESULT([static libs : ${enable_static}])
|
||||
AC_MSG_RESULT([autogen : ${enable_autogen}])
|
||||
AC_MSG_RESULT([debug : ${enable_debug}])
|
||||
AC_MSG_RESULT([stats : ${enable_stats}])
|
||||
AC_MSG_RESULT([experimetal_smallocx : ${enable_experimental_smallocx}])
|
||||
AC_MSG_RESULT([prof : ${enable_prof}])
|
||||
AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}])
|
||||
AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}])
|
||||
|
||||
Vendored
+156
-22
@@ -424,7 +424,7 @@ for (i = 0; i < nbins; i++) {
|
||||
called repeatedly. General information that never changes during
|
||||
execution can be omitted by specifying <quote>g</quote> as a character
|
||||
within the <parameter>opts</parameter> string. Note that
|
||||
<function>malloc_message()</function> uses the
|
||||
<function>malloc_stats_print()</function> uses the
|
||||
<function>mallctl*()</function> functions internally, so inconsistent
|
||||
statistics can be reported if multiple threads use these functions
|
||||
simultaneously. If <option>--enable-stats</option> is specified during
|
||||
@@ -433,10 +433,11 @@ for (i = 0; i < nbins; i++) {
|
||||
arena statistics, respectively; <quote>b</quote> and <quote>l</quote> can
|
||||
be specified to omit per size class statistics for bins and large objects,
|
||||
respectively; <quote>x</quote> can be specified to omit all mutex
|
||||
statistics. Unrecognized characters are silently ignored. Note that
|
||||
thread caching may prevent some statistics from being completely up to
|
||||
date, since extra locking would be required to merge counters that track
|
||||
thread cache operations.</para>
|
||||
statistics; <quote>e</quote> can be used to omit extent statistics.
|
||||
Unrecognized characters are silently ignored. Note that thread caching
|
||||
may prevent some statistics from being completely up to date, since extra
|
||||
locking would be required to merge counters that track thread cache
|
||||
operations.</para>
|
||||
|
||||
<para>The <function>malloc_usable_size()</function> function
|
||||
returns the usable size of the allocation pointed to by
|
||||
@@ -903,6 +904,23 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.confirm_conf">
|
||||
<term>
|
||||
<mallctl>opt.confirm_conf</mallctl>
|
||||
(<type>bool</type>)
|
||||
<literal>r-</literal>
|
||||
</term>
|
||||
<listitem><para>Confirm-runtime-options-when-program-starts
|
||||
enabled/disabled. If true, the string specified via
|
||||
<option>--with-malloc-conf</option>, the string pointed to by the
|
||||
global variable <varname>malloc_conf</varname>, the <quote>name</quote>
|
||||
of the file referenced by the symbolic link named
|
||||
<filename class="symlink">/etc/malloc.conf</filename>, and the value of
|
||||
the environment variable <envar>MALLOC_CONF</envar>, will be printed in
|
||||
order. Then, each option being set will be individually printed. This
|
||||
option is disabled by default.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.abort_conf">
|
||||
<term>
|
||||
<mallctl>opt.abort_conf</mallctl>
|
||||
@@ -943,16 +961,19 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
||||
<citerefentry><refentrytitle>munmap</refentrytitle>
|
||||
<manvolnum>2</manvolnum></citerefentry> or equivalent (see <link
|
||||
linkend="stats.retained">stats.retained</link> for related details).
|
||||
This option is disabled by default unless discarding virtual memory is
|
||||
known to trigger
|
||||
platform-specific performance problems, e.g. for [64-bit] Linux, which
|
||||
has a quirk in its virtual memory allocation algorithm that causes
|
||||
semi-permanent VM map holes under normal jemalloc operation. Although
|
||||
<citerefentry><refentrytitle>munmap</refentrytitle>
|
||||
<manvolnum>2</manvolnum></citerefentry> causes issues on 32-bit Linux as
|
||||
well, retaining virtual memory for 32-bit Linux is disabled by default
|
||||
due to the practical possibility of address space exhaustion.
|
||||
</para></listitem>
|
||||
It also makes jemalloc use <citerefentry>
|
||||
<refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum>
|
||||
</citerefentry> or equivalent in a more greedy way, mapping larger
|
||||
chunks in one go. This option is disabled by default unless discarding
|
||||
virtual memory is known to trigger platform-specific performance
|
||||
problems, namely 1) for [64-bit] Linux, which has a quirk in its virtual
|
||||
memory allocation algorithm that causes semi-permanent VM map holes
|
||||
under normal jemalloc operation; and 2) for [64-bit] Windows, which
|
||||
disallows split / merged regions with
|
||||
<parameter><constant>MEM_RELEASE</constant></parameter>. Although the
|
||||
same issues may present on 32-bit platforms as well, retaining virtual
|
||||
memory for 32-bit Linux and Windows is disabled by default due to the
|
||||
practical possibility of address space exhaustion. </para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.dss">
|
||||
@@ -988,6 +1009,24 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
||||
number of CPUs, or one if there is a single CPU.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.oversize_threshold">
|
||||
<term>
|
||||
<mallctl>opt.oversize_threshold</mallctl>
|
||||
(<type>size_t</type>)
|
||||
<literal>r-</literal>
|
||||
</term>
|
||||
<listitem><para>The threshold in bytes of which requests are considered
|
||||
oversize. Allocation requests with greater sizes are fulfilled from a
|
||||
dedicated arena (automatically managed, however not within
|
||||
<literal>narenas</literal>), in order to reduce fragmentation by not
|
||||
mixing huge allocations with small ones. In addition, the decay API
|
||||
guarantees on the extents greater than the specified threshold may be
|
||||
overridden. Note that requests with arena index specified via
|
||||
<constant>MALLOCX_ARENA</constant>, or threads associated with explicit
|
||||
arenas will not be considered. The default threshold is 8MiB. Values
|
||||
not within large size classes disables this feature.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.percpu_arena">
|
||||
<term>
|
||||
<mallctl>opt.percpu_arena</mallctl>
|
||||
@@ -1009,7 +1048,7 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
||||
<varlistentry id="opt.background_thread">
|
||||
<term>
|
||||
<mallctl>opt.background_thread</mallctl>
|
||||
(<type>const bool</type>)
|
||||
(<type>bool</type>)
|
||||
<literal>r-</literal>
|
||||
</term>
|
||||
<listitem><para>Internal background worker threads enabled/disabled.
|
||||
@@ -1024,7 +1063,7 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
||||
<varlistentry id="opt.max_background_threads">
|
||||
<term>
|
||||
<mallctl>opt.max_background_threads</mallctl>
|
||||
(<type>const size_t</type>)
|
||||
(<type>size_t</type>)
|
||||
<literal>r-</literal>
|
||||
</term>
|
||||
<listitem><para>Maximum number of background threads that will be created
|
||||
@@ -1055,7 +1094,11 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
||||
linkend="arena.i.dirty_decay_ms"><mallctl>arena.<i>.dirty_decay_ms</mallctl></link>
|
||||
for related dynamic control options. See <link
|
||||
linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
|
||||
for a description of muzzy pages.</para></listitem>
|
||||
for a description of muzzy pages.for a description of muzzy pages. Note
|
||||
that when the <link
|
||||
linkend="opt.oversize_threshold"><mallctl>oversize_threshold</mallctl></link>
|
||||
feature is enabled, the arenas reserved for oversize requests may have
|
||||
its own default decay settings.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.muzzy_decay_ms">
|
||||
@@ -1763,10 +1806,11 @@ malloc_conf = "xmalloc:true";]]></programlisting>
|
||||
to control allocation for arenas explicitly created via <link
|
||||
linkend="arenas.create"><mallctl>arenas.create</mallctl></link> such
|
||||
that all extents originate from an application-supplied extent allocator
|
||||
(by specifying the custom extent hook functions during arena creation),
|
||||
but the automatically created arenas will have already created extents
|
||||
prior to the application having an opportunity to take over extent
|
||||
allocation.</para>
|
||||
(by specifying the custom extent hook functions during arena creation).
|
||||
However, the API guarantees for the automatically created arenas may be
|
||||
relaxed -- hooks set there may be called in a "best effort" fashion; in
|
||||
addition there may be extents created prior to the application having an
|
||||
opportunity to take over extent allocation.</para>
|
||||
|
||||
<programlisting language="C"><![CDATA[
|
||||
typedef extent_hooks_s extent_hooks_t;
|
||||
@@ -2593,6 +2637,17 @@ struct extent_hooks_s {
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.extent_avail">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.extent_avail</mallctl>
|
||||
(<type>size_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para>Number of allocated (but unused) extent structs in this
|
||||
arena.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.base">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.base</mallctl>
|
||||
@@ -2760,6 +2815,28 @@ struct extent_hooks_s {
|
||||
all bin size classes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.small.nfills">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.small.nfills</mallctl>
|
||||
(<type>uint64_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para>Cumulative number of tcache fills by all small size
|
||||
classes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.small.nflushes">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.small.nflushes</mallctl>
|
||||
(<type>uint64_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para>Cumulative number of tcache flushes by all small size
|
||||
classes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.large.allocated">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.large.allocated</mallctl>
|
||||
@@ -2810,6 +2887,28 @@ struct extent_hooks_s {
|
||||
all large size classes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.large.nfills">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.large.nfills</mallctl>
|
||||
(<type>uint64_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para>Cumulative number of tcache fills by all large size
|
||||
classes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.large.nflushes">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.large.nflushes</mallctl>
|
||||
(<type>uint64_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para>Cumulative number of tcache flushes by all large size
|
||||
classes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.bins.j.nmalloc">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.bins.<j>.nmalloc</mallctl>
|
||||
@@ -2909,6 +3008,17 @@ struct extent_hooks_s {
|
||||
<listitem><para>Current number of slabs.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry id="stats.arenas.i.bins.j.nonfull_slabs">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.bins.<j>.nonfull_slabs</mallctl>
|
||||
(<type>size_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para>Current number of nonfull slabs.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.bins.mutex">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.bins.<j>.mutex.{counter}</mallctl>
|
||||
@@ -2922,6 +3032,30 @@ struct extent_hooks_s {
|
||||
counters</link>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.extents.n">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.extents.<j>.n{extent_type}</mallctl>
|
||||
(<type>size_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para> Number of extents of the given type in this arena in
|
||||
the bucket corresponding to page size index <j>. The extent type
|
||||
is one of dirty, muzzy, or retained.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.extents.bytes">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.extents.<j>.{extent_type}_bytes</mallctl>
|
||||
(<type>size_t</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-stats</option>]
|
||||
</term>
|
||||
<listitem><para> Sum of the bytes managed by extents of the given type
|
||||
in this arena in the bucket corresponding to page size index <j>.
|
||||
The extent type is one of dirty, muzzy, or retained.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="stats.arenas.i.lextents.j.nmalloc">
|
||||
<term>
|
||||
<mallctl>stats.arenas.<i>.lextents.<j>.nmalloc</mallctl>
|
||||
|
||||
+18
-8
@@ -3,8 +3,8 @@
|
||||
|
||||
#include "jemalloc/internal/bin.h"
|
||||
#include "jemalloc/internal/extent_dss.h"
|
||||
#include "jemalloc/internal/hook.h"
|
||||
#include "jemalloc/internal/pages.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
|
||||
extern ssize_t opt_dirty_decay_ms;
|
||||
@@ -16,13 +16,17 @@ extern const char *percpu_arena_mode_names[];
|
||||
extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS];
|
||||
extern malloc_mutex_t arenas_lock;
|
||||
|
||||
extern size_t opt_oversize_threshold;
|
||||
extern size_t oversize_threshold;
|
||||
|
||||
void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena,
|
||||
unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms,
|
||||
ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy);
|
||||
void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
||||
bin_stats_t *bstats, arena_stats_large_t *lstats);
|
||||
bin_stats_t *bstats, arena_stats_large_t *lstats,
|
||||
arena_stats_extents_t *estats);
|
||||
void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena,
|
||||
extent_hooks_t **r_extent_hooks, extent_t *extent);
|
||||
#ifdef JEMALLOC_JET
|
||||
@@ -56,16 +60,17 @@ void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size,
|
||||
szind_t ind, bool zero);
|
||||
void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||
size_t alignment, bool zero, tcache_t *tcache);
|
||||
void arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize);
|
||||
void arena_prof_promote(tsdn_t *tsdn, void *ptr, size_t usize);
|
||||
void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
||||
bool slow_path);
|
||||
void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena,
|
||||
extent_t *extent, void *ptr);
|
||||
void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
||||
szind_t binind, extent_t *extent, void *ptr);
|
||||
void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
|
||||
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||
size_t extra, bool zero);
|
||||
size_t extra, bool zero, size_t *newsize);
|
||||
void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||
size_t size, size_t alignment, bool zero, tcache_t *tcache);
|
||||
size_t size, size_t alignment, bool zero, tcache_t *tcache,
|
||||
hook_ralloc_args_t *hook_args);
|
||||
dss_prec_t arena_dss_prec_get(arena_t *arena);
|
||||
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
|
||||
ssize_t arena_dirty_decay_ms_default_get(void);
|
||||
@@ -79,7 +84,12 @@ void arena_nthreads_inc(arena_t *arena, bool internal);
|
||||
void arena_nthreads_dec(arena_t *arena, bool internal);
|
||||
size_t arena_extent_sn_next(arena_t *arena);
|
||||
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
||||
void arena_boot(void);
|
||||
bool arena_init_huge(void);
|
||||
bool arena_is_huge(unsigned arena_ind);
|
||||
arena_t *arena_choose_huge(tsd_t *tsd);
|
||||
bin_t *arena_bin_choose_lock(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
||||
unsigned *binshard);
|
||||
void arena_boot(sc_data_t *sc_data);
|
||||
void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork1(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork2(tsdn_t *tsdn, arena_t *arena);
|
||||
|
||||
+115
-42
@@ -4,10 +4,36 @@
|
||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/rtree.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/sc.h"
|
||||
#include "jemalloc/internal/sz.h"
|
||||
#include "jemalloc/internal/ticker.h"
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE bool
|
||||
arena_has_default_hooks(arena_t *arena) {
|
||||
return (extent_hooks_get(arena) == &extent_hooks_default);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE arena_t *
|
||||
arena_choose_maybe_huge(tsd_t *tsd, arena_t *arena, size_t size) {
|
||||
if (arena != NULL) {
|
||||
return arena;
|
||||
}
|
||||
|
||||
/*
|
||||
* For huge allocations, use the dedicated huge arena if both are true:
|
||||
* 1) is using auto arena selection (i.e. arena == NULL), and 2) the
|
||||
* thread is not assigned to a manual arena.
|
||||
*/
|
||||
if (unlikely(size >= oversize_threshold)) {
|
||||
arena_t *tsd_arena = tsd_arena_get(tsd);
|
||||
if (tsd_arena == NULL || arena_is_auto(tsd_arena)) {
|
||||
return arena_choose_huge(tsd);
|
||||
}
|
||||
}
|
||||
|
||||
return arena_choose(tsd, NULL);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE prof_tctx_t *
|
||||
arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
|
||||
cassert(config_prof);
|
||||
@@ -28,7 +54,7 @@ arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, UNUSED size_t usize,
|
||||
arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize,
|
||||
alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) {
|
||||
cassert(config_prof);
|
||||
assert(ptr != NULL);
|
||||
@@ -47,7 +73,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, UNUSED size_t usize,
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, UNUSED prof_tctx_t *tctx) {
|
||||
arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) {
|
||||
cassert(config_prof);
|
||||
assert(ptr != NULL);
|
||||
|
||||
@@ -57,6 +83,32 @@ arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, UNUSED prof_tctx_t *tctx) {
|
||||
large_prof_tctx_reset(tsdn, extent);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE nstime_t
|
||||
arena_prof_alloc_time_get(tsdn_t *tsdn, const void *ptr,
|
||||
alloc_ctx_t *alloc_ctx) {
|
||||
cassert(config_prof);
|
||||
assert(ptr != NULL);
|
||||
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
/*
|
||||
* Unlike arena_prof_prof_tctx_{get, set}, we only call this once we're
|
||||
* sure we have a sampled allocation.
|
||||
*/
|
||||
assert(!extent_slab_get(extent));
|
||||
return large_prof_alloc_time_get(extent);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_prof_alloc_time_set(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx,
|
||||
nstime_t t) {
|
||||
cassert(config_prof);
|
||||
assert(ptr != NULL);
|
||||
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
assert(!extent_slab_get(extent));
|
||||
large_prof_alloc_time_set(extent, t);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) {
|
||||
tsd_t *tsd;
|
||||
@@ -83,14 +135,33 @@ arena_decay_tick(tsdn_t *tsdn, arena_t *arena) {
|
||||
arena_decay_ticks(tsdn, arena, 1);
|
||||
}
|
||||
|
||||
/* Purge a single extent to retained / unmapped directly. */
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_decay_extent(tsdn_t *tsdn,arena_t *arena, extent_hooks_t **r_extent_hooks,
|
||||
extent_t *extent) {
|
||||
size_t extent_size = extent_size_get(extent);
|
||||
extent_dalloc_wrapper(tsdn, arena,
|
||||
r_extent_hooks, extent);
|
||||
if (config_stats) {
|
||||
/* Update stats accordingly. */
|
||||
arena_stats_lock(tsdn, &arena->stats);
|
||||
arena_stats_add_u64(tsdn, &arena->stats,
|
||||
&arena->decay_dirty.stats->nmadvise, 1);
|
||||
arena_stats_add_u64(tsdn, &arena->stats,
|
||||
&arena->decay_dirty.stats->purged, extent_size >> LG_PAGE);
|
||||
arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped,
|
||||
extent_size);
|
||||
arena_stats_unlock(tsdn, &arena->stats);
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero,
|
||||
tcache_t *tcache, bool slow_path) {
|
||||
assert(!tsdn_null(tsdn) || tcache == NULL);
|
||||
assert(size != 0);
|
||||
|
||||
if (likely(tcache != NULL)) {
|
||||
if (likely(size <= SMALL_MAXCLASS)) {
|
||||
if (likely(size <= SC_SMALL_MAXCLASS)) {
|
||||
return tcache_alloc_small(tsdn_tsd(tsdn), arena,
|
||||
tcache, size, ind, zero, slow_path);
|
||||
}
|
||||
@@ -119,7 +190,7 @@ arena_salloc(tsdn_t *tsdn, const void *ptr) {
|
||||
|
||||
szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
(uintptr_t)ptr, true);
|
||||
assert(szind != NSIZES);
|
||||
assert(szind != SC_NSIZES);
|
||||
|
||||
return sz_index2size(szind);
|
||||
}
|
||||
@@ -152,11 +223,21 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
|
||||
/* Only slab members should be looked up via interior pointers. */
|
||||
assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
|
||||
|
||||
assert(szind != NSIZES);
|
||||
assert(szind != SC_NSIZES);
|
||||
|
||||
return sz_index2size(szind);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind) {
|
||||
if (config_prof && unlikely(szind < SC_NBINS)) {
|
||||
arena_dalloc_promoted(tsdn, ptr, NULL, true);
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
||||
assert(ptr != NULL);
|
||||
@@ -173,13 +254,28 @@ arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
||||
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
||||
rtree_ctx, (uintptr_t)ptr, true);
|
||||
assert(szind == extent_szind_get(extent));
|
||||
assert(szind < NSIZES);
|
||||
assert(szind < SC_NSIZES);
|
||||
assert(slab == extent_slab_get(extent));
|
||||
}
|
||||
|
||||
if (likely(slab)) {
|
||||
/* Small allocation. */
|
||||
arena_dalloc_small(tsdn, ptr);
|
||||
} else {
|
||||
arena_dalloc_large_no_tcache(tsdn, ptr, szind);
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
|
||||
bool slow_path) {
|
||||
if (szind < nhbins) {
|
||||
if (config_prof && unlikely(szind < SC_NBINS)) {
|
||||
arena_dalloc_promoted(tsdn, ptr, tcache, slow_path);
|
||||
} else {
|
||||
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||
slow_path);
|
||||
}
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
@@ -203,7 +299,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
||||
if (alloc_ctx != NULL) {
|
||||
szind = alloc_ctx->szind;
|
||||
slab = alloc_ctx->slab;
|
||||
assert(szind != NSIZES);
|
||||
assert(szind != SC_NSIZES);
|
||||
} else {
|
||||
rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
|
||||
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
@@ -215,7 +311,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
||||
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
||||
rtree_ctx, (uintptr_t)ptr, true);
|
||||
assert(szind == extent_szind_get(extent));
|
||||
assert(szind < NSIZES);
|
||||
assert(szind < SC_NSIZES);
|
||||
assert(slab == extent_slab_get(extent));
|
||||
}
|
||||
|
||||
@@ -224,25 +320,14 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||
slow_path);
|
||||
} else {
|
||||
if (szind < nhbins) {
|
||||
if (config_prof && unlikely(szind < NBINS)) {
|
||||
arena_dalloc_promoted(tsdn, ptr, tcache,
|
||||
slow_path);
|
||||
} else {
|
||||
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
|
||||
szind, slow_path);
|
||||
}
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
}
|
||||
arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
||||
assert(ptr != NULL);
|
||||
assert(size <= LARGE_MAXCLASS);
|
||||
assert(size <= SC_LARGE_MAXCLASS);
|
||||
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
@@ -252,7 +337,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
||||
* object, so base szind and slab on the given size.
|
||||
*/
|
||||
szind = sz_size2index(size);
|
||||
slab = (szind < NBINS);
|
||||
slab = (szind < SC_NBINS);
|
||||
}
|
||||
|
||||
if ((config_prof && opt_prof) || config_debug) {
|
||||
@@ -264,7 +349,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
||||
(uintptr_t)ptr, true, &szind, &slab);
|
||||
|
||||
assert(szind == sz_size2index(size));
|
||||
assert((config_prof && opt_prof) || slab == (szind < NBINS));
|
||||
assert((config_prof && opt_prof) || slab == (szind < SC_NBINS));
|
||||
|
||||
if (config_debug) {
|
||||
extent_t *extent = rtree_extent_read(tsdn,
|
||||
@@ -278,8 +363,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
||||
/* Small allocation. */
|
||||
arena_dalloc_small(tsdn, ptr);
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
arena_dalloc_large_no_tcache(tsdn, ptr, szind);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +372,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
||||
alloc_ctx_t *alloc_ctx, bool slow_path) {
|
||||
assert(!tsdn_null(tsdn) || tcache == NULL);
|
||||
assert(ptr != NULL);
|
||||
assert(size <= LARGE_MAXCLASS);
|
||||
assert(size <= SC_LARGE_MAXCLASS);
|
||||
|
||||
if (unlikely(tcache == NULL)) {
|
||||
arena_sdalloc_no_tcache(tsdn, ptr, size);
|
||||
@@ -297,7 +381,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
||||
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
UNUSED alloc_ctx_t local_ctx;
|
||||
alloc_ctx_t local_ctx;
|
||||
if (config_prof && opt_prof) {
|
||||
if (alloc_ctx == NULL) {
|
||||
/* Uncommon case and should be a static check. */
|
||||
@@ -318,7 +402,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
||||
* object, so base szind and slab on the given size.
|
||||
*/
|
||||
szind = sz_size2index(size);
|
||||
slab = (szind < NBINS);
|
||||
slab = (szind < SC_NBINS);
|
||||
}
|
||||
|
||||
if (config_debug) {
|
||||
@@ -336,18 +420,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||
slow_path);
|
||||
} else {
|
||||
if (szind < nhbins) {
|
||||
if (config_prof && unlikely(szind < NBINS)) {
|
||||
arena_dalloc_promoted(tsdn, ptr, tcache,
|
||||
slow_path);
|
||||
} else {
|
||||
tcache_dalloc_large(tsdn_tsd(tsdn),
|
||||
tcache, ptr, szind, slow_path);
|
||||
}
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
}
|
||||
arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+49
-15
@@ -4,7 +4,9 @@
|
||||
#include "jemalloc/internal/atomic.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/mutex_prof.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/sc.h"
|
||||
|
||||
JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||
|
||||
/*
|
||||
* In those architectures that support 64-bit atomics, we use atomic updates for
|
||||
@@ -33,6 +35,13 @@ struct arena_stats_large_s {
|
||||
* periodically merges into this counter.
|
||||
*/
|
||||
arena_stats_u64_t nrequests; /* Partially derived. */
|
||||
/*
|
||||
* Number of tcache fills / flushes for large (similarly, periodically
|
||||
* merged). Note that there is no large tcache batch-fill currently
|
||||
* (i.e. only fill 1 at a time); however flush may be batched.
|
||||
*/
|
||||
arena_stats_u64_t nfills; /* Partially derived. */
|
||||
arena_stats_u64_t nflushes; /* Partially derived. */
|
||||
|
||||
/* Current number of allocations of this size class. */
|
||||
size_t curlextents; /* Derived. */
|
||||
@@ -48,6 +57,22 @@ struct arena_stats_decay_s {
|
||||
arena_stats_u64_t purged;
|
||||
};
|
||||
|
||||
typedef struct arena_stats_extents_s arena_stats_extents_t;
|
||||
struct arena_stats_extents_s {
|
||||
/*
|
||||
* Stats for a given index in the range [0, SC_NPSIZES] in an extents_t.
|
||||
* We track both bytes and # of extents: two extents in the same bucket
|
||||
* may have different sizes if adjacent size classes differ by more than
|
||||
* a page, so bytes cannot always be derived from # of extents.
|
||||
*/
|
||||
atomic_zu_t ndirty;
|
||||
atomic_zu_t dirty_bytes;
|
||||
atomic_zu_t nmuzzy;
|
||||
atomic_zu_t muzzy_bytes;
|
||||
atomic_zu_t nretained;
|
||||
atomic_zu_t retained_bytes;
|
||||
};
|
||||
|
||||
/*
|
||||
* Arena stats. Note that fields marked "derived" are not directly maintained
|
||||
* within the arena code; rather their values are derived during stats merge
|
||||
@@ -69,6 +94,9 @@ struct arena_stats_s {
|
||||
*/
|
||||
atomic_zu_t retained; /* Derived. */
|
||||
|
||||
/* Number of extent_t structs allocated by base, but not being used. */
|
||||
atomic_zu_t extent_avail;
|
||||
|
||||
arena_stats_decay_t decay_dirty;
|
||||
arena_stats_decay_t decay_muzzy;
|
||||
|
||||
@@ -80,22 +108,27 @@ struct arena_stats_s {
|
||||
atomic_zu_t allocated_large; /* Derived. */
|
||||
arena_stats_u64_t nmalloc_large; /* Derived. */
|
||||
arena_stats_u64_t ndalloc_large; /* Derived. */
|
||||
arena_stats_u64_t nfills_large; /* Derived. */
|
||||
arena_stats_u64_t nflushes_large; /* Derived. */
|
||||
arena_stats_u64_t nrequests_large; /* Derived. */
|
||||
|
||||
/* VM space had to be leaked (undocumented). Normally 0. */
|
||||
atomic_zu_t abandoned_vm;
|
||||
|
||||
/* Number of bytes cached in tcache associated with this arena. */
|
||||
atomic_zu_t tcache_bytes; /* Derived. */
|
||||
|
||||
mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes];
|
||||
|
||||
/* One element for each large size class. */
|
||||
arena_stats_large_t lstats[NSIZES - NBINS];
|
||||
arena_stats_large_t lstats[SC_NSIZES - SC_NBINS];
|
||||
|
||||
/* Arena uptime. */
|
||||
nstime_t uptime;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
arena_stats_init(UNUSED tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
arena_stats_init(tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
if (config_debug) {
|
||||
for (size_t i = 0; i < sizeof(arena_stats_t); i++) {
|
||||
assert(((char *)arena_stats)[i] == 0);
|
||||
@@ -147,11 +180,11 @@ arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
#endif
|
||||
}
|
||||
|
||||
UNUSED static inline void
|
||||
static inline void
|
||||
arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_u64_t *p, uint64_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
UNUSED uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
|
||||
uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
@@ -176,7 +209,8 @@ arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) {
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) {
|
||||
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
atomic_zu_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
#else
|
||||
@@ -186,8 +220,8 @@ arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
||||
size_t x) {
|
||||
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
atomic_zu_t *p, size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
atomic_fetch_add_zu(p, x, ATOMIC_RELAXED);
|
||||
#else
|
||||
@@ -198,10 +232,10 @@ arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
||||
size_t x) {
|
||||
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
atomic_zu_t *p, size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
UNUSED size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
|
||||
size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
@@ -218,11 +252,12 @@ arena_stats_accum_zu(atomic_zu_t *dst, size_t src) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_large_flush_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
szind_t szind, uint64_t nrequests) {
|
||||
arena_stats_lock(tsdn, arena_stats);
|
||||
arena_stats_add_u64(tsdn, arena_stats, &arena_stats->lstats[szind -
|
||||
NBINS].nrequests, nrequests);
|
||||
arena_stats_large_t *lstats = &arena_stats->lstats[szind - SC_NBINS];
|
||||
arena_stats_add_u64(tsdn, arena_stats, &lstats->nrequests, nrequests);
|
||||
arena_stats_add_u64(tsdn, arena_stats, &lstats->nflushes, 1);
|
||||
arena_stats_unlock(tsdn, arena_stats);
|
||||
}
|
||||
|
||||
@@ -233,5 +268,4 @@ arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) {
|
||||
arena_stats_unlock(tsdn, arena_stats);
|
||||
}
|
||||
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_STATS_H */
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/nstime.h"
|
||||
#include "jemalloc/internal/ql.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/sc.h"
|
||||
#include "jemalloc/internal/smoothstep.h"
|
||||
#include "jemalloc/internal/ticker.h"
|
||||
|
||||
@@ -90,6 +90,9 @@ struct arena_s {
|
||||
*/
|
||||
atomic_u_t nthreads[2];
|
||||
|
||||
/* Next bin shard for binding new threads. Synchronization: atomic. */
|
||||
atomic_u_t binshard_next;
|
||||
|
||||
/*
|
||||
* When percpu_arena is enabled, to amortize the cost of reading /
|
||||
* updating the current CPU id, track the most recent thread accessing
|
||||
@@ -113,7 +116,6 @@ struct arena_s {
|
||||
|
||||
/* Synchronization: internal. */
|
||||
prof_accum_t prof_accum;
|
||||
uint64_t prof_accumbytes;
|
||||
|
||||
/*
|
||||
* PRNG state for cache index randomization of large allocation base
|
||||
@@ -196,6 +198,7 @@ struct arena_s {
|
||||
* Synchronization: extent_avail_mtx.
|
||||
*/
|
||||
extent_tree_t extent_avail;
|
||||
atomic_zu_t extent_avail_cnt;
|
||||
malloc_mutex_t extent_avail_mtx;
|
||||
|
||||
/*
|
||||
@@ -203,7 +206,7 @@ struct arena_s {
|
||||
*
|
||||
* Synchronization: internal.
|
||||
*/
|
||||
bin_t bins[NBINS];
|
||||
bins_t bins[SC_NBINS];
|
||||
|
||||
/*
|
||||
* Base allocator, from which arena metadata are allocated.
|
||||
|
||||
+10
-2
@@ -1,13 +1,15 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_TYPES_H
|
||||
|
||||
#include "jemalloc/internal/sc.h"
|
||||
|
||||
/* Maximum number of regions in one slab. */
|
||||
#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN)
|
||||
#define LG_SLAB_MAXREGS (LG_PAGE - SC_LG_TINY_MIN)
|
||||
#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS)
|
||||
|
||||
/* Default decay times in milliseconds. */
|
||||
#define DIRTY_DECAY_MS_DEFAULT ZD(10 * 1000)
|
||||
#define MUZZY_DECAY_MS_DEFAULT ZD(10 * 1000)
|
||||
#define MUZZY_DECAY_MS_DEFAULT (0)
|
||||
/* Number of event ticks between time checks. */
|
||||
#define DECAY_NTICKS_PER_UPDATE 1000
|
||||
|
||||
@@ -40,4 +42,10 @@ typedef enum {
|
||||
#define PERCPU_ARENA_ENABLED(m) ((m) >= percpu_arena_mode_enabled_base)
|
||||
#define PERCPU_ARENA_DEFAULT percpu_arena_disabled
|
||||
|
||||
/*
|
||||
* When allocation_size >= oversize_threshold, use the dedicated huge arena
|
||||
* (unless have explicitly spicified arena index). 0 disables the feature.
|
||||
*/
|
||||
#define OVERSIZE_THRESHOLD_DEFAULT (8 << 20)
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */
|
||||
+10
-1
@@ -1,12 +1,19 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ATOMIC_H
|
||||
#define JEMALLOC_INTERNAL_ATOMIC_H
|
||||
|
||||
#define ATOMIC_INLINE static inline
|
||||
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
||||
|
||||
#define JEMALLOC_U8_ATOMICS
|
||||
#if defined(JEMALLOC_GCC_ATOMIC_ATOMICS)
|
||||
# include "jemalloc/internal/atomic_gcc_atomic.h"
|
||||
# if !defined(JEMALLOC_GCC_U8_ATOMIC_ATOMICS)
|
||||
# undef JEMALLOC_U8_ATOMICS
|
||||
# endif
|
||||
#elif defined(JEMALLOC_GCC_SYNC_ATOMICS)
|
||||
# include "jemalloc/internal/atomic_gcc_sync.h"
|
||||
# if !defined(JEMALLOC_GCC_U8_SYNC_ATOMICS)
|
||||
# undef JEMALLOC_U8_ATOMICS
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# include "jemalloc/internal/atomic_msvc.h"
|
||||
#elif defined(JEMALLOC_C11_ATOMICS)
|
||||
@@ -66,6 +73,8 @@ JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(uint8_t, u8, 0)
|
||||
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2)
|
||||
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
|
||||
@@ -67,7 +67,8 @@ atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
UNUSED type *expected, type desired, \
|
||||
atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||
true, atomic_enum_to_builtin(success_mo), \
|
||||
@@ -76,7 +77,8 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
UNUSED type *expected, type desired, \
|
||||
atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||
false, \
|
||||
|
||||
+11
-7
@@ -27,8 +27,10 @@ atomic_fence(atomic_memory_order_t mo) {
|
||||
asm volatile("" ::: "memory");
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
/* This is implicit on x86. */
|
||||
# elif defined(__ppc__)
|
||||
# elif defined(__ppc64__)
|
||||
asm volatile("lwsync");
|
||||
# elif defined(__ppc__)
|
||||
asm volatile("sync");
|
||||
# elif defined(__sparc__) && defined(__arch64__)
|
||||
if (mo == atomic_memory_order_acquire) {
|
||||
asm volatile("membar #LoadLoad | #LoadStore");
|
||||
@@ -113,8 +115,8 @@ atomic_store_##short_type(atomic_##short_type##_t *a, \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
/* \
|
||||
* Because of FreeBSD, we care about gcc 4.2, which doesn't have\
|
||||
* an atomic exchange builtin. We fake it with a CAS loop. \
|
||||
@@ -129,8 +131,9 @@ atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
type *expected, type desired, \
|
||||
atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
||||
desired); \
|
||||
if (prev == *expected) { \
|
||||
@@ -142,8 +145,9 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
} \
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
type *expected, type desired, \
|
||||
atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
||||
desired); \
|
||||
if (prev == *expected) { \
|
||||
|
||||
@@ -8,7 +8,6 @@ extern atomic_b_t background_thread_enabled_state;
|
||||
extern size_t n_background_threads;
|
||||
extern size_t max_background_threads;
|
||||
extern background_thread_info_t *background_thread_info;
|
||||
extern bool can_enable_background_thread;
|
||||
|
||||
bool background_thread_create(tsd_t *tsd, unsigned arena_ind);
|
||||
bool background_threads_enable(tsd_t *tsd);
|
||||
|
||||
@@ -15,7 +15,12 @@ background_thread_enabled_set(tsdn_t *tsdn, bool state) {
|
||||
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
|
||||
arena_background_thread_info_get(arena_t *arena) {
|
||||
unsigned arena_ind = arena_ind_get(arena);
|
||||
return &background_thread_info[arena_ind % ncpus];
|
||||
return &background_thread_info[arena_ind % max_background_threads];
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
|
||||
background_thread_info_get(size_t ind) {
|
||||
return &background_thread_info[ind % max_background_threads];
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE uint64_t
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX
|
||||
#define MAX_BACKGROUND_THREAD_LIMIT MALLOCX_ARENA_LIMIT
|
||||
#define DEFAULT_NUM_BACKGROUND_THREAD 4
|
||||
|
||||
typedef enum {
|
||||
background_thread_stopped,
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/sc.h"
|
||||
|
||||
/* Embedded at the beginning of every block of base-managed virtual memory. */
|
||||
struct base_block_s {
|
||||
@@ -46,7 +46,7 @@ struct base_s {
|
||||
base_block_t *blocks;
|
||||
|
||||
/* Heap of extents that track unused trailing space within blocks. */
|
||||
extent_heap_t avail[NSIZES];
|
||||
extent_heap_t avail[SC_NSIZES];
|
||||
|
||||
/* Stats, only maintained if config_stats. */
|
||||
size_t allocated;
|
||||
|
||||
+21
-4
@@ -1,10 +1,12 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BIN_H
|
||||
#define JEMALLOC_INTERNAL_BIN_H
|
||||
|
||||
#include "jemalloc/internal/bin_stats.h"
|
||||
#include "jemalloc/internal/bin_types.h"
|
||||
#include "jemalloc/internal/extent_types.h"
|
||||
#include "jemalloc/internal/extent_structs.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/bin_stats.h"
|
||||
#include "jemalloc/internal/sc.h"
|
||||
|
||||
/*
|
||||
* A bin contains a set of extents that are currently being used for slab
|
||||
@@ -41,6 +43,9 @@ struct bin_info_s {
|
||||
/* Total number of regions in a slab for this bin's size class. */
|
||||
uint32_t nregs;
|
||||
|
||||
/* Number of sharded bins in each arena for this size class. */
|
||||
uint32_t n_shards;
|
||||
|
||||
/*
|
||||
* Metadata used to manipulate bitmaps for slabs associated with this
|
||||
* bin.
|
||||
@@ -48,8 +53,7 @@ struct bin_info_s {
|
||||
bitmap_info_t bitmap_info;
|
||||
};
|
||||
|
||||
extern const bin_info_t bin_infos[NBINS];
|
||||
|
||||
extern bin_info_t bin_infos[SC_NBINS];
|
||||
|
||||
typedef struct bin_s bin_t;
|
||||
struct bin_s {
|
||||
@@ -78,6 +82,18 @@ struct bin_s {
|
||||
bin_stats_t stats;
|
||||
};
|
||||
|
||||
/* A set of sharded bins of the same size class. */
|
||||
typedef struct bins_s bins_t;
|
||||
struct bins_s {
|
||||
/* Sharded bins. Dynamically sized. */
|
||||
bin_t *bin_shards;
|
||||
};
|
||||
|
||||
void bin_shard_sizes_boot(unsigned bin_shards[SC_NBINS]);
|
||||
bool bin_update_shard_size(unsigned bin_shards[SC_NBINS], size_t start_size,
|
||||
size_t end_size, size_t nshards);
|
||||
void bin_boot(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]);
|
||||
|
||||
/* Initializes a bin to empty. Returns true on error. */
|
||||
bool bin_init(bin_t *bin);
|
||||
|
||||
@@ -90,7 +106,7 @@ void bin_postfork_child(tsdn_t *tsdn, bin_t *bin);
|
||||
static inline void
|
||||
bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
|
||||
malloc_mutex_lock(tsdn, &bin->lock);
|
||||
malloc_mutex_prof_read(tsdn, &dst_bin_stats->mutex_data, &bin->lock);
|
||||
malloc_mutex_prof_accum(tsdn, &dst_bin_stats->mutex_data, &bin->lock);
|
||||
dst_bin_stats->nmalloc += bin->stats.nmalloc;
|
||||
dst_bin_stats->ndalloc += bin->stats.ndalloc;
|
||||
dst_bin_stats->nrequests += bin->stats.nrequests;
|
||||
@@ -100,6 +116,7 @@ bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
|
||||
dst_bin_stats->nslabs += bin->stats.nslabs;
|
||||
dst_bin_stats->reslabs += bin->stats.reslabs;
|
||||
dst_bin_stats->curslabs += bin->stats.curslabs;
|
||||
dst_bin_stats->nonfull_slabs += bin->stats.nonfull_slabs;
|
||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@ struct bin_stats_s {
|
||||
/* Current number of slabs in this bin. */
|
||||
size_t curslabs;
|
||||
|
||||
/* Current size of nonfull slabs heap in this bin. */
|
||||
size_t nonfull_slabs;
|
||||
|
||||
mutex_prof_data_t mutex_data;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BIN_TYPES_H
|
||||
#define JEMALLOC_INTERNAL_BIN_TYPES_H
|
||||
|
||||
#include "jemalloc/internal/sc.h"
|
||||
|
||||
#define BIN_SHARDS_MAX (1 << EXTENT_BITS_BINSHARD_WIDTH)
|
||||
#define N_BIN_SHARDS_DEFAULT 1
|
||||
|
||||
/* Used in TSD static initializer only. Real init in arena_bind(). */
|
||||
#define TSD_BINSHARDS_ZERO_INITIALIZER {{UINT8_MAX}}
|
||||
|
||||
typedef struct tsd_binshards_s tsd_binshards_t;
|
||||
struct tsd_binshards_s {
|
||||
uint8_t binshard[SC_NBINS];
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BIN_TYPES_H */
|
||||
@@ -27,6 +27,25 @@ ffs_u(unsigned bitmap) {
|
||||
return JEMALLOC_INTERNAL_FFS(bitmap);
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_INTERNAL_POPCOUNTL
|
||||
BIT_UTIL_INLINE unsigned
|
||||
popcount_lu(unsigned long bitmap) {
|
||||
return JEMALLOC_INTERNAL_POPCOUNTL(bitmap);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clears first unset bit in bitmap, and returns
|
||||
* place of bit. bitmap *must not* be 0.
|
||||
*/
|
||||
|
||||
BIT_UTIL_INLINE size_t
|
||||
cfs_lu(unsigned long* bitmap) {
|
||||
size_t bit = ffs_lu(*bitmap) - 1;
|
||||
*bitmap ^= ZU(1) << bit;
|
||||
return bit;
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
ffs_zu(size_t bitmap) {
|
||||
#if LG_SIZEOF_PTR == LG_SIZEOF_INT
|
||||
@@ -63,6 +82,22 @@ ffs_u32(uint32_t bitmap) {
|
||||
|
||||
BIT_UTIL_INLINE uint64_t
|
||||
pow2_ceil_u64(uint64_t x) {
|
||||
#if (defined(__amd64__) || defined(__x86_64__) || defined(JEMALLOC_HAVE_BUILTIN_CLZ))
|
||||
if(unlikely(x <= 1)) {
|
||||
return x;
|
||||
}
|
||||
size_t msb_on_index;
|
||||
#if (defined(__amd64__) || defined(__x86_64__))
|
||||
asm ("bsrq %1, %0"
|
||||
: "=r"(msb_on_index) // Outputs.
|
||||
: "r"(x-1) // Inputs.
|
||||
);
|
||||
#elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ))
|
||||
msb_on_index = (63 ^ __builtin_clzll(x - 1));
|
||||
#endif
|
||||
assert(msb_on_index < 63);
|
||||
return 1ULL << (msb_on_index + 1);
|
||||
#else
|
||||
x--;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
@@ -72,10 +107,27 @@ pow2_ceil_u64(uint64_t x) {
|
||||
x |= x >> 32;
|
||||
x++;
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE uint32_t
|
||||
pow2_ceil_u32(uint32_t x) {
|
||||
#if ((defined(__i386__) || defined(JEMALLOC_HAVE_BUILTIN_CLZ)) && (!defined(__s390__)))
|
||||
if(unlikely(x <= 1)) {
|
||||
return x;
|
||||
}
|
||||
size_t msb_on_index;
|
||||
#if (defined(__i386__))
|
||||
asm ("bsr %1, %0"
|
||||
: "=r"(msb_on_index) // Outputs.
|
||||
: "r"(x-1) // Inputs.
|
||||
);
|
||||
#elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ))
|
||||
msb_on_index = (31 ^ __builtin_clz(x - 1));
|
||||
#endif
|
||||
assert(msb_on_index < 31);
|
||||
return 1U << (msb_on_index + 1);
|
||||
#else
|
||||
x--;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
@@ -84,6 +136,7 @@ pow2_ceil_u32(uint32_t x) {
|
||||
x |= x >> 16;
|
||||
x++;
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Compute the smallest power of 2 that is >= x. */
|
||||
@@ -160,6 +213,27 @@ lg_floor(size_t x) {
|
||||
}
|
||||
#endif
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
lg_ceil(size_t x) {
|
||||
return lg_floor(x) + ((x & (x - 1)) == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
#undef BIT_UTIL_INLINE
|
||||
|
||||
/* A compile-time version of lg_floor and lg_ceil. */
|
||||
#define LG_FLOOR_1(x) 0
|
||||
#define LG_FLOOR_2(x) (x < (1ULL << 1) ? LG_FLOOR_1(x) : 1 + LG_FLOOR_1(x >> 1))
|
||||
#define LG_FLOOR_4(x) (x < (1ULL << 2) ? LG_FLOOR_2(x) : 2 + LG_FLOOR_2(x >> 2))
|
||||
#define LG_FLOOR_8(x) (x < (1ULL << 4) ? LG_FLOOR_4(x) : 4 + LG_FLOOR_4(x >> 4))
|
||||
#define LG_FLOOR_16(x) (x < (1ULL << 8) ? LG_FLOOR_8(x) : 8 + LG_FLOOR_8(x >> 8))
|
||||
#define LG_FLOOR_32(x) (x < (1ULL << 16) ? LG_FLOOR_16(x) : 16 + LG_FLOOR_16(x >> 16))
|
||||
#define LG_FLOOR_64(x) (x < (1ULL << 32) ? LG_FLOOR_32(x) : 32 + LG_FLOOR_32(x >> 32))
|
||||
#if LG_SIZEOF_PTR == 2
|
||||
# define LG_FLOOR(x) LG_FLOOR_32((x))
|
||||
#else
|
||||
# define LG_FLOOR(x) LG_FLOOR_64((x))
|
||||
#endif
|
||||
|
||||
#define LG_CEIL(x) (LG_FLOOR(x) + (((x) & ((x) - 1)) == 0 ? 0 : 1))
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BIT_UTIL_H */
|
||||
Loaded 100 of 563 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user