Compare commits
1307 Commits
v2.1.0-rc-
...
561943ddca
Author | SHA1 | Date | |
---|---|---|---|
561943ddca | |||
e161113ad5 | |||
a0a257fe22 | |||
1d939e69fd | |||
c4707c2cf7 | |||
76a7b3eaf0 | |||
3587b47edd | |||
e569b1dd14 | |||
815d179d82 | |||
fb9425381e | |||
12dfc0ab94 | |||
2ce86e1498 | |||
aab3d8866e | |||
587c0559b5 | |||
0c31cc217f | |||
b9060328fc | |||
8531500d7d | |||
923e3be6a5 | |||
9ebfb30871 | |||
cd574e85c3 | |||
de30ac5399 | |||
d578dbe141 | |||
9ae04b75c6 | |||
80eb1f2a50 | |||
12f552b000 | |||
ae5bdb490d | |||
dd00ea4439 | |||
6af3b30b4c | |||
dcaa200b67 | |||
02053ad8f2 | |||
66df44a8dd | |||
7ec7544995 | |||
2a80d4053c | |||
ac3e7eef61 | |||
63c1b83f18 | |||
a8f16ab89d | |||
8c412a6cff | |||
29d83fc5e8 | |||
6fe0088c1b | |||
b3f7a9b659 | |||
2d5508eb7c | |||
1a84e507fc | |||
4f419be42d | |||
539d7e8402 | |||
ad22233308 | |||
f344665ddc | |||
8ff90ae769 | |||
2fd0ff8a93 | |||
3c659e57ec | |||
1c2d2cd13c | |||
ce1676f3d3 | |||
75a4676eac | |||
0a70469cd0 | |||
13f6c10e6e | |||
73a8b2c9fc | |||
f22d96df0c | |||
3bdb342d24 | |||
e4a80e22f3 | |||
5df2a5c3c0 | |||
9bead305cf | |||
49fa2e6637 | |||
924875d0b2 | |||
18b865bbea | |||
086feaf7a5 | |||
88436c9d1f | |||
b41699af5c | |||
6886f7d392 | |||
ac66240fac | |||
9d873c0147 | |||
9489609b61 | |||
57d583d6b5 | |||
8bb179c4dd | |||
a68eb0fadb | |||
efe61762b5 | |||
3b72e971e6 | |||
ad01aa72b2 | |||
4620dc72fe | |||
fd18ad9102 | |||
2952cc8373 | |||
ab07d7e192 | |||
fc9624e996 | |||
ca7257d7f7 | |||
1511603b6a | |||
1e69f793e2 | |||
636f8ec0fb | |||
9bb91682da | |||
b305b9c6f1 | |||
5c7a5daf73 | |||
fe0c687f82 | |||
4a203ebf47 | |||
f260f1d50a | |||
d2928e5580 | |||
d908e931b1 | |||
806b129292 | |||
819459664e | |||
c6435b026d | |||
eae1ef32db | |||
1cc66122df | |||
cedc425704 | |||
07d7699ba7 | |||
c93e6abaa9 | |||
5753bdba52 | |||
7910a6b3d0 | |||
5a054cc9ca | |||
4d70adf26e | |||
db51ec6489 | |||
df60ac8dfc | |||
a9be30e6e7 | |||
b65c9d2ab7 | |||
f333b74cd1 | |||
0a182a87aa | |||
cf0589f6b3 | |||
a72746d491 | |||
a0f6ff6f7d | |||
ca6f919664 | |||
d2a8aef843 | |||
f14b1c7168 | |||
0a08914a01 | |||
031e8e3495 | |||
62489245cb | |||
00844cb89c | |||
c943c1ecd7 | |||
74f9364196 | |||
4fd1e7507a | |||
edb57903bc | |||
c8f4af7455 | |||
7a6a7421cd | |||
cfa96f2476 | |||
1c2759f2d7 | |||
2e858bdd5a | |||
2c8950d5b4 | |||
895464f50d | |||
7a69989275 | |||
a6bfd2306c | |||
447f9a886d | |||
fc2af3f935 | |||
12db0a3753 | |||
a3991e7c76 | |||
ce0e1358fc | |||
ce2bf344f9 | |||
ebb9f59196 | |||
b03060a00f | |||
39996b2dc8 | |||
3fcb846eca | |||
d66c818c1e | |||
0348492f6c | |||
ead3bcde1a | |||
2ca277ddf7 | |||
274471a066 | |||
001f586a24 | |||
e2efb78385 | |||
5018a192d7 | |||
bd821d0a63 | |||
c5e463c366 | |||
c46334b046 | |||
146d301002 | |||
e6ad15889e | |||
7fb2889c74 | |||
f750a52f75 | |||
cf0ff8cf62 | |||
b7f79c4192 | |||
ad4e950005 | |||
18929038fb | |||
890b3e12dc | |||
0a45b51760 | |||
c0a6bde9e5 | |||
e4289295e8 | |||
60b06790a3 | |||
c421e84854 | |||
ba5f6a62c8 | |||
65b7428bdf | |||
f68917c8cc | |||
80fd52625e | |||
9961cb700e | |||
bb983594d5 | |||
eeea09f65a | |||
95b9464c9f | |||
f1ab604fe9 | |||
d9740445dc | |||
69d44c27cc | |||
f8ded1ecd1 | |||
3cae30eedd | |||
e34f0efc79 | |||
c9ac60a2fc | |||
8c8d7b3bf9 | |||
7fa51e906c | |||
a0d653fff7 | |||
2df67abffb | |||
c944039759 | |||
73d1d993d7 | |||
efa5e07549 | |||
72fe3613d3 | |||
a936603e37 | |||
f5c9fb3842 | |||
68e76285fe | |||
f23f214cfc | |||
bfd698fd56 | |||
f6bd64159f | |||
c22594c6ab | |||
5f1d65f1f2 | |||
db0b209ca6 | |||
2017897ad6 | |||
0d7e6284bc | |||
77d985a483 | |||
f68de677c6 | |||
9d00a87851 | |||
4aebc2502d | |||
f1ca91faf1 | |||
fd1ec1c853 | |||
575dbcd7f1 | |||
c420ff1c81 | |||
9af77225f2 | |||
dbf4a58807 | |||
6b58a0e0f7 | |||
7f044442bc | |||
35e6993629 | |||
f82fbf9b55 | |||
5fcb182cb8 | |||
6fc0085292 | |||
3cee38bf92 | |||
f85d0bd333 | |||
bf66bff7b4 | |||
f5668c82a7 | |||
595d638ee0 | |||
e3bf579fd3 | |||
fd137cad90 | |||
6a9acb20dc | |||
29c0a98f01 | |||
b0670976ff | |||
317325aeb8 | |||
13ad145811 | |||
12a373324e | |||
45a444eb29 | |||
fe75412dfe | |||
85136c9af2 | |||
5187f32346 | |||
3a62c389ef | |||
48ed06a255 | |||
7d5d52afe3 | |||
bb9892cc84 | |||
f0c774de5a | |||
555824d913 | |||
cc1000e73b | |||
0d979459a4 | |||
78d7949347 | |||
2fe468826d | |||
8128ac09b3 | |||
3a52dfc4ea | |||
b8b364f292 | |||
a995afa6eb | |||
7415f562ff | |||
3425619773 | |||
1e8a351f67 | |||
2ff18fe98d | |||
06380ccc58 | |||
d93204bfe6 | |||
3b87050dcb | |||
6da907910c | |||
2493a16828 | |||
1bbe5fbef4 | |||
8c9c7254b4 | |||
55a88e7576 | |||
9c9c7cdf8b | |||
fa72388a8b | |||
9eb6a377fd | |||
7567e3289c | |||
f276356172 | |||
7d39fc0667 | |||
56350c8704 | |||
7bd31b1c0a | |||
cf5bb87b6c | |||
31df328be7 | |||
ff8d037474 | |||
031682051f | |||
0e8824a8d2 | |||
f0ddbe7a8c | |||
18c5948e3f | |||
660bc28f0c | |||
9c5166b921 | |||
4a7c76cc1c | |||
1e2fd53b86 | |||
ab09407c3d | |||
9b2310a3e7 | |||
56a56e57c8 | |||
7908e7e982 | |||
92b32b838c | |||
65efa8590f | |||
d70aa968d6 | |||
591cd0ad2d | |||
1bdc78e5e0 | |||
7100708dfd | |||
08379ea622 | |||
161208a1fd | |||
3959067f22 | |||
65096f60b1 | |||
4b32664e46 | |||
cf1ee8db02 | |||
89d4b4245d | |||
1d7d221da1 | |||
b4621f6a4e | |||
c6b895ced2 | |||
5f51a9384e | |||
88736fc58a | |||
be96d79281 | |||
2a28eed7e8 | |||
443aaff217 | |||
b4d3bb083d | |||
b9ce21853f | |||
31e20e9af0 | |||
cfb7a74841 | |||
c8f2485ff0 | |||
62857e1372 | |||
ae3b592cf6 | |||
3365363d23 | |||
f480720665 | |||
d0a8f9df58 | |||
28dc153822 | |||
b265dcf73f | |||
4b9b095104 | |||
ea8eb53a34 | |||
412b807d3f | |||
14cbde2586 | |||
429751e1fc | |||
04f50f7453 | |||
3814b9797d | |||
44d810c398 | |||
c982972ee8 | |||
cfba3d3082 | |||
587527e418 | |||
bb4a3bc6cb | |||
29615d61eb | |||
86f910c865 | |||
2f6a691f65 | |||
ea59ce6dc3 | |||
3cbe39784f | |||
cb2089ccfe | |||
c2bdb884c2 | |||
7daec9d0f5 | |||
a05c642f5e | |||
4c70641d8f | |||
e1939d4d11 | |||
6da5d9f4f0 | |||
401344ac5a | |||
329ba1d5e4 | |||
7faf648919 | |||
8b5369d120 | |||
8af198f7a4 | |||
b1735ab0af | |||
1ab36272f6 | |||
86e5f0359d | |||
ff007bca7f | |||
d03e6e8201 | |||
d481aeae66 | |||
c832d4ce21 | |||
a5a0e690ce | |||
74496016f0 | |||
bb8ff0de59 | |||
c66369f302 | |||
de800f79e9 | |||
c0111d83ae | |||
596b171c2c | |||
99785c0b41 | |||
f2eafe0f14 | |||
5ea9f27645 | |||
6300270a21 | |||
2e587fd897 | |||
f022be6fb9 | |||
8ebf66a686 | |||
ee695eb738 | |||
80d8d6f32f | |||
0b7a9c6a56 | |||
54b70f99cc | |||
fe0fef2f21 | |||
1eec19c583 | |||
6b40658eac | |||
bd836b9ecb | |||
074a026d64 | |||
60864649c0 | |||
d2a26f0c09 | |||
74546807f4 | |||
d7d9199f8e | |||
77299455f9 | |||
0d5ac30e49 | |||
2c55e243f5 | |||
cb2362432e | |||
9c3e464ce4 | |||
4e8e188d24 | |||
e476b4f0c6 | |||
eec286845e | |||
c276cb8979 | |||
58107e6ed8 | |||
eb4c8c6cc0 | |||
0f7dfc6ce7 | |||
a4693f8acc | |||
fc7c6b9705 | |||
43ce2d13ec | |||
6f6f8d4d52 | |||
54fdcf6d80 | |||
fd46d3ef96 | |||
2a15d6b4a3 | |||
acdc165102 | |||
bb4e3c26f4 | |||
8e4a8f0f4b | |||
2fd6f68c97 | |||
f7ca4f8fa3 | |||
4c3d759837 | |||
04daf393d7 | |||
e62477a38e | |||
3338fcf91f | |||
136f76c575 | |||
b94c124869 | |||
1fe7b68f0e | |||
3d9ed2dfe8 | |||
c8cc0feae5 | |||
1d53cd8e8b | |||
73ec7f2252 | |||
5450ffc280 | |||
a9125196ce | |||
ab9765582a | |||
060b2b70dc | |||
739a31538f | |||
67595b4d45 | |||
c5003e0ee6 | |||
984657a5dd | |||
2930933f19 | |||
72a6f5ae08 | |||
7a96a8cbf3 | |||
0b4befd823 | |||
151b6775b0 | |||
47a6bdbcd2 | |||
20ab95380a | |||
73afdaedb9 | |||
a231c2afaf | |||
74109d1195 | |||
2bd847b833 | |||
2d74fb30de | |||
af339e6086 | |||
ae5c4a11a8 | |||
4ce7d76500 | |||
a031f9d867 | |||
2f6fa792df | |||
be0f977dc7 | |||
73efae7c2f | |||
6b67cd676d | |||
2db38a87e3 | |||
213511a77d | |||
a38a033143 | |||
619d5939b3 | |||
68a26d2bc6 | |||
2661885cf2 | |||
6a820837cc | |||
02b74402f4 | |||
3535a61844 | |||
eb4fe4ff60 | |||
793ec5b4a5 | |||
c14b637536 | |||
489d9b1960 | |||
2f60890d29 | |||
19d4b0a247 | |||
69d190e485 | |||
2df84f53ed | |||
876a1e9cd8 | |||
2945793de9 | |||
0de0e511ee | |||
c16d9f9712 | |||
0903d4b83e | |||
0bd1f72017 | |||
7bc1440b8b | |||
9562ac2c62 | |||
9da78b82f3 | |||
8018ce51a0 | |||
3871e44732 | |||
beb1058a51 | |||
259efff707 | |||
3c4a4d8976 | |||
e3ad402853 | |||
470e7b0b07 | |||
cda89d0588 | |||
f5993d472c | |||
0d01862441 | |||
ec2ff87ac7 | |||
fd16a55745 | |||
f1f9e4547d | |||
3238b6d4de | |||
43f0a4b646 | |||
c760b7328b | |||
7d9db55d5d | |||
0741e307cc | |||
38f5374e49 | |||
db1320dd3a | |||
2f8f38b6a2 | |||
0303dcf16a | |||
4c4db56a82 | |||
11c58c4afb | |||
07d0eb0616 | |||
7d74d192f9 | |||
da60c39216 | |||
5ca67b28cf | |||
8247669d3b | |||
55762f9c92 | |||
2a1a48bc68 | |||
d5b47a803c | |||
695a7b0195 | |||
ff13142093 | |||
d6aace8c51 | |||
ec2b8e1854 | |||
884d2d6890 | |||
72899173a0 | |||
79c72d1aef | |||
ab0b1b645b | |||
7eb12d09f9 | |||
ed8ec257cc | |||
c7a28ae526 | |||
c22c68ef28 | |||
d07e1f9cce | |||
158cd55b1a | |||
5fcc59434b | |||
0650790c43 | |||
55debcb643 | |||
ded55057cc | |||
7cb78cab40 | |||
468aba1399 | |||
eba242de7f | |||
fa92540bb9 | |||
b508d98dd7 | |||
4b68e5e4b7 | |||
3f6121839a | |||
5e1745ebfb | |||
b20bc6c28a | |||
9a1483377c | |||
4c97f6b098 | |||
f9af43309d | |||
a77fd75687 | |||
f5b4928818 | |||
25d61b5cd4 | |||
e65e14f796 | |||
6aea801779 | |||
21fd9fe227 | |||
948b0fdd99 | |||
b5cf2de900 | |||
18d05ca635 | |||
b8cd42e235 | |||
4e8ff7815e | |||
57b007759e | |||
8692541e7f | |||
f5b827a039 | |||
3a79cee2f9 | |||
3b68543e32 | |||
7c2a245944 | |||
56e27e3184 | |||
b7c87bed82 | |||
3cfda97c05 | |||
52df12493b | |||
6e7b030afa | |||
afeeb97f05 | |||
5f925d3e71 | |||
26e1975edc | |||
2169456d6a | |||
cca53b2d26 | |||
2a6ecf61b2 | |||
18c53fad9a | |||
84fc05acc0 | |||
c960df8f70 | |||
9d0baf30b8 | |||
312e4bc0f1 | |||
1d7f5b7ef1 | |||
08e381a307 | |||
49e518ac19 | |||
8e2ebf05b8 | |||
924b79add2 | |||
857dcc5535 | |||
7c0d583435 | |||
2b6a88f8cb | |||
fbf31c77ed | |||
9c2aa62f1f | |||
b6456abf0d | |||
5138b0d1ab | |||
0f60a5a467 | |||
982e5357a5 | |||
0ad0ff508b | |||
b4d61649cb | |||
cdfbaa47b6 | |||
211805e460 | |||
841d57cf13 | |||
bd25904371 | |||
3c001c11ae | |||
1f6036ec18 | |||
104e101158 | |||
b281b4c105 | |||
cf6a370eea | |||
8feb244dc9 | |||
f9e2e72d84 | |||
32ef8ba3c3 | |||
2fb53e34af | |||
c72dec6369 | |||
c0b0c5d397 | |||
d34ccc424d | |||
663c89ac53 | |||
414f18a518 | |||
9bfdece859 | |||
ad79c5daf5 | |||
48a1bef1ae | |||
09cb5d8f19 | |||
c216df9b73 | |||
a0a5ca3390 | |||
ae0a921ba8 | |||
3ce03dabf5 | |||
4a530c4703 | |||
c9f9c2a24c | |||
cd538566d3 | |||
f0fe0a1962 | |||
68e3f6fc00 | |||
a23adf6db6 | |||
da5752e971 | |||
40682e37c0 | |||
cbd36efd91 | |||
96c712ae9c | |||
28065c2c8e | |||
9677ebb44e | |||
172ea8bc00 | |||
d2ec6f1f10 | |||
bc7a74e432 | |||
8561278539 | |||
f932799efa | |||
67dedc3fb5 | |||
7120856407 | |||
a1b138ccd1 | |||
d192904f8c | |||
0bd7070ec5 | |||
63ca3089da | |||
39d644e115 | |||
ac89796d5d | |||
4e1250a832 | |||
4049af94dc | |||
ab40037cb4 | |||
66305c3c86 | |||
989d14072d | |||
21d4f4b78d | |||
94b7950cf1 | |||
1fe3f62be4 | |||
43df4356b6 | |||
5440dd3dac | |||
88718de96e | |||
d8d86f3f0c | |||
1ff62fb2b5 | |||
284e2a3ead | |||
3c97c2d953 | |||
196aeae11f | |||
ba2850ea21 | |||
1f4872769d | |||
24c647966b | |||
d3f3048568 | |||
ea249723f9 | |||
52a2df2576 | |||
6645b322bd | |||
7a683a46a9 | |||
cb24252286 | |||
fff3dc4685 | |||
9c01d51334 | |||
9aafb62961 | |||
891040479b | |||
55bcf082ec | |||
67053645e1 | |||
854caffea8 | |||
36e952606b | |||
eba93484c1 | |||
d09d55951d | |||
b35e100bb2 | |||
27b37eb570 | |||
92295506a7 | |||
d20ed07066 | |||
3fa16fd846 | |||
481dfd5ff5 | |||
e5a99943a5 | |||
dbaf379f19 | |||
e1bd3bb8ec | |||
ca834dd119 | |||
163549098d | |||
4800db00d9 | |||
675707b46c | |||
14ebdab034 | |||
8541e292cd | |||
9adec02640 | |||
6a97ad664b | |||
8bb291bbd9 | |||
13a55bff61 | |||
d6efc19ba8 | |||
517e603539 | |||
d144101a7e | |||
b84202a689 | |||
572351067c | |||
9a3d6e725e | |||
d6ac8cfeca | |||
e697363574 | |||
8cc6868480 | |||
37d393c1f9 | |||
ec8b7783f3 | |||
7b375eb912 | |||
ffdea97de3 | |||
7c02d79a5c | |||
46bbc4bf92 | |||
08104c97f7 | |||
8cf169849c | |||
67ac6a6c6e | |||
ef270887fc | |||
d61cb3f0f3 | |||
12d3fbe9a7 | |||
bf9d6157f5 | |||
c4d7868381 | |||
de0a88e45b | |||
fed4f40cfb | |||
d1b4aab952 | |||
072a5356b6 | |||
781278df06 | |||
42a81b1c8e | |||
3e6ed45562 | |||
366fe60e2f | |||
be30230422 | |||
a523d1ca66 | |||
62a75bcddd | |||
bd754a7ee8 | |||
ae98d199e7 | |||
95ff5dd5eb | |||
3f3e9b5735 | |||
82a48fa3b4 | |||
97ce74b798 | |||
91704df08d | |||
4add037dc7 | |||
79314a11b5 | |||
0ff87a0ac3 | |||
1aef67368b | |||
ba2a669be6 | |||
fd721c5dc4 | |||
34070bba89 | |||
1b1fc0fc09 | |||
44a1547d2e | |||
439f9cce3d | |||
9aecec2d96 | |||
26fffdd3e8 | |||
7bf69ec350 | |||
49f884bb68 | |||
a58fcc7f14 | |||
113b5e7258 | |||
5b337d4c65 | |||
0b80e82721 | |||
7e45fa9708 | |||
aa92f3d401 | |||
692c92b0df | |||
51cb2c0b9a | |||
6e52474953 | |||
35db1cd0c4 | |||
739a1103f0 | |||
bb8cbb49f5 | |||
3be29f5b73 | |||
d944569fb2 | |||
3ca27ec566 | |||
779bfc762e | |||
54828600a8 | |||
d5410b88a3 | |||
e86d9fd29b | |||
cbebcfae82 | |||
3dc16db278 | |||
e81227e5f7 | |||
fd83c263e1 | |||
9ca857c98e | |||
afcba6b086 | |||
ef50acc867 | |||
f12833f36c | |||
b26788819e | |||
f905de7c42 | |||
8466a8850f | |||
af8e2cddcb | |||
0089866142 | |||
ca892c7f11 | |||
2a33000ace | |||
bd8da9b987 | |||
5bd780ef07 | |||
25c445b889 | |||
ca4111ac77 | |||
868e8ae124 | |||
51358c7110 | |||
ad97741e1e | |||
5d281e0fd0 | |||
c1a1242398 | |||
5000215973 | |||
ceda21830f | |||
b80b7b482c | |||
8e41f71e70 | |||
72286c865f | |||
2d435457e6 | |||
cef1ff7067 | |||
393dc07de8 | |||
49f0425e56 | |||
7973e523c3 | |||
c4326520cd | |||
dfb9d78448 | |||
26714a836c | |||
59e2986080 | |||
65fc484fa4 | |||
253978bc5f | |||
4aad60f69d | |||
72f7aaf9e4 | |||
d12b5f7b05 | |||
a7239558bd | |||
9d3e4b8767 | |||
cbb99c7b47 | |||
dca0752189 | |||
760a1e4322 | |||
56bc78f63c | |||
60b89c5c08 | |||
fa0f648a0b | |||
5592c663a4 | |||
c847353baf | |||
a140f59acb | |||
b2eae73fb0 | |||
a34dc8f1f8 | |||
92e2937a6b | |||
47757f69bd | |||
b642294193 | |||
8075af364f | |||
3d7285063a | |||
232420621a | |||
a0432be819 | |||
468093227d | |||
32facdc2ff | |||
3a719272cb | |||
9ce4c5a494 | |||
15cc7b0b87 | |||
6d152181d3 | |||
97082fa42c | |||
becd137cf5 | |||
89fc0fb372 | |||
68d79c73cf | |||
d0e9ed4181 | |||
535d2f85ca | |||
5ec20fbcbd | |||
0225fb8e5d | |||
035f830b71 | |||
7a1fb4a790 | |||
4939b05ca7 | |||
2e1f0c8f5f | |||
d8ac596687 | |||
1f43ab3bcc | |||
ef9fbf775c | |||
d6ff728a4d | |||
f6ea8f077b | |||
3e96764fc4 | |||
45b21ae0af | |||
490e49406f | |||
36e7d06b39 | |||
b26b52fd2d | |||
b35041f1f3 | |||
bf7ba3991f | |||
30806c6ebd | |||
29af6e5b7c | |||
cde0e92591 | |||
85b28f7ee3 | |||
df24b99303 | |||
d659a5e04d | |||
99c0246720 | |||
c0dba76ecd | |||
e37a375c18 | |||
6718eb374d | |||
bba7f10703 | |||
df947db055 | |||
256e873e7b | |||
34bc3b759e | |||
853aa2784c | |||
4011ab8080 | |||
07eaad7226 | |||
c743d3c341 | |||
05a5645f4c | |||
7aa71fb202 | |||
6410faa5b4 | |||
a3e578240b | |||
dd492ff52d | |||
e7b576bc45 | |||
7fcc40d0e1 | |||
e6fc6093b2 | |||
73ee70a862 | |||
b647053fb9 | |||
d518e55a67 | |||
fcd38db2ef | |||
89cd8c8fd0 | |||
88c7e7f192 | |||
a00e77d554 | |||
05d5bd9fe5 | |||
e14e7e96c7 | |||
4b8ac300c8 | |||
ee9c5fffad | |||
55caf049b1 | |||
4bdaeaa30d | |||
7c58d9c569 | |||
d6b2c1d81e | |||
4a2acf99a7 | |||
3567941139 | |||
50e7fb612c | |||
03dd9ee579 | |||
2a3c6f3522 | |||
2e46f2fead | |||
b00b72d70f | |||
7dbaf9b8d9 | |||
6b463adbb9 | |||
cb819d7da6 | |||
841ba37841 | |||
7cfefbc512 | |||
9ebba7252c | |||
835c56330a | |||
3e5c70e6b4 | |||
95b88b6ac6 | |||
c1f39afaa3 | |||
1893f7204e | |||
4a062abfde | |||
fb26aa04b6 | |||
7c538b471d | |||
c4c1941fc8 | |||
0ce2be24a3 | |||
3cf60d0d26 | |||
7d33ee80d0 | |||
52ba2de51f | |||
a1b8b57d34 | |||
cf9e0a356c | |||
e66b783df8 | |||
b695200123 | |||
a383fb405e | |||
1cebaf83e1 | |||
4976825bd6 | |||
098d172f40 | |||
f4a3c52428 | |||
2d60b637ec | |||
79b16d9a34 | |||
d69f2fd321 | |||
4015c1bb6e | |||
9f76f20ea8 | |||
b399ff3291 | |||
4fafc17b90 | |||
f1bb88624b | |||
f950e3192f | |||
bef2f078e0 | |||
218053a2be | |||
baca904079 | |||
b5175cb82b | |||
39888a1ebc | |||
ffea22c71b | |||
dd15bb2205 | |||
4b53b5544f | |||
24ca2d3531 | |||
5587e3430b | |||
0c36669fef | |||
bbce86cb9d | |||
ed3a45bfc6 | |||
144fd59c1c | |||
bdc54d7115 | |||
aa04371663 | |||
78ef412516 | |||
28f7f5cb14 | |||
624b92bc97 | |||
ca799298f4 | |||
42b67a7b61 | |||
4de4386142 | |||
509eeca760 | |||
1cb9663776 | |||
26667fdcd6 | |||
681a3eec53 | |||
2a5df890f7 | |||
ae0059591c | |||
8655becf1e | |||
2a3a0aa689 | |||
ce417ec7c8 | |||
4e848a998e | |||
d89f35775e | |||
88ebf72003 | |||
9437b175a2 | |||
302d73a078 | |||
ba7c36e30e | |||
b4da43c87f | |||
f5e078ea3d | |||
8aba39c955 | |||
68a5f90715 | |||
f3dfadddfa | |||
f1ec1fd4a6 | |||
cf59db9cee | |||
e21fbe84ba | |||
1e4d675f76 | |||
e02fe870e9 | |||
9ef9250c18 | |||
2e4b9d3787 | |||
fd2b3c3239 | |||
6640394bd3 | |||
84cc726c4f | |||
5d99d21915 | |||
3b8636544a | |||
14ce60ab65 | |||
7506431b34 | |||
8621209eb3 | |||
d1fe317fb9 | |||
a5c47d3f22 | |||
267c272ce5 | |||
7a8ae32b85 | |||
921d404a5a | |||
de6a7beb5e | |||
5a928208fd | |||
92fc163341 | |||
ca1e03f3ea | |||
de8c3ad603 | |||
f7d56bdd48 | |||
afc13b45f4 | |||
11d2c3c69e | |||
356521e176 | |||
468668e518 | |||
e53dec7bab | |||
26cd6de110 | |||
d1157ca261 | |||
0d49b49482 | |||
753820bd81 | |||
2a98e44a5c | |||
9650d3f56b | |||
aff308f67d | |||
be76d663b5 | |||
160863561f | |||
de02fdb812 | |||
1dda98e337 | |||
ccc6afdfa4 | |||
6b166551af | |||
90694f816f | |||
51636fbac3 | |||
3c7aa417a9 | |||
04d560739d | |||
2c1842f06c | |||
aba487277c | |||
1b95d5dfed | |||
7590fc4f45 | |||
a409408ac0 | |||
b121c9778f | |||
d452761ff9 | |||
dbc5725779 | |||
8b6536c55b | |||
c7318b0383 | |||
26fa85e421 | |||
939742a991 | |||
6ab7386a79 | |||
a750cdc3cb | |||
2f8af0fb08 | |||
7a9802ccb7 | |||
d356d04bf5 | |||
c99c4988ff | |||
6c564eb98b | |||
786d8634cf | |||
70b5204a9f | |||
1d70309a16 | |||
b2aba8c447 | |||
8757b47b35 | |||
b1a7632536 | |||
97c73d5358 | |||
bb3f05aef1 | |||
2001ffc27c | |||
bd2dd4035e | |||
7eb793f577 | |||
b05cedb509 | |||
cd484aa7bb | |||
fbfb528adc | |||
d9cba7f4cc | |||
7d5c5e18c6 | |||
2c0935a771 | |||
5312797b97 | |||
801af6b799 | |||
b42379b519 | |||
8b328b92b1 | |||
2e6ecf8ddb | |||
12c7c48b20 | |||
732a42a073 | |||
5638d5c010 | |||
6a984ac84c | |||
c1eb6b94ed | |||
85135b9267 | |||
670c5bac17 | |||
2dab1426b4 | |||
43004b19c3 | |||
4044d95aaa | |||
c6024c06ce | |||
e56bcb6489 | |||
d9e0164080 | |||
b588cd645e | |||
2c163d7219 | |||
39c53fe903 | |||
7b12d8f9e9 | |||
4649f66c00 | |||
9648abf4b9 | |||
cc1246d0f5 | |||
726aa43a95 | |||
224f983ca8 | |||
f962884341 | |||
6f35cc8bfa | |||
c08c9bc216 | |||
239652be7c | |||
68c9ec0f82 | |||
da07122997 | |||
5fb66dc6ee | |||
0c414fc8a6 | |||
097507a2d9 | |||
466b3fcead | |||
81dc6d1269 | |||
b6c020d35d | |||
dfbe97988f | |||
cd36679a1c | |||
4d555bce96 | |||
d96c6012c5 | |||
15793e714d | |||
437cb94dda | |||
544765e408 | |||
472b1f0da1 | |||
867b2eee40 | |||
5a30b15d1e | |||
0f2c507c30 | |||
c545916332 | |||
ac81f5f624 | |||
50ae7ab558 | |||
a5e29ed745 | |||
6d29170342 | |||
410314022f | |||
815e00d389 | |||
fbf5455f89 | |||
8925704555 | |||
462365dc97 | |||
e73dd52973 | |||
881eec4e02 | |||
bcdfc73767 | |||
0520aa3d40 | |||
c562d17b78 | |||
aee68520b3 | |||
88d8bf63f5 | |||
303887ea37 | |||
51d3d33175 | |||
cdb5ea279d | |||
311e1b318a | |||
31c5b6f1db | |||
a024f81e5d | |||
4089fca87c | |||
99533a9687 | |||
d175a38ad1 | |||
28e918be18 | |||
b4403ff959 | |||
8c548bad92 | |||
6ecad9af72 | |||
df73f9a18f | |||
9b453327a8 | |||
071552ffd5 | |||
33a0b4b295 | |||
21bcd0780c | |||
f6cdf2914c | |||
7698a62c1f | |||
2ae22cdb30 | |||
7705432820 | |||
f150832676 | |||
80c9375d65 | |||
48ddff9e85 | |||
6f64fe02d5 | |||
61ab4d8d58 | |||
3bb962a266 | |||
c286dc4f5c | |||
9d36ded2b3 | |||
71686405e0 | |||
34c4a9c508 | |||
effafd3e91 | |||
5a61bdf2b0 | |||
d21fcfd1c6 | |||
fff9a27362 | |||
ad7872a0e3 | |||
f3ea2ccc21 | |||
e959a9e795 | |||
3fe5eac56d | |||
67191be78d | |||
00cfb67b64 | |||
35aa8f5a94 | |||
f44972b8b3 | |||
94675a3011 | |||
7112fbee7e | |||
ff13633962 | |||
cb93e34de0 | |||
883968f53e | |||
d6d4b579c9 | |||
0e83d84360 | |||
63a6b3bdba | |||
aafa7e112a | |||
804eb7aa5a | |||
eeba641732 | |||
932ea6cb1d | |||
dd4724e374 | |||
e652c9956e | |||
d11767776e | |||
daefa58c0c | |||
7fe7299e7c | |||
0af9c6e8b0 | |||
b9c2113d43 | |||
4fd23de9b6 | |||
3b372ebe86 | |||
d14d149a3b | |||
44acf7dace | |||
da7efdb1a8 | |||
444f39f9ff | |||
fd9c26f016 | |||
7ef9f5cd65 | |||
d3321b3c57 | |||
bbe546008f | |||
5ec91e2d20 | |||
fbe4df0251 | |||
e5c690eb89 | |||
aeedd114a6 | |||
dfa5e0e005 | |||
5911d370e5 | |||
baf769c462 | |||
33e8e0890b | |||
e2e82edefb | |||
da1b5c6953 | |||
629725e262 | |||
6ba4c0091b | |||
99d5261aab | |||
97487cf0c4 | |||
8436f2e2bb | |||
310e436163 | |||
b64477fd7e | |||
782da43114 | |||
37854b693b | |||
7360b72c7b | |||
6f68f268c0 | |||
983587aeb7 | |||
ee415d2e4a | |||
0c075d7fe4 | |||
eec3653c6b | |||
5ac2a24611 | |||
144683d7b3 | |||
9c917a9119 | |||
dc48b84191 | |||
8555d31ddf | |||
cb0dde2a80 | |||
5f5b1f751b | |||
24c5dad929 | |||
f0046fcd57 | |||
3c3e415175 | |||
00d3355f43 | |||
907a14faff | |||
4348e89f99 | |||
7a24cc54f8 | |||
80f6e3c272 | |||
edb1297c4a | |||
1ee157f943 | |||
1b2981b06e | |||
7203fefd33 | |||
d808b2dd19 | |||
ee34a1e361 | |||
1766f91697 | |||
b3aa28d085 | |||
a605d7af11 | |||
19b1a33c48 | |||
04aa511448 | |||
8dc3d4466b | |||
0716a58ff0 | |||
60052081b4 | |||
f11d49b264 | |||
103dae6d08 | |||
821ed7b25e | |||
87f83b6f30 | |||
ace81d797e | |||
57ca2c7c6d | |||
8360d9e045 | |||
560ffbbb6a | |||
72314606f3 | |||
db009b69dd | |||
3ed99dc0ce | |||
762a7c99d5 | |||
4e62156b70 | |||
cc49536755 | |||
54b844dc3b | |||
1e8ba13f66 | |||
93011cee9c | |||
a474a5c73c | |||
17b98ca99d | |||
281eedb71e | |||
1ee533591c | |||
b87e1df140 | |||
f88239a13e | |||
68476cbc00 | |||
f2c1f64f02 | |||
a7209184c8 | |||
ba59e29499 | |||
f94196d865 | |||
bb5a9f9737 | |||
4bc5cf7c64 | |||
639d14452b | |||
e7413fb741 | |||
c0e720498d | |||
383c3b4be6 | |||
e9b202f5c8 | |||
bc3005a6a4 | |||
8cf19e0594 | |||
b137b57dbc | |||
5dff8927da | |||
197e79dd07 | |||
6262aca761 | |||
c156ae704b | |||
a67979ec40 | |||
54bfc11620 | |||
d33c2cd3a2 | |||
3a5f428fb6 | |||
0331152569 | |||
1b7e854f5f | |||
12a945d863 |
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
* Ability to choose between RocksDB and SQLite databases
|
* Ability to choose between RocksDB and SQLite databases
|
||||||
* Added direct reads and implemented download fallback
|
* Added direct reads and implemented download fallback
|
||||||
|
* Comprehensive WinFSP and FUSE unit tests, including remote testing
|
||||||
* Corrected file times on S3 and Sia providers
|
* Corrected file times on S3 and Sia providers
|
||||||
* Corrected handling of `chown()` and `chmod()`
|
* Corrected handling of `chown()` and `chmod()`
|
||||||
* Fixed erroneous download of chunks after resize
|
* Fixed erroneous download of chunks after resize
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_DIRECT_OPEN_FILE_HPP_
|
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_DIRECT_OPEN_FILE_HPP_
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_DIRECT_OPEN_FILE_HPP_
|
#define REPERTORY_INCLUDE_FILE_MANAGER_DIRECT_OPEN_FILE_HPP_
|
||||||
|
|
||||||
#include "file_manager/ring_buffer_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ namespace repertory {
|
|||||||
class i_provider;
|
class i_provider;
|
||||||
class i_upload_manager;
|
class i_upload_manager;
|
||||||
|
|
||||||
class direct_open_file final : public ring_buffer_base {
|
class direct_open_file final : public open_file_base {
|
||||||
public:
|
public:
|
||||||
direct_open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
direct_open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
||||||
filesystem_item fsi, i_provider &provider);
|
filesystem_item fsi, i_provider &provider);
|
||||||
@ -42,38 +42,61 @@ public:
|
|||||||
direct_open_file(const direct_open_file &) noexcept = delete;
|
direct_open_file(const direct_open_file &) noexcept = delete;
|
||||||
direct_open_file(direct_open_file &&) noexcept = delete;
|
direct_open_file(direct_open_file &&) noexcept = delete;
|
||||||
auto operator=(direct_open_file &&) noexcept -> direct_open_file & = delete;
|
auto operator=(direct_open_file &&) noexcept -> direct_open_file & = delete;
|
||||||
auto
|
auto operator=(const direct_open_file &) noexcept
|
||||||
operator=(const direct_open_file &) noexcept -> direct_open_file & = delete;
|
-> direct_open_file & = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<data_buffer, min_ring_size> ring_data_;
|
std::atomic<std::uint64_t> last_progress_{0U};
|
||||||
|
std::size_t total_chunks_;
|
||||||
|
stop_type stop_requested_{false};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto on_check_start() -> bool override;
|
[[nodiscard]] auto is_download_complete() const -> bool override {
|
||||||
|
return false;
|
||||||
[[nodiscard]] auto
|
|
||||||
on_chunk_downloaded(std::size_t /* chunk */,
|
|
||||||
const data_buffer & /* buffer */) -> api_error override {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
on_read_chunk(std::size_t chunk, std::size_t read_size,
|
|
||||||
std::uint64_t read_offset, data_buffer &data,
|
|
||||||
std::size_t &bytes_read) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto use_buffer(std::size_t chunk,
|
|
||||||
std::function<api_error(data_buffer &)> func)
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
auto close() -> bool override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto is_complete() const -> bool override { return true; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto is_write_supported() const -> bool override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_read_state() const
|
||||||
|
-> boost::dynamic_bitset<> override {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_read_state(std::size_t /* chunk */) const
|
||||||
|
-> bool override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_total_chunks() const -> std::uint64_t {
|
||||||
|
return total_chunks_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto native_operation(native_operation_callback /* callback */)
|
[[nodiscard]] auto native_operation(native_operation_callback /* callback */)
|
||||||
-> api_error override {
|
-> api_error override {
|
||||||
return api_error::not_supported;
|
return api_error::not_supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto native_operation(std::uint64_t /* new_file_size */,
|
[[nodiscard]] auto native_operation(std::uint64_t /* new_file_size */,
|
||||||
native_operation_callback /* callback */)
|
native_operation_callback /*callback*/)
|
||||||
|
-> api_error override {
|
||||||
|
return api_error::not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto read(std::size_t read_size, std::uint64_t read_offset,
|
||||||
|
data_buffer &data) -> api_error override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto resize(std::uint64_t /*size*/) -> api_error override {
|
||||||
|
return api_error::not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto write(std::uint64_t, const data_buffer &, std::size_t &)
|
||||||
-> api_error override {
|
-> api_error override {
|
||||||
return api_error::not_supported;
|
return api_error::not_supported;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,23 @@ E_SIMPLE2(download_begin, info, true,
|
|||||||
std::string, dest_path, dest, E_FROM_STRING
|
std::string, dest_path, dest, E_FROM_STRING
|
||||||
);
|
);
|
||||||
|
|
||||||
|
E_SIMPLE5(download_chunk_begin, debug, true,
|
||||||
|
std::string, api_path, ap, E_FROM_STRING,
|
||||||
|
std::string, dest_path, dest, E_FROM_STRING,
|
||||||
|
std::size_t, chunk, chunk, E_FROM_SIZE_T,
|
||||||
|
std::size_t, total, total, E_FROM_SIZE_T,
|
||||||
|
std::size_t, complete, complete, E_FROM_SIZE_T
|
||||||
|
);
|
||||||
|
|
||||||
|
E_SIMPLE6(download_chunk_end, debug, true,
|
||||||
|
std::string, api_path, ap, E_FROM_STRING,
|
||||||
|
std::string, dest_path, dest, E_FROM_STRING,
|
||||||
|
std::size_t, chunk, chunk, E_FROM_SIZE_T,
|
||||||
|
std::size_t, total, total, E_FROM_SIZE_T,
|
||||||
|
std::size_t, complete, complete, E_FROM_SIZE_T,
|
||||||
|
api_error, result, result, E_FROM_API_FILE_ERROR
|
||||||
|
);
|
||||||
|
|
||||||
E_SIMPLE3(download_end, info, true,
|
E_SIMPLE3(download_end, info, true,
|
||||||
std::string, api_path, ap, E_FROM_STRING,
|
std::string, api_path, ap, E_FROM_STRING,
|
||||||
std::string, dest_path, dest, E_FROM_STRING,
|
std::string, dest_path, dest, E_FROM_STRING,
|
||||||
|
@ -62,12 +62,8 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] virtual auto get_source_path() const -> std::string = 0;
|
[[nodiscard]] virtual auto get_source_path() const -> std::string = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_complete() const -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_directory() const -> bool = 0;
|
[[nodiscard]] virtual auto is_directory() const -> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_write_supported() const -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto has_handle(std::uint64_t handle) const -> bool = 0;
|
[[nodiscard]] virtual auto has_handle(std::uint64_t handle) const -> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto
|
||||||
@ -86,6 +82,9 @@ public:
|
|||||||
|
|
||||||
virtual void set_api_path(const std::string &api_path) = 0;
|
virtual void set_api_path(const std::string &api_path) = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
set_open_data(std::map<std::uint64_t, open_file_data> open_data) = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto write(std::uint64_t write_offset,
|
[[nodiscard]] virtual auto write(std::uint64_t write_offset,
|
||||||
const data_buffer &data,
|
const data_buffer &data,
|
||||||
std::size_t &bytes_written) -> api_error = 0;
|
std::size_t &bytes_written) -> api_error = 0;
|
||||||
@ -106,8 +105,12 @@ public:
|
|||||||
[[nodiscard]] virtual auto get_handles() const
|
[[nodiscard]] virtual auto get_handles() const
|
||||||
-> std::vector<std::uint64_t> = 0;
|
-> std::vector<std::uint64_t> = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto is_complete() const -> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_modified() const -> bool = 0;
|
[[nodiscard]] virtual auto is_modified() const -> bool = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto is_write_supported() const -> bool = 0;
|
||||||
|
|
||||||
virtual void remove(std::uint64_t handle) = 0;
|
virtual void remove(std::uint64_t handle) = 0;
|
||||||
|
|
||||||
virtual void remove_all() = 0;
|
virtual void remove_all() = 0;
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "file_manager/open_file_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/types/file/i_file.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class i_provider;
|
class i_provider;
|
||||||
@ -69,19 +68,19 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool allocated{false};
|
bool allocated{false};
|
||||||
std::unique_ptr<utils::file::i_file> nf_;
|
|
||||||
bool notified_{false};
|
bool notified_{false};
|
||||||
std::size_t read_chunk_{};
|
std::size_t read_chunk_{};
|
||||||
boost::dynamic_bitset<> read_state_;
|
boost::dynamic_bitset<> read_state_;
|
||||||
std::unique_ptr<std::thread> reader_thread_;
|
std::unique_ptr<std::thread> reader_thread_;
|
||||||
|
std::unique_ptr<std::thread> download_thread_;
|
||||||
mutable std::recursive_mutex rw_mtx_;
|
mutable std::recursive_mutex rw_mtx_;
|
||||||
stop_type stop_requested_{false};
|
stop_type stop_requested_{false};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] auto adjust_cache_size(std::uint64_t file_size,
|
[[nodiscard]] auto adjust_cache_size(std::uint64_t file_size, bool shrink)
|
||||||
bool shrink) -> api_error;
|
-> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto check_start() -> api_error;
|
[[nodiscard]] auto check_allocation() -> api_error;
|
||||||
|
|
||||||
void download_chunk(std::size_t chunk, bool skip_active, bool should_reset);
|
void download_chunk(std::size_t chunk, bool skip_active, bool should_reset);
|
||||||
|
|
||||||
@ -94,7 +93,10 @@ private:
|
|||||||
|
|
||||||
void set_read_state(boost::dynamic_bitset<> read_state);
|
void set_read_state(boost::dynamic_bitset<> read_state);
|
||||||
|
|
||||||
void update_reader(std::size_t chunk);
|
void update_background_reader(std::size_t read_chunk);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] auto is_download_complete() const -> bool override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto close() -> bool override;
|
auto close() -> bool override;
|
||||||
@ -111,12 +113,12 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto native_operation(native_operation_callback callback)
|
||||||
native_operation(native_operation_callback callback) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto native_operation(std::uint64_t new_file_size,
|
||||||
native_operation(std::uint64_t new_file_size,
|
native_operation_callback callback)
|
||||||
native_operation_callback callback) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
void remove(std::uint64_t handle) override;
|
void remove(std::uint64_t handle) override;
|
||||||
|
|
||||||
|
@ -24,18 +24,21 @@
|
|||||||
|
|
||||||
#include "file_manager/i_open_file.hpp"
|
#include "file_manager/i_open_file.hpp"
|
||||||
|
|
||||||
|
#include "utils/types/file/i_file.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class i_provider;
|
class i_provider;
|
||||||
|
|
||||||
class open_file_base : public i_closeable_open_file {
|
class open_file_base : public i_closeable_open_file {
|
||||||
public:
|
public:
|
||||||
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
||||||
filesystem_item fsi, i_provider &provider, bool disable_io);
|
filesystem_item fsi, i_provider &provider,
|
||||||
|
bool disable_io = false);
|
||||||
|
|
||||||
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
||||||
filesystem_item fsi,
|
filesystem_item fsi,
|
||||||
std::map<std::uint64_t, open_file_data> open_data,
|
std::map<std::uint64_t, open_file_data> open_data,
|
||||||
i_provider &provider, bool disable_io);
|
i_provider &provider, bool disable_io = false);
|
||||||
|
|
||||||
~open_file_base() override = default;
|
~open_file_base() override = default;
|
||||||
|
|
||||||
@ -96,7 +99,7 @@ public:
|
|||||||
[[nodiscard]] auto get_result() -> api_error;
|
[[nodiscard]] auto get_result() -> api_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::uint64_t chunk_size_;
|
std::uint64_t chunk_size_;
|
||||||
std::uint8_t chunk_timeout_;
|
std::uint8_t chunk_timeout_;
|
||||||
filesystem_item fsi_;
|
filesystem_item fsi_;
|
||||||
@ -105,19 +108,21 @@ private:
|
|||||||
i_provider &provider_;
|
i_provider &provider_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::size_t, std::shared_ptr<download>> active_downloads_;
|
|
||||||
api_error error_{api_error::success};
|
api_error error_{api_error::success};
|
||||||
mutable std::mutex error_mtx_;
|
mutable std::mutex error_mtx_;
|
||||||
mutable std::recursive_mutex file_mtx_;
|
|
||||||
stop_type io_stop_requested_{false};
|
stop_type io_stop_requested_{false};
|
||||||
std::unique_ptr<std::thread> io_thread_;
|
std::unique_ptr<std::thread> io_thread_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unordered_map<std::size_t, std::shared_ptr<download>> active_downloads_;
|
||||||
|
mutable std::recursive_mutex file_mtx_;
|
||||||
|
std::atomic<std::chrono::system_clock::time_point> last_access_{
|
||||||
|
std::chrono::system_clock::now()};
|
||||||
|
bool modified_{false};
|
||||||
|
std::unique_ptr<utils::file::i_file> nf_;
|
||||||
mutable std::mutex io_thread_mtx_;
|
mutable std::mutex io_thread_mtx_;
|
||||||
std::condition_variable io_thread_notify_;
|
std::condition_variable io_thread_notify_;
|
||||||
std::deque<std::shared_ptr<io_item>> io_thread_queue_;
|
std::deque<std::shared_ptr<io_item>> io_thread_queue_;
|
||||||
std::atomic<std::chrono::system_clock::time_point> last_access_{
|
|
||||||
std::chrono::system_clock::now(),
|
|
||||||
};
|
|
||||||
bool modified_{false};
|
|
||||||
bool removed_{false};
|
bool removed_{false};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -126,42 +131,11 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto do_io(std::function<api_error()> action) -> api_error;
|
[[nodiscard]] auto do_io(std::function<api_error()> action) -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto get_active_downloads()
|
[[nodiscard]] virtual auto is_download_complete() const -> bool = 0;
|
||||||
-> std::unordered_map<std::size_t, std::shared_ptr<download>> & {
|
|
||||||
return active_downloads_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_mutex() const -> std::recursive_mutex & {
|
|
||||||
return file_mtx_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_last_chunk_size() const -> std::size_t;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_provider() -> i_provider & { return provider_; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_provider() const -> const i_provider & {
|
|
||||||
return provider_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto is_removed() const -> bool;
|
|
||||||
|
|
||||||
void notify_io();
|
|
||||||
|
|
||||||
void reset_timeout();
|
void reset_timeout();
|
||||||
|
|
||||||
auto set_api_error(const api_error &err) -> api_error;
|
auto set_api_error(const api_error &e) -> api_error;
|
||||||
|
|
||||||
void set_file_size(std::uint64_t size);
|
|
||||||
|
|
||||||
void set_last_chunk_size(std::size_t size);
|
|
||||||
|
|
||||||
void set_modified(bool modified);
|
|
||||||
|
|
||||||
void set_removed(bool removed);
|
|
||||||
|
|
||||||
void set_source_path(std::string source_path);
|
|
||||||
|
|
||||||
void wait_for_io(stop_type &stop_requested);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void add(std::uint64_t handle, open_file_data ofd) override;
|
void add(std::uint64_t handle, open_file_data ofd) override;
|
||||||
@ -186,21 +160,23 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] auto get_handles() const -> std::vector<std::uint64_t> override;
|
[[nodiscard]] auto get_handles() const -> std::vector<std::uint64_t> override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_data()
|
||||||
get_open_data() -> std::map<std::uint64_t, open_file_data> & override;
|
-> std::map<std::uint64_t, open_file_data> & override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_open_data() const
|
[[nodiscard]] auto get_open_data() const
|
||||||
-> const std::map<std::uint64_t, open_file_data> & override;
|
-> const std::map<std::uint64_t, open_file_data> & override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_data(std::uint64_t handle)
|
||||||
get_open_data(std::uint64_t handle) -> open_file_data & override;
|
-> open_file_data & override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_data(std::uint64_t handle) const
|
||||||
get_open_data(std::uint64_t handle) const -> const open_file_data & override;
|
-> const open_file_data & override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_open_file_count() const -> std::size_t override;
|
[[nodiscard]] auto get_open_file_count() const -> std::size_t override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_source_path() const -> std::string override;
|
[[nodiscard]] auto get_source_path() const -> std::string override {
|
||||||
|
return fsi_.source_path;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto has_handle(std::uint64_t handle) const -> bool override;
|
[[nodiscard]] auto has_handle(std::uint64_t handle) const -> bool override;
|
||||||
|
|
||||||
@ -215,6 +191,9 @@ public:
|
|||||||
void remove_all() override;
|
void remove_all() override;
|
||||||
|
|
||||||
void set_api_path(const std::string &api_path) override;
|
void set_api_path(const std::string &api_path) override;
|
||||||
|
|
||||||
|
void
|
||||||
|
set_open_data(std::map<std::uint64_t, open_file_data> open_data) override;
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_BASE_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_BASE_HPP_
|
|
||||||
|
|
||||||
#include "file_manager/open_file_base.hpp"
|
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
#include "utils/file.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class i_provider;
|
|
||||||
class i_upload_manager;
|
|
||||||
|
|
||||||
class ring_buffer_base : public open_file_base {
|
|
||||||
public:
|
|
||||||
ring_buffer_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|
||||||
filesystem_item fsi, i_provider &provider,
|
|
||||||
std::size_t ring_size, bool disable_io);
|
|
||||||
|
|
||||||
~ring_buffer_base() override = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ring_buffer_base() = delete;
|
|
||||||
ring_buffer_base(const ring_buffer_base &) noexcept = delete;
|
|
||||||
ring_buffer_base(ring_buffer_base &&) noexcept = delete;
|
|
||||||
auto operator=(ring_buffer_base &&) noexcept -> ring_buffer_base & = delete;
|
|
||||||
auto
|
|
||||||
operator=(const ring_buffer_base &) noexcept -> ring_buffer_base & = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr const auto min_ring_size{5U};
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::dynamic_bitset<> read_state_;
|
|
||||||
std::size_t total_chunks_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::condition_variable chunk_notify_;
|
|
||||||
mutable std::mutex chunk_mtx_;
|
|
||||||
std::mutex read_mtx_;
|
|
||||||
std::unique_ptr<std::thread> reader_thread_;
|
|
||||||
std::size_t ring_begin_{};
|
|
||||||
std::size_t ring_end_{};
|
|
||||||
std::size_t ring_pos_{};
|
|
||||||
stop_type stop_requested_{false};
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] auto check_start() -> api_error;
|
|
||||||
|
|
||||||
auto download_chunk(std::size_t chunk, bool skip_active) -> api_error;
|
|
||||||
|
|
||||||
void reader_thread();
|
|
||||||
|
|
||||||
void update_position(std::size_t count, bool is_forward);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
[[nodiscard]] auto has_reader_thread() const -> bool {
|
|
||||||
return reader_thread_ != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_ring_size() const -> std::size_t {
|
|
||||||
return read_state_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto on_check_start() -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
on_chunk_downloaded(std::size_t chunk,
|
|
||||||
const data_buffer &buffer) -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
on_read_chunk(std::size_t chunk, std::size_t read_size,
|
|
||||||
std::uint64_t read_offset, data_buffer &data,
|
|
||||||
std::size_t &bytes_read) -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
use_buffer(std::size_t chunk,
|
|
||||||
std::function<api_error(data_buffer &)> func) -> api_error = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
auto close() -> bool override;
|
|
||||||
|
|
||||||
void forward(std::size_t count);
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_current_chunk() const -> std::size_t {
|
|
||||||
return ring_pos_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_first_chunk() const -> std::size_t {
|
|
||||||
return ring_begin_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_last_chunk() const -> std::size_t { return ring_end_; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_read_state() const -> boost::dynamic_bitset<> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_read_state(std::size_t chunk) const -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_total_chunks() const -> std::size_t {
|
|
||||||
return total_chunks_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto is_complete() const -> bool override { return false; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto is_write_supported() const -> bool override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto read(std::size_t read_size, std::uint64_t read_offset,
|
|
||||||
data_buffer &data) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto resize(std::uint64_t /* size */) -> api_error override {
|
|
||||||
return api_error::not_supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reverse(std::size_t count);
|
|
||||||
|
|
||||||
void set(std::size_t first_chunk, std::size_t current_chunk);
|
|
||||||
|
|
||||||
void set_api_path(const std::string &api_path) override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
write(std::uint64_t /* write_offset */, const data_buffer & /* data */,
|
|
||||||
std::size_t & /* bytes_written */) -> api_error override {
|
|
||||||
return api_error::not_supported;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_BASE_HPP_
|
|
@ -22,16 +22,15 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
#define REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
||||||
|
|
||||||
#include "file_manager/ring_buffer_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/file.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class i_provider;
|
class i_provider;
|
||||||
class i_upload_manager;
|
class i_upload_manager;
|
||||||
|
|
||||||
class ring_buffer_open_file final : public ring_buffer_base {
|
class ring_buffer_open_file final : public open_file_base {
|
||||||
public:
|
public:
|
||||||
ring_buffer_open_file(std::string buffer_directory, std::uint64_t chunk_size,
|
ring_buffer_open_file(std::string buffer_directory, std::uint64_t chunk_size,
|
||||||
std::uint8_t chunk_timeout, filesystem_item fsi,
|
std::uint8_t chunk_timeout, filesystem_item fsi,
|
||||||
@ -43,49 +42,95 @@ public:
|
|||||||
ring_buffer_open_file() = delete;
|
ring_buffer_open_file() = delete;
|
||||||
ring_buffer_open_file(const ring_buffer_open_file &) noexcept = delete;
|
ring_buffer_open_file(const ring_buffer_open_file &) noexcept = delete;
|
||||||
ring_buffer_open_file(ring_buffer_open_file &&) noexcept = delete;
|
ring_buffer_open_file(ring_buffer_open_file &&) noexcept = delete;
|
||||||
auto operator=(ring_buffer_open_file &&) noexcept -> ring_buffer_open_file & =
|
auto operator=(ring_buffer_open_file &&) noexcept
|
||||||
delete;
|
-> ring_buffer_open_file & = delete;
|
||||||
auto operator=(const ring_buffer_open_file &) noexcept
|
auto operator=(const ring_buffer_open_file &) noexcept
|
||||||
-> ring_buffer_open_file & = delete;
|
-> ring_buffer_open_file & = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string source_path_;
|
boost::dynamic_bitset<> ring_state_;
|
||||||
|
std::size_t total_chunks_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<utils::file::i_file> nf_;
|
std::unique_ptr<std::thread> chunk_forward_thread_;
|
||||||
|
std::unique_ptr<std::thread> chunk_reverse_thread_;
|
||||||
|
std::condition_variable chunk_notify_;
|
||||||
|
mutable std::mutex chunk_mtx_;
|
||||||
|
std::mutex read_mtx_;
|
||||||
|
std::unique_ptr<std::thread> reader_thread_;
|
||||||
|
std::size_t ring_begin_{};
|
||||||
|
std::size_t ring_end_{};
|
||||||
|
std::size_t ring_pos_{};
|
||||||
|
std::string source_path_;
|
||||||
|
stop_type stop_requested_{false};
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto download_chunk(std::size_t chunk, bool skip_active) -> api_error;
|
||||||
|
|
||||||
|
void background_reader_thread();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto on_check_start() -> bool override;
|
[[nodiscard]] auto is_download_complete() const -> bool override {
|
||||||
|
return false;
|
||||||
[[nodiscard]] auto
|
}
|
||||||
on_chunk_downloaded(std::size_t chunk,
|
|
||||||
const data_buffer &buffer) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
on_read_chunk(std::size_t chunk, std::size_t read_size,
|
|
||||||
std::uint64_t read_offset, data_buffer &data,
|
|
||||||
std::size_t &bytes_read) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto use_buffer(std::size_t chunk,
|
|
||||||
std::function<api_error(data_buffer &)> func)
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static auto can_handle_file(std::uint64_t file_size,
|
[[nodiscard]] static auto can_handle_file(std::uint64_t file_size,
|
||||||
std::size_t chunk_size,
|
std::size_t chunk_size,
|
||||||
std::size_t ring_size) -> bool;
|
std::size_t ring_size) -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
auto close() -> bool override;
|
||||||
native_operation(native_operation_callback callback) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto native_operation(std::uint64_t /* new_file_size */,
|
void forward(std::size_t count);
|
||||||
native_operation_callback /* callback */)
|
|
||||||
|
[[nodiscard]] auto get_current_chunk() const -> std::size_t {
|
||||||
|
return ring_pos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_first_chunk() const -> std::size_t {
|
||||||
|
return ring_begin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_last_chunk() const -> std::size_t { return ring_end_; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_read_state() const -> boost::dynamic_bitset<> override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_read_state(std::size_t chunk) const -> bool override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_total_chunks() const -> std::size_t {
|
||||||
|
return total_chunks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto is_complete() const -> bool override { return true; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto is_write_supported() const -> bool override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto native_operation(native_operation_callback callback)
|
||||||
|
-> api_error override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto native_operation(std::uint64_t, native_operation_callback)
|
||||||
-> api_error override {
|
-> api_error override {
|
||||||
return api_error::not_supported;
|
return api_error::not_supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_source_path() const -> std::string override {
|
[[nodiscard]] auto read(std::size_t read_size, std::uint64_t read_offset,
|
||||||
return source_path_;
|
data_buffer &data) -> api_error override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto resize(std::uint64_t /* size */) -> api_error override {
|
||||||
|
return api_error::not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse(std::size_t count);
|
||||||
|
|
||||||
|
void set(std::size_t first_chunk, std::size_t current_chunk);
|
||||||
|
|
||||||
|
void set_api_path(const std::string &api_path) override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto write(std::uint64_t, const data_buffer &, std::size_t &)
|
||||||
|
-> api_error override {
|
||||||
|
return api_error::not_supported;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -29,7 +29,7 @@ constexpr const auto default_eviction_delay_mins{1U};
|
|||||||
constexpr const auto default_high_freq_interval_secs{30U};
|
constexpr const auto default_high_freq_interval_secs{30U};
|
||||||
constexpr const auto default_low_freq_interval_secs{0U * 60U};
|
constexpr const auto default_low_freq_interval_secs{0U * 60U};
|
||||||
constexpr const auto default_max_cache_size_bytes{
|
constexpr const auto default_max_cache_size_bytes{
|
||||||
std::uint64_t(20UL * 1024UL * 1024UL * 1024UL),
|
20UL * 1024UL * 1024UL * 1024UL,
|
||||||
};
|
};
|
||||||
constexpr const auto default_max_upload_count{5U};
|
constexpr const auto default_max_upload_count{5U};
|
||||||
constexpr const auto default_med_freq_interval_secs{2U * 60U};
|
constexpr const auto default_med_freq_interval_secs{2U * 60U};
|
||||||
@ -216,31 +216,33 @@ enum class api_error {
|
|||||||
|
|
||||||
[[nodiscard]] auto api_error_from_string(std::string_view str) -> api_error;
|
[[nodiscard]] auto api_error_from_string(std::string_view str) -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto api_error_to_string(const api_error &error)
|
||||||
api_error_to_string(const api_error &error) -> const std::string &;
|
-> const std::string &;
|
||||||
|
|
||||||
enum class database_type {
|
enum class database_type {
|
||||||
rocksdb,
|
rocksdb,
|
||||||
sqlite,
|
sqlite,
|
||||||
};
|
};
|
||||||
[[nodiscard]] auto database_type_from_string(
|
|
||||||
std::string type,
|
|
||||||
database_type default_type = database_type::rocksdb) -> database_type;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto
|
||||||
database_type_to_string(const database_type &type) -> std::string;
|
database_type_from_string(std::string type,
|
||||||
|
database_type default_type = database_type::rocksdb)
|
||||||
|
-> database_type;
|
||||||
|
|
||||||
|
[[nodiscard]] auto database_type_to_string(const database_type &type)
|
||||||
|
-> std::string;
|
||||||
|
|
||||||
enum class download_type {
|
enum class download_type {
|
||||||
default_,
|
|
||||||
direct,
|
direct,
|
||||||
|
fallback,
|
||||||
ring_buffer,
|
ring_buffer,
|
||||||
};
|
};
|
||||||
[[nodiscard]] auto download_type_from_string(
|
|
||||||
std::string type,
|
|
||||||
download_type default_type = download_type::default_) -> download_type;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto
|
||||||
download_type_to_string(const download_type &type) -> std::string;
|
download_type_from_string(std::string type,
|
||||||
|
download_type default_type = download_type::fallback)
|
||||||
|
-> download_type;
|
||||||
|
|
||||||
|
[[nodiscard]] auto download_type_to_string(const download_type &type)
|
||||||
|
-> std::string;
|
||||||
|
|
||||||
enum class exit_code : std::int32_t {
|
enum class exit_code : std::int32_t {
|
||||||
success = 0,
|
success = 0,
|
||||||
|
@ -80,7 +80,7 @@ app_config::app_config(const provider_type &prov,
|
|||||||
med_freq_interval_secs_(default_med_freq_interval_secs),
|
med_freq_interval_secs_(default_med_freq_interval_secs),
|
||||||
online_check_retry_secs_(default_online_check_retry_secs),
|
online_check_retry_secs_(default_online_check_retry_secs),
|
||||||
orphaned_file_retention_days_(default_orphaned_file_retention_days),
|
orphaned_file_retention_days_(default_orphaned_file_retention_days),
|
||||||
preferred_download_type_(download_type::default_),
|
preferred_download_type_(download_type::fallback),
|
||||||
retry_read_count_(default_retry_read_count),
|
retry_read_count_(default_retry_read_count),
|
||||||
ring_buffer_file_size_(default_ring_buffer_file_size),
|
ring_buffer_file_size_(default_ring_buffer_file_size),
|
||||||
task_wait_ms_(default_task_wait_ms) {
|
task_wait_ms_(default_task_wait_ms) {
|
||||||
@ -1171,13 +1171,8 @@ void app_config::set_low_frequency_interval_secs(std::uint16_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void app_config::set_max_cache_size_bytes(std::uint64_t value) {
|
void app_config::set_max_cache_size_bytes(std::uint64_t value) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
set_value(max_cache_size_bytes_, value);
|
set_value(max_cache_size_bytes_, value);
|
||||||
auto res = cache_size_mgr::instance().shrink(0U);
|
cache_size_mgr::instance().shrink(0U);
|
||||||
if (res != api_error::success) {
|
|
||||||
utils::error::raise_error(function_name, res, "failed to shrink cache");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_config::set_max_upload_count(std::uint8_t value) {
|
void app_config::set_max_upload_count(std::uint8_t value) {
|
||||||
|
@ -81,8 +81,8 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::chown_impl(std::string api_path, uid_t uid,
|
auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
||||||
gid_t gid) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
return check_and_perform(
|
return check_and_perform(
|
||||||
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
||||||
@ -481,8 +481,8 @@ auto fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st,
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::getattr_impl(std::string api_path,
|
auto fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
|
||||||
struct stat *unix_st) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
auto parent = utils::path::get_parent_api_path(api_path);
|
auto parent = utils::path::get_parent_api_path(api_path);
|
||||||
|
|
||||||
@ -565,8 +565,8 @@ auto fuse_drive::getxtimes_impl(std::string api_path, struct timespec *bkuptime,
|
|||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
auto fuse_drive::init_impl(struct fuse_conn_info *conn,
|
auto fuse_drive::init_impl(struct fuse_conn_info *conn, struct fuse_config *cfg)
|
||||||
struct fuse_config *cfg) -> void * {
|
-> void * {
|
||||||
#else
|
#else
|
||||||
void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
||||||
#endif
|
#endif
|
||||||
@ -800,8 +800,9 @@ auto fuse_drive::release_impl(std::string /*api_path*/,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::releasedir_impl(
|
auto fuse_drive::releasedir_impl(std::string /*api_path*/,
|
||||||
std::string /*api_path*/, struct fuse_file_info *file_info) -> api_error {
|
struct fuse_file_info *file_info)
|
||||||
|
-> api_error {
|
||||||
auto iter = directory_cache_->get_directory(file_info->fh);
|
auto iter = directory_cache_->get_directory(file_info->fh);
|
||||||
if (iter == nullptr) {
|
if (iter == nullptr) {
|
||||||
return api_error::invalid_handle;
|
return api_error::invalid_handle;
|
||||||
@ -819,8 +820,8 @@ auto fuse_drive::rename_directory(const std::string &from_api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::rename_file(const std::string &from_api_path,
|
auto fuse_drive::rename_file(const std::string &from_api_path,
|
||||||
const std::string &to_api_path,
|
const std::string &to_api_path, bool overwrite)
|
||||||
bool overwrite) -> int {
|
-> int {
|
||||||
auto res = fm_->rename_file(from_api_path, to_api_path, overwrite);
|
auto res = fm_->rename_file(from_api_path, to_api_path, overwrite);
|
||||||
errno = std::abs(utils::from_api_error(res));
|
errno = std::abs(utils::from_api_error(res));
|
||||||
return (res == api_error::success) ? 0 : -1;
|
return (res == api_error::success) ? 0 : -1;
|
||||||
@ -830,8 +831,8 @@ auto fuse_drive::rename_file(const std::string &from_api_path,
|
|||||||
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path,
|
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path,
|
||||||
unsigned int /*flags*/) -> api_error {
|
unsigned int /*flags*/) -> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::rename_impl(std::string from_api_path,
|
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path)
|
||||||
std::string to_api_path) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
auto res = check_parent_access(to_api_path, W_OK | X_OK);
|
auto res = check_parent_access(to_api_path, W_OK | X_OK);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -945,15 +946,15 @@ auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
|||||||
}
|
}
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
||||||
char *value, size_t size,
|
char *value, size_t size, int &attribute_size)
|
||||||
int &attribute_size) -> api_error {
|
-> api_error {
|
||||||
return getxattr_common(api_path, name, value, size, attribute_size, nullptr);
|
return getxattr_common(api_path, name, value, size, attribute_size, nullptr);
|
||||||
}
|
}
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
||||||
int &required_size,
|
int &required_size, bool &return_size)
|
||||||
bool &return_size) -> api_error {
|
-> api_error {
|
||||||
auto check_size = (size == 0);
|
auto check_size = (size == 0);
|
||||||
|
|
||||||
auto res = check_parent_access(api_path, X_OK);
|
auto res = check_parent_access(api_path, X_OK);
|
||||||
@ -993,8 +994,8 @@ auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::removexattr_impl(std::string api_path,
|
auto fuse_drive::removexattr_impl(std::string api_path, const char *name)
|
||||||
const char *name) -> api_error {
|
-> api_error {
|
||||||
std::string attribute_name;
|
std::string attribute_name;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
auto res = parse_xattr_parameters(name, 0, attribute_name, api_path);
|
auto res = parse_xattr_parameters(name, 0, attribute_name, api_path);
|
||||||
@ -1022,8 +1023,8 @@ auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
|||||||
uint32_t position) -> api_error {
|
uint32_t position) -> api_error {
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
||||||
const char *value, size_t size,
|
const char *value, size_t size, int flags)
|
||||||
int flags) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
std::string attribute_name;
|
std::string attribute_name;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@ -1101,8 +1102,8 @@ void fuse_drive::set_item_meta(const std::string &api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
auto fuse_drive::setattr_x_impl(std::string api_path,
|
auto fuse_drive::setattr_x_impl(std::string api_path, struct setattr_x *attr)
|
||||||
struct setattr_x *attr) -> api_error {
|
-> api_error {
|
||||||
bool exists{};
|
bool exists{};
|
||||||
auto res = provider_.is_file(api_path, exists);
|
auto res = provider_.is_file(api_path, exists);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -1156,7 +1157,7 @@ auto fuse_drive::setattr_x_impl(std::string api_path,
|
|||||||
ts[0].tv_sec = attr->acctime.tv_sec;
|
ts[0].tv_sec = attr->acctime.tv_sec;
|
||||||
ts[0].tv_nsec = attr->acctime.tv_nsec;
|
ts[0].tv_nsec = attr->acctime.tv_nsec;
|
||||||
} else {
|
} else {
|
||||||
struct timeval tv {};
|
struct timeval tv{};
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
ts[0].tv_sec = tv.tv_sec;
|
ts[0].tv_sec = tv.tv_sec;
|
||||||
ts[0].tv_nsec = tv.tv_usec * 1000;
|
ts[0].tv_nsec = tv.tv_usec * 1000;
|
||||||
@ -1201,8 +1202,9 @@ auto fuse_drive::setattr_x_impl(std::string api_path,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::setbkuptime_impl(
|
auto fuse_drive::setbkuptime_impl(std::string api_path,
|
||||||
std::string api_path, const struct timespec *bkuptime) -> api_error {
|
const struct timespec *bkuptime)
|
||||||
|
-> api_error {
|
||||||
return check_and_perform(
|
return check_and_perform(
|
||||||
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
||||||
auto nanos = bkuptime->tv_nsec +
|
auto nanos = bkuptime->tv_nsec +
|
||||||
@ -1238,8 +1240,8 @@ auto fuse_drive::setvolname_impl(const char * /*volname*/) -> api_error {
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::statfs_x_impl(std::string /*api_path*/,
|
auto fuse_drive::statfs_x_impl(std::string /*api_path*/, struct statfs *stbuf)
|
||||||
struct statfs *stbuf) -> api_error {
|
-> api_error {
|
||||||
if (statfs(&config_.get_cache_directory()[0], stbuf) != 0) {
|
if (statfs(&config_.get_cache_directory()[0], stbuf) != 0) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
@ -1264,8 +1266,8 @@ auto fuse_drive::statfs_x_impl(std::string /*api_path*/,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::statfs_impl(std::string /*api_path*/,
|
auto fuse_drive::statfs_impl(std::string /*api_path*/, struct statvfs *stbuf)
|
||||||
struct statvfs *stbuf) -> api_error {
|
-> api_error {
|
||||||
if (statvfs(config_.get_cache_directory().data(), stbuf) != 0) {
|
if (statvfs(config_.get_cache_directory().data(), stbuf) != 0) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
@ -1315,10 +1317,6 @@ auto fuse_drive::truncate_impl(std::string api_path, off_t size) -> api_error {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not fm_->get_open_file(handle, true, open_file)) {
|
|
||||||
return api_error::invalid_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = open_file->resize(static_cast<std::uint64_t>(size));
|
res = open_file->resize(static_cast<std::uint64_t>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1349,8 +1347,8 @@ auto fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2],
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::utimens_impl(std::string api_path,
|
auto fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2])
|
||||||
const struct timespec tv[2]) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
api_meta_map meta;
|
api_meta_map meta;
|
||||||
auto res = provider_.get_item_meta(api_path, meta);
|
auto res = provider_.get_item_meta(api_path, meta);
|
||||||
|
@ -21,43 +21,66 @@
|
|||||||
*/
|
*/
|
||||||
#include "file_manager/direct_open_file.hpp"
|
#include "file_manager/direct_open_file.hpp"
|
||||||
|
|
||||||
|
#include "events/event_system.hpp"
|
||||||
|
#include "file_manager/events.hpp"
|
||||||
#include "file_manager/open_file_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
#include "utils/common.hpp"
|
||||||
|
#include "utils/time.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
direct_open_file::direct_open_file(std::uint64_t chunk_size,
|
direct_open_file::direct_open_file(std::uint64_t chunk_size,
|
||||||
std::uint8_t chunk_timeout,
|
std::uint8_t chunk_timeout,
|
||||||
filesystem_item fsi, i_provider &provider)
|
filesystem_item fsi, i_provider &provider)
|
||||||
: ring_buffer_base(chunk_size, chunk_timeout, fsi, provider,
|
: open_file_base(chunk_size, chunk_timeout, fsi, provider, true),
|
||||||
min_ring_size, true) {}
|
total_chunks_(static_cast<std::size_t>(
|
||||||
|
utils::divide_with_ceiling(fsi.size, chunk_size))) {
|
||||||
direct_open_file::~direct_open_file() {
|
event_system::instance().raise<download_begin>(fsi_.api_path, "");
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto direct_open_file::on_check_start() -> bool {
|
direct_open_file::~direct_open_file() { close(); }
|
||||||
return (get_file_size() == 0U || has_reader_thread());
|
|
||||||
|
auto direct_open_file::close() -> bool {
|
||||||
|
stop_requested_ = true;
|
||||||
|
last_progress_ = 0U;
|
||||||
|
auto ret = open_file_base::close();
|
||||||
|
|
||||||
|
event_system::instance().raise<download_end>(fsi_.api_path, "",
|
||||||
|
api_error::download_stopped);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto direct_open_file::on_read_chunk(std::size_t chunk, std::size_t read_size,
|
auto direct_open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
||||||
std::uint64_t read_offset,
|
data_buffer &data) -> api_error {
|
||||||
data_buffer &data,
|
if (fsi_.directory) {
|
||||||
std::size_t &bytes_read) -> api_error {
|
return api_error::invalid_operation;
|
||||||
auto &buffer = ring_data_.at(chunk % get_ring_size());
|
}
|
||||||
auto begin =
|
|
||||||
std::next(buffer.begin(), static_cast<std::int64_t>(read_offset));
|
|
||||||
auto end = std::next(begin, static_cast<std::int64_t>(read_size));
|
|
||||||
data.insert(data.end(), begin, end);
|
|
||||||
bytes_read = read_size;
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto direct_open_file::use_buffer(std::size_t chunk,
|
reset_timeout();
|
||||||
std::function<api_error(data_buffer &)> func)
|
|
||||||
-> api_error {
|
read_size = utils::calculate_read_size(fsi_.size, read_size, read_offset);
|
||||||
return func(ring_data_.at(chunk % get_ring_size()));
|
if (read_size == 0U) {
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = provider_.read_file_bytes(fsi_.api_path, read_size, read_offset,
|
||||||
|
data, stop_requested_);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_timeout();
|
||||||
|
if ((utils::time::get_time_now() - last_progress_.load()) >
|
||||||
|
(2U * utils::time::NANOS_PER_SECOND)) {
|
||||||
|
last_progress_ = utils::time::get_time_now();
|
||||||
|
auto progress = (static_cast<double>(read_offset + read_size) /
|
||||||
|
static_cast<double>(fsi_.size)) *
|
||||||
|
100.0;
|
||||||
|
event_system::instance().raise<download_progress>(fsi_.api_path, "",
|
||||||
|
progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
|
#include "utils/time.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
file_manager::file_manager(app_config &config, i_provider &provider)
|
file_manager::file_manager(app_config &config, i_provider &provider)
|
||||||
@ -157,10 +158,6 @@ auto file_manager::evict_file(const std::string &api_path) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsi.source_path.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string pinned;
|
std::string pinned;
|
||||||
res = provider_.get_item_meta(api_path, META_PINNED, pinned);
|
res = provider_.get_item_meta(api_path, META_PINNED, pinned);
|
||||||
if (res != api_error::success && res != api_error::item_not_found) {
|
if (res != api_error::success && res != api_error::item_not_found) {
|
||||||
@ -173,22 +170,35 @@ auto file_manager::evict_file(const std::string &api_path) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string source_path{};
|
||||||
|
res = provider_.get_item_meta(api_path, META_SOURCE, source_path);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(std::string{function_name}, api_path,
|
||||||
|
res, "failed to get source path");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (source_path.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<i_closeable_open_file> closeable_file;
|
std::shared_ptr<i_closeable_open_file> closeable_file;
|
||||||
if (open_file_lookup_.contains(api_path)) {
|
if (open_file_lookup_.contains(api_path)) {
|
||||||
closeable_file = open_file_lookup_.at(api_path);
|
closeable_file = open_file_lookup_.at(api_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
open_file_lookup_.erase(api_path);
|
open_file_lookup_.erase(api_path);
|
||||||
open_lock.unlock();
|
|
||||||
|
|
||||||
auto allocated = closeable_file ? closeable_file->get_allocated() : true;
|
auto allocated = closeable_file ? closeable_file->get_allocated() : true;
|
||||||
|
|
||||||
|
auto removed = remove_source_and_shrink_cache(api_path, source_path, fsi.size,
|
||||||
|
allocated);
|
||||||
|
open_lock.unlock();
|
||||||
|
|
||||||
closeable_file.reset();
|
closeable_file.reset();
|
||||||
|
|
||||||
auto removed = remove_source_and_shrink_cache(api_path, fsi.source_path,
|
|
||||||
fsi.size, allocated);
|
|
||||||
if (removed) {
|
if (removed) {
|
||||||
event_system::instance().raise<filesystem_item_evicted>(api_path,
|
event_system::instance().raise<filesystem_item_evicted>(api_path,
|
||||||
fsi.source_path);
|
source_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return removed;
|
return removed;
|
||||||
@ -219,7 +229,7 @@ auto file_manager::get_open_file_by_handle(std::uint64_t handle) const
|
|||||||
-> std::shared_ptr<i_closeable_open_file> {
|
-> std::shared_ptr<i_closeable_open_file> {
|
||||||
auto file_iter =
|
auto file_iter =
|
||||||
std::find_if(open_file_lookup_.begin(), open_file_lookup_.end(),
|
std::find_if(open_file_lookup_.begin(), open_file_lookup_.end(),
|
||||||
[&handle](auto &&item) -> bool {
|
[&handle](const auto &item) -> bool {
|
||||||
return item.second->has_handle(handle);
|
return item.second->has_handle(handle);
|
||||||
});
|
});
|
||||||
return (file_iter == open_file_lookup_.end()) ? nullptr : file_iter->second;
|
return (file_iter == open_file_lookup_.end()) ? nullptr : file_iter->second;
|
||||||
@ -367,10 +377,7 @@ auto file_manager::is_processing(const std::string &api_path) const -> bool {
|
|||||||
auto closeable_file = file_iter->second;
|
auto closeable_file = file_iter->second;
|
||||||
open_lock.unlock();
|
open_lock.unlock();
|
||||||
|
|
||||||
return closeable_file->is_write_supported()
|
return closeable_file->is_modified() || not closeable_file->is_complete();
|
||||||
? closeable_file->is_modified() ||
|
|
||||||
not closeable_file->is_complete()
|
|
||||||
: false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file_manager::open(const std::string &api_path, bool directory,
|
auto file_manager::open(const std::string &api_path, bool directory,
|
||||||
@ -380,10 +387,11 @@ auto file_manager::open(const std::string &api_path, bool directory,
|
|||||||
return open(api_path, directory, ofd, handle, file, nullptr);
|
return open(api_path, directory, ofd, handle, file, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file_manager::open(
|
auto file_manager::open(const std::string &api_path, bool directory,
|
||||||
const std::string &api_path, bool directory, const open_file_data &ofd,
|
const open_file_data &ofd, std::uint64_t &handle,
|
||||||
std::uint64_t &handle, std::shared_ptr<i_open_file> &file,
|
std::shared_ptr<i_open_file> &file,
|
||||||
std::shared_ptr<i_closeable_open_file> closeable_file) -> api_error {
|
std::shared_ptr<i_closeable_open_file> closeable_file)
|
||||||
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto create_and_add_handle =
|
const auto create_and_add_handle =
|
||||||
@ -435,19 +443,19 @@ auto file_manager::open(
|
|||||||
auto ring_size{ring_buffer_file_size / chunk_size};
|
auto ring_size{ring_buffer_file_size / chunk_size};
|
||||||
|
|
||||||
const auto get_download_type = [&](download_type type) -> download_type {
|
const auto get_download_type = [&](download_type type) -> download_type {
|
||||||
if (directory || fsi.size == 0U || is_processing(api_path)) {
|
if (directory || fsi.size == 0U) {
|
||||||
return download_type::default_;
|
return download_type::fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == download_type::direct) {
|
if (type == download_type::direct) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == download_type::default_) {
|
if (type == download_type::fallback) {
|
||||||
auto free_space =
|
auto free_space =
|
||||||
utils::file::get_free_drive_space(config_.get_cache_directory());
|
utils::file::get_free_drive_space(config_.get_cache_directory());
|
||||||
if (fsi.size < free_space) {
|
if (fsi.size < free_space) {
|
||||||
return download_type::default_;
|
return download_type::fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,11 +480,7 @@ auto file_manager::open(
|
|||||||
return download_type::direct;
|
return download_type::direct;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto preferred_type = config_.get_preferred_download_type();
|
auto type = get_download_type(config_.get_preferred_download_type());
|
||||||
auto type = get_download_type(directory ? download_type::default_
|
|
||||||
: preferred_type == download_type::default_
|
|
||||||
? download_type::ring_buffer
|
|
||||||
: preferred_type);
|
|
||||||
if (not directory) {
|
if (not directory) {
|
||||||
event_system::instance().raise<download_type_selected>(
|
event_system::instance().raise<download_type_selected>(
|
||||||
fsi.api_path, fsi.source_path, type);
|
fsi.api_path, fsi.source_path, type);
|
||||||
@ -747,8 +751,8 @@ auto file_manager::rename_directory(const std::string &from_api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto file_manager::rename_file(const std::string &from_api_path,
|
auto file_manager::rename_file(const std::string &from_api_path,
|
||||||
const std::string &to_api_path,
|
const std::string &to_api_path, bool overwrite)
|
||||||
bool overwrite) -> api_error {
|
-> api_error {
|
||||||
if (not provider_.is_rename_supported()) {
|
if (not provider_.is_rename_supported()) {
|
||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
@ -907,6 +911,7 @@ void file_manager::stop() {
|
|||||||
|
|
||||||
stop_requested_ = true;
|
stop_requested_ = true;
|
||||||
|
|
||||||
|
polling::instance().remove_callback("db_cleanup");
|
||||||
polling::instance().remove_callback("timed_out_close");
|
polling::instance().remove_callback("timed_out_close");
|
||||||
|
|
||||||
unique_mutex_lock upload_lock(upload_mtx_);
|
unique_mutex_lock upload_lock(upload_mtx_);
|
||||||
|
@ -28,10 +28,13 @@
|
|||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
#include "types/startup_exception.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
||||||
@ -60,12 +63,11 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|||||||
i_provider &provider,
|
i_provider &provider,
|
||||||
std::optional<boost::dynamic_bitset<>> read_state,
|
std::optional<boost::dynamic_bitset<>> read_state,
|
||||||
i_upload_manager &mgr)
|
i_upload_manager &mgr)
|
||||||
: open_file_base(chunk_size, chunk_timeout, fsi, open_data, provider,
|
: open_file_base(chunk_size, chunk_timeout, fsi, open_data, provider),
|
||||||
false),
|
|
||||||
mgr_(mgr) {
|
mgr_(mgr) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (fsi.directory) {
|
if (fsi_.directory) {
|
||||||
if (read_state.has_value()) {
|
if (read_state.has_value()) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, fsi.api_path, fsi.source_path,
|
function_name, fsi.api_path, fsi.source_path,
|
||||||
@ -76,7 +78,7 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nf_ = utils::file::file::open_or_create_file(fsi.source_path,
|
nf_ = utils::file::file::open_or_create_file(fsi.source_path,
|
||||||
get_provider().is_read_only());
|
provider_.is_read_only());
|
||||||
set_api_error(*nf_ ? api_error::success : api_error::os_error);
|
set_api_error(*nf_ ? api_error::success : api_error::os_error);
|
||||||
if (get_api_error() != api_error::success) {
|
if (get_api_error() != api_error::success) {
|
||||||
return;
|
return;
|
||||||
@ -89,12 +91,12 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsi.size == 0U) {
|
if (fsi_.size == 0U) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_state_.resize(static_cast<std::size_t>(
|
read_state_.resize(static_cast<std::size_t>(
|
||||||
utils::divide_with_ceiling(fsi.size, chunk_size)),
|
utils::divide_with_ceiling(fsi_.size, chunk_size)),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
auto file_size = nf_->size();
|
auto file_size = nf_->size();
|
||||||
@ -106,7 +108,7 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_provider().is_read_only() || file_size.value() == fsi.size) {
|
if (provider_.is_read_only() || file_size.value() == fsi.size) {
|
||||||
read_state_.set(0U, read_state_.size(), true);
|
read_state_.set(0U, read_state_.size(), true);
|
||||||
allocated = true;
|
allocated = true;
|
||||||
}
|
}
|
||||||
@ -118,16 +120,16 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|||||||
|
|
||||||
open_file::~open_file() { close(); }
|
open_file::~open_file() { close(); }
|
||||||
|
|
||||||
auto open_file::adjust_cache_size(std::uint64_t file_size,
|
auto open_file::adjust_cache_size(std::uint64_t file_size, bool shrink)
|
||||||
bool shrink) -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (file_size == get_file_size()) {
|
if (file_size == fsi_.size) {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_size > get_file_size()) {
|
if (file_size > fsi_.size) {
|
||||||
auto size = file_size - get_file_size();
|
auto size = file_size - fsi_.size;
|
||||||
auto res = shrink ? cache_size_mgr::instance().shrink(size)
|
auto res = shrink ? cache_size_mgr::instance().shrink(size)
|
||||||
: cache_size_mgr::instance().expand(size);
|
: cache_size_mgr::instance().expand(size);
|
||||||
if (res == api_error::success) {
|
if (res == api_error::success) {
|
||||||
@ -135,13 +137,13 @@ auto open_file::adjust_cache_size(std::uint64_t file_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, get_api_path(), get_source_path(), res,
|
function_name, fsi_.api_path, fsi_.source_path, res,
|
||||||
fmt::format("failed to {} cache|size|{}",
|
fmt::format("failed to {} cache|size|{}",
|
||||||
(shrink ? "shrink" : "expand"), size));
|
(shrink ? "shrink" : "expand"), size));
|
||||||
return set_api_error(res);
|
return set_api_error(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size = get_file_size() - file_size;
|
auto size = fsi_.size - file_size;
|
||||||
auto res = shrink ? cache_size_mgr::instance().expand(size)
|
auto res = shrink ? cache_size_mgr::instance().expand(size)
|
||||||
: cache_size_mgr::instance().shrink(size);
|
: cache_size_mgr::instance().shrink(size);
|
||||||
if (res == api_error::success) {
|
if (res == api_error::success) {
|
||||||
@ -149,16 +151,16 @@ auto open_file::adjust_cache_size(std::uint64_t file_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, get_api_path(), get_source_path(), res,
|
function_name, fsi_.api_path, fsi_.source_path, res,
|
||||||
fmt::format("failed to {} cache|size|{}", (shrink ? "expand" : "shrink"),
|
fmt::format("failed to {} cache|size|{}", (shrink ? "expand" : "shrink"),
|
||||||
size));
|
size));
|
||||||
return set_api_error(res);
|
return set_api_error(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::check_start() -> api_error {
|
auto open_file::check_allocation() -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
unique_recur_mutex_lock file_lock(get_mutex());
|
unique_recur_mutex_lock file_lock(file_mtx_);
|
||||||
if (allocated) {
|
if (allocated) {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
@ -166,12 +168,12 @@ auto open_file::check_start() -> api_error {
|
|||||||
auto file_size = nf_->size();
|
auto file_size = nf_->size();
|
||||||
if (not file_size.has_value()) {
|
if (not file_size.has_value()) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, get_api_path(), get_source_path(),
|
function_name, fsi_.api_path, fsi_.source_path,
|
||||||
utils::get_last_error_code(), "failed to get file size");
|
utils::get_last_error_code(), "failed to get file size");
|
||||||
return set_api_error(api_error::os_error);
|
return set_api_error(api_error::os_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_size.value() == get_file_size()) {
|
if (file_size.value() == fsi_.size) {
|
||||||
allocated = true;
|
allocated = true;
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
@ -183,11 +185,11 @@ auto open_file::check_start() -> api_error {
|
|||||||
}
|
}
|
||||||
file_lock.lock();
|
file_lock.lock();
|
||||||
|
|
||||||
if (not nf_->truncate(get_file_size())) {
|
if (not nf_->truncate(fsi_.size)) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, get_api_path(), get_source_path(),
|
function_name, fsi_.api_path, fsi_.source_path,
|
||||||
utils::get_last_error_code(),
|
utils::get_last_error_code(),
|
||||||
fmt::format("failed to truncate file|size|{}", get_file_size()));
|
fmt::format("failed to truncate file|size|{}", fsi_.size));
|
||||||
return set_api_error(res);
|
return set_api_error(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,13 +200,15 @@ auto open_file::check_start() -> api_error {
|
|||||||
auto open_file::close() -> bool {
|
auto open_file::close() -> bool {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (is_directory() || stop_requested_) {
|
if (fsi_.directory || stop_requested_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_requested_ = true;
|
stop_requested_ = true;
|
||||||
|
|
||||||
notify_io();
|
unique_mutex_lock reader_lock(io_thread_mtx_);
|
||||||
|
io_thread_notify_.notify_all();
|
||||||
|
reader_lock.unlock();
|
||||||
|
|
||||||
if (reader_thread_) {
|
if (reader_thread_) {
|
||||||
reader_thread_->join();
|
reader_thread_->join();
|
||||||
@ -219,10 +223,9 @@ auto open_file::close() -> bool {
|
|||||||
auto err = get_api_error();
|
auto err = get_api_error();
|
||||||
if (err == api_error::success || err == api_error::download_incomplete ||
|
if (err == api_error::success || err == api_error::download_incomplete ||
|
||||||
err == api_error::download_stopped) {
|
err == api_error::download_stopped) {
|
||||||
if (is_modified() && not read_state.all()) {
|
if (modified_ && not read_state.all()) {
|
||||||
set_api_error(api_error::download_incomplete);
|
set_api_error(api_error::download_incomplete);
|
||||||
} else if (not is_modified() && (get_file_size() > 0U) &&
|
} else if (not modified_ && (fsi_.size > 0U) && not read_state.all()) {
|
||||||
not read_state.all()) {
|
|
||||||
set_api_error(api_error::download_stopped);
|
set_api_error(api_error::download_stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +234,7 @@ auto open_file::close() -> bool {
|
|||||||
|
|
||||||
nf_->close();
|
nf_->close();
|
||||||
|
|
||||||
if (is_modified()) {
|
if (modified_) {
|
||||||
if (err == api_error::success) {
|
if (err == api_error::success) {
|
||||||
mgr_.queue_upload(*this);
|
mgr_.queue_upload(*this);
|
||||||
return true;
|
return true;
|
||||||
@ -244,24 +247,24 @@ auto open_file::close() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (err != api_error::success || read_state.all()) {
|
if (err != api_error::success || read_state.all()) {
|
||||||
mgr_.remove_resume(get_api_path(), get_source_path());
|
mgr_.remove_resume(fsi_.api_path, get_source_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == api_error::success) {
|
if (err == api_error::success) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_manager::remove_source_and_shrink_cache(
|
file_manager::remove_source_and_shrink_cache(fsi_.api_path, fsi_.source_path,
|
||||||
get_api_path(), get_source_path(), get_file_size(), allocated);
|
fsi_.size, allocated);
|
||||||
|
|
||||||
auto parent = utils::path::get_parent_path(get_source_path());
|
auto parent = utils::path::get_parent_path(fsi_.source_path);
|
||||||
set_source_path(utils::path::combine(parent, {utils::create_uuid_string()}));
|
fsi_.source_path =
|
||||||
|
utils::path::combine(parent, {utils::create_uuid_string()});
|
||||||
auto res = get_provider().set_item_meta(get_api_path(), META_SOURCE,
|
auto res =
|
||||||
get_source_path());
|
provider_.set_item_meta(fsi_.api_path, META_SOURCE, fsi_.source_path);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(),
|
utils::error::raise_api_path_error(function_name, fsi_.api_path,
|
||||||
get_source_path(), res,
|
fsi_.source_path, res,
|
||||||
"failed to set new source path");
|
"failed to set new source path");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,27 +281,30 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
|||||||
auto read_state = get_read_state();
|
auto read_state = get_read_state();
|
||||||
if ((get_api_error() == api_error::success) && (chunk < read_state.size()) &&
|
if ((get_api_error() == api_error::success) && (chunk < read_state.size()) &&
|
||||||
not read_state[chunk]) {
|
not read_state[chunk]) {
|
||||||
if (get_active_downloads().find(chunk) != get_active_downloads().end()) {
|
if (active_downloads_.find(chunk) != active_downloads_.end()) {
|
||||||
if (skip_active) {
|
if (skip_active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto active_download = get_active_downloads().at(chunk);
|
auto active_download = active_downloads_.at(chunk);
|
||||||
rw_lock.unlock();
|
rw_lock.unlock();
|
||||||
|
|
||||||
active_download->wait();
|
active_download->wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data_offset = chunk * get_chunk_size();
|
auto data_offset = chunk * chunk_size_;
|
||||||
auto data_size = (chunk == read_state.size() - 1U) ? get_last_chunk_size()
|
auto data_size =
|
||||||
: get_chunk_size();
|
(chunk == read_state.size() - 1U) ? last_chunk_size_ : chunk_size_;
|
||||||
if (get_active_downloads().empty() && (read_state.count() == 0U)) {
|
if (active_downloads_.empty() && (read_state.count() == 0U)) {
|
||||||
event_system::instance().raise<download_begin>(get_api_path(),
|
event_system::instance().raise<download_begin>(fsi_.api_path,
|
||||||
get_source_path());
|
fsi_.source_path);
|
||||||
}
|
}
|
||||||
|
event_system::instance().raise<download_chunk_begin>(
|
||||||
|
fsi_.api_path, fsi_.source_path, chunk, read_state.size(),
|
||||||
|
read_state.count());
|
||||||
|
|
||||||
get_active_downloads()[chunk] = std::make_shared<download>();
|
active_downloads_[chunk] = std::make_shared<download>();
|
||||||
rw_lock.unlock();
|
rw_lock.unlock();
|
||||||
|
|
||||||
if (should_reset) {
|
if (should_reset) {
|
||||||
@ -311,23 +317,26 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
|||||||
auto state = get_read_state();
|
auto state = get_read_state();
|
||||||
|
|
||||||
unique_recur_mutex_lock lock(rw_mtx_);
|
unique_recur_mutex_lock lock(rw_mtx_);
|
||||||
auto active_download = get_active_downloads().at(chunk);
|
auto active_download = active_downloads_.at(chunk);
|
||||||
get_active_downloads().erase(chunk);
|
active_downloads_.erase(chunk);
|
||||||
|
event_system::instance().raise<download_chunk_end>(
|
||||||
|
fsi_.api_path, fsi_.source_path, chunk, state.size(), state.count(),
|
||||||
|
get_api_error());
|
||||||
if (get_api_error() == api_error::success) {
|
if (get_api_error() == api_error::success) {
|
||||||
auto progress = (static_cast<double>(state.count()) /
|
auto progress = (static_cast<double>(state.count()) /
|
||||||
static_cast<double>(state.size())) *
|
static_cast<double>(state.size())) *
|
||||||
100.0;
|
100.0;
|
||||||
event_system::instance().raise<download_progress>(
|
event_system::instance().raise<download_progress>(
|
||||||
get_api_path(), get_source_path(), progress);
|
fsi_.api_path, fsi_.source_path, progress);
|
||||||
if (state.all() && not notified_) {
|
if (state.all() && not notified_) {
|
||||||
notified_ = true;
|
notified_ = true;
|
||||||
event_system::instance().raise<download_end>(
|
event_system::instance().raise<download_end>(
|
||||||
get_api_path(), get_source_path(), get_api_error());
|
fsi_.api_path, fsi_.source_path, get_api_error());
|
||||||
}
|
}
|
||||||
} else if (not notified_) {
|
} else if (not notified_) {
|
||||||
notified_ = true;
|
notified_ = true;
|
||||||
event_system::instance().raise<download_end>(
|
event_system::instance().raise<download_end>(
|
||||||
get_api_path(), get_source_path(), get_api_error());
|
fsi_.api_path, fsi_.source_path, get_api_error());
|
||||||
}
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
@ -339,7 +348,7 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
|||||||
};
|
};
|
||||||
|
|
||||||
data_buffer buffer;
|
data_buffer buffer;
|
||||||
auto res = get_provider().read_file_bytes(
|
auto res = provider_.read_file_bytes(
|
||||||
get_api_path(), data_size, data_offset, buffer, stop_requested_);
|
get_api_path(), data_size, data_offset, buffer, stop_requested_);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
set_api_error(res);
|
set_api_error(res);
|
||||||
@ -385,12 +394,12 @@ void open_file::download_range(std::size_t begin_chunk, std::size_t end_chunk,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::get_allocated() const -> bool {
|
auto open_file::get_allocated() const -> bool {
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
return allocated;
|
return allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::get_read_state() const -> boost::dynamic_bitset<> {
|
auto open_file::get_read_state() const -> boost::dynamic_bitset<> {
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
return read_state_;
|
return read_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,13 +409,17 @@ auto open_file::get_read_state(std::size_t chunk) const -> bool {
|
|||||||
|
|
||||||
auto open_file::is_complete() const -> bool { return get_read_state().all(); }
|
auto open_file::is_complete() const -> bool { return get_read_state().all(); }
|
||||||
|
|
||||||
|
auto open_file::is_download_complete() const -> bool {
|
||||||
|
return get_read_state().all();
|
||||||
|
}
|
||||||
|
|
||||||
auto open_file::native_operation(
|
auto open_file::native_operation(
|
||||||
i_open_file::native_operation_callback callback) -> api_error {
|
i_open_file::native_operation_callback callback) -> api_error {
|
||||||
if (stop_requested_) {
|
if (stop_requested_) {
|
||||||
return set_api_error(api_error::download_stopped);
|
return set_api_error(api_error::download_stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = check_start();
|
auto res = check_allocation();
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -420,7 +433,7 @@ auto open_file::native_operation(
|
|||||||
i_open_file::native_operation_callback callback) -> api_error {
|
i_open_file::native_operation_callback callback) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (is_directory()) {
|
if (fsi_.directory) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return set_api_error(api_error::invalid_operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,7 +441,7 @@ auto open_file::native_operation(
|
|||||||
return set_api_error(api_error::download_stopped);
|
return set_api_error(api_error::download_stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = check_start();
|
auto res = check_allocation();
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -442,14 +455,14 @@ auto open_file::native_operation(
|
|||||||
auto last_chunk = is_empty_file
|
auto last_chunk = is_empty_file
|
||||||
? std::size_t(0U)
|
? std::size_t(0U)
|
||||||
: static_cast<std::size_t>(utils::divide_with_ceiling(
|
: static_cast<std::size_t>(utils::divide_with_ceiling(
|
||||||
new_file_size, get_chunk_size())) -
|
new_file_size, chunk_size_)) -
|
||||||
1U;
|
1U;
|
||||||
|
|
||||||
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
||||||
auto read_state = get_read_state();
|
auto read_state = get_read_state();
|
||||||
if (not is_empty_file && (last_chunk < read_state.size())) {
|
if (not is_empty_file && (last_chunk < read_state.size())) {
|
||||||
rw_lock.unlock();
|
rw_lock.unlock();
|
||||||
update_reader(0U);
|
update_background_reader(0U);
|
||||||
|
|
||||||
download_chunk(last_chunk, false, true);
|
download_chunk(last_chunk, false, true);
|
||||||
if (get_api_error() != api_error::success) {
|
if (get_api_error() != api_error::success) {
|
||||||
@ -499,11 +512,10 @@ auto open_file::native_operation(
|
|||||||
}
|
}
|
||||||
set_read_state(read_state);
|
set_read_state(read_state);
|
||||||
|
|
||||||
set_last_chunk_size(static_cast<std::size_t>(
|
last_chunk_size_ = static_cast<std::size_t>(
|
||||||
new_file_size <= get_chunk_size() ? new_file_size
|
new_file_size <= chunk_size_ ? new_file_size
|
||||||
: (new_file_size % get_chunk_size()) == 0U
|
: (new_file_size % chunk_size_) == 0U ? chunk_size_
|
||||||
? get_chunk_size()
|
: new_file_size % chunk_size_);
|
||||||
: new_file_size % get_chunk_size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (original_file_size == new_file_size) {
|
if (original_file_size == new_file_size) {
|
||||||
@ -511,15 +523,15 @@ auto open_file::native_operation(
|
|||||||
}
|
}
|
||||||
set_modified();
|
set_modified();
|
||||||
|
|
||||||
set_file_size(new_file_size);
|
fsi_.size = new_file_size;
|
||||||
auto now = std::to_string(utils::time::get_time_now());
|
auto now = std::to_string(utils::time::get_time_now());
|
||||||
res = get_provider().set_item_meta(
|
res = provider_.set_item_meta(fsi_.api_path,
|
||||||
get_api_path(), {
|
{
|
||||||
{META_CHANGED, now},
|
{META_CHANGED, now},
|
||||||
{META_MODIFIED, now},
|
{META_MODIFIED, now},
|
||||||
{META_SIZE, std::to_string(new_file_size)},
|
{META_SIZE, std::to_string(new_file_size)},
|
||||||
{META_WRITTEN, now},
|
{META_WRITTEN, now},
|
||||||
});
|
});
|
||||||
if (res == api_error::success) {
|
if (res == api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -531,7 +543,7 @@ auto open_file::native_operation(
|
|||||||
|
|
||||||
auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
||||||
data_buffer &data) -> api_error {
|
data_buffer &data) -> api_error {
|
||||||
if (is_directory()) {
|
if (fsi_.directory) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return set_api_error(api_error::invalid_operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,7 +557,7 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = check_start();
|
auto res = check_allocation();
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -553,9 +565,9 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
const auto read_from_source = [this, &data, &read_offset,
|
const auto read_from_source = [this, &data, &read_offset,
|
||||||
&read_size]() -> api_error {
|
&read_size]() -> api_error {
|
||||||
return do_io([this, &data, &read_offset, &read_size]() -> api_error {
|
return do_io([this, &data, &read_offset, &read_size]() -> api_error {
|
||||||
if (get_provider().is_read_only()) {
|
if (provider_.is_read_only()) {
|
||||||
return get_provider().read_file_bytes(
|
return provider_.read_file_bytes(fsi_.api_path, read_size, read_offset,
|
||||||
get_api_path(), read_size, read_offset, data, stop_requested_);
|
data, stop_requested_);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.resize(read_size);
|
data.resize(read_size);
|
||||||
@ -571,11 +583,11 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
return read_from_source();
|
return read_from_source();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto begin_chunk = static_cast<std::size_t>(read_offset / get_chunk_size());
|
auto begin_chunk = static_cast<std::size_t>(read_offset / chunk_size_);
|
||||||
auto end_chunk =
|
auto end_chunk =
|
||||||
static_cast<std::size_t>((read_size + read_offset) / get_chunk_size());
|
static_cast<std::size_t>((read_size + read_offset) / chunk_size_);
|
||||||
|
|
||||||
update_reader(begin_chunk);
|
update_background_reader(begin_chunk);
|
||||||
|
|
||||||
download_range(begin_chunk, end_chunk, true);
|
download_range(begin_chunk, end_chunk, true);
|
||||||
if (get_api_error() != api_error::success) {
|
if (get_api_error() != api_error::success) {
|
||||||
@ -591,14 +603,14 @@ void open_file::remove(std::uint64_t handle) {
|
|||||||
open_file_base::remove(handle);
|
open_file_base::remove(handle);
|
||||||
|
|
||||||
recur_mutex_lock rw_lock(rw_mtx_);
|
recur_mutex_lock rw_lock(rw_mtx_);
|
||||||
if (is_modified() && get_read_state().all() &&
|
if (modified_ && get_read_state().all() &&
|
||||||
(get_api_error() == api_error::success)) {
|
(get_api_error() == api_error::success)) {
|
||||||
mgr_.queue_upload(*this);
|
mgr_.queue_upload(*this);
|
||||||
open_file_base::set_modified(false);
|
modified_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_removed() && (get_open_file_count() == 0U)) {
|
if (removed_ && (get_open_file_count() == 0U)) {
|
||||||
open_file_base::set_removed(false);
|
removed_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,8 +618,8 @@ void open_file::remove_all() {
|
|||||||
open_file_base::remove_all();
|
open_file_base::remove_all();
|
||||||
|
|
||||||
recur_mutex_lock rw_lock(rw_mtx_);
|
recur_mutex_lock rw_lock(rw_mtx_);
|
||||||
open_file_base::set_modified(false);
|
modified_ = false;
|
||||||
open_file_base::set_removed(true);
|
removed_ = true;
|
||||||
|
|
||||||
mgr_.remove_upload(get_api_path());
|
mgr_.remove_upload(get_api_path());
|
||||||
|
|
||||||
@ -615,11 +627,11 @@ void open_file::remove_all() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
||||||
if (is_directory()) {
|
if (fsi_.directory) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return set_api_error(api_error::invalid_operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_file_size == get_file_size()) {
|
if (new_file_size == fsi_.size) {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,56 +643,58 @@ auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void open_file::set_modified() {
|
void open_file::set_modified() {
|
||||||
if (not is_modified()) {
|
if (not modified_) {
|
||||||
open_file_base::set_modified(true);
|
modified_ = true;
|
||||||
mgr_.store_resume(*this);
|
mgr_.store_resume(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not is_removed()) {
|
if (not removed_) {
|
||||||
open_file_base::set_removed(true);
|
removed_ = true;
|
||||||
mgr_.remove_upload(get_api_path());
|
mgr_.remove_upload(get_api_path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file::set_read_state(std::size_t chunk) {
|
void open_file::set_read_state(std::size_t chunk) {
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
read_state_.set(chunk);
|
read_state_.set(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file::set_read_state(boost::dynamic_bitset<> read_state) {
|
void open_file::set_read_state(boost::dynamic_bitset<> read_state) {
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
read_state_ = std::move(read_state);
|
read_state_ = std::move(read_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file::update_reader(std::size_t chunk) {
|
void open_file::update_background_reader(std::size_t read_chunk) {
|
||||||
recur_mutex_lock rw_lock(rw_mtx_);
|
recur_mutex_lock rw_lock(rw_mtx_);
|
||||||
read_chunk_ = chunk;
|
read_chunk_ = read_chunk;
|
||||||
|
|
||||||
if (reader_thread_ || stop_requested_) {
|
if (reader_thread_ || stop_requested_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reader_thread_ = std::make_unique<std::thread>([this]() {
|
reader_thread_ = std::make_unique<std::thread>([this]() {
|
||||||
unique_recur_mutex_lock lock(rw_mtx_);
|
std::size_t next_chunk{};
|
||||||
auto next_chunk{read_chunk_};
|
|
||||||
auto read_chunk{read_chunk_};
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
while (not stop_requested_) {
|
while (not stop_requested_) {
|
||||||
lock.lock();
|
unique_recur_mutex_lock lock(rw_mtx_);
|
||||||
|
|
||||||
auto read_state = get_read_state();
|
auto read_state = get_read_state();
|
||||||
if ((get_file_size() == 0U) || read_state.all()) {
|
if ((fsi_.size == 0U) || read_state.all()) {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
wait_for_io(stop_requested_);
|
|
||||||
|
unique_mutex_lock io_lock(io_thread_mtx_);
|
||||||
|
if (not stop_requested_ && io_thread_queue_.empty()) {
|
||||||
|
io_thread_notify_.wait(io_lock);
|
||||||
|
}
|
||||||
|
io_thread_notify_.notify_all();
|
||||||
|
io_lock.unlock();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_chunk != read_chunk_) {
|
do {
|
||||||
next_chunk = read_chunk = read_chunk_;
|
next_chunk = read_chunk_ =
|
||||||
}
|
((read_chunk_ + 1U) >= read_state.size()) ? 0U : read_chunk_ + 1U;
|
||||||
|
} while ((next_chunk != 0U) &&
|
||||||
|
(active_downloads_.find(next_chunk) != active_downloads_.end()));
|
||||||
|
|
||||||
next_chunk = next_chunk + 1U >= read_state.size() ? 0U : next_chunk + 1U;
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
download_chunk(next_chunk, true, false);
|
download_chunk(next_chunk, true, false);
|
||||||
@ -694,7 +708,7 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
|||||||
|
|
||||||
bytes_written = 0U;
|
bytes_written = 0U;
|
||||||
|
|
||||||
if (is_directory() || get_provider().is_read_only()) {
|
if (fsi_.directory || provider_.is_read_only()) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return set_api_error(api_error::invalid_operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,16 +720,16 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
|||||||
return set_api_error(api_error::download_stopped);
|
return set_api_error(api_error::download_stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = check_start();
|
auto res = check_allocation();
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto begin_chunk = static_cast<std::size_t>(write_offset / get_chunk_size());
|
auto begin_chunk = static_cast<std::size_t>(write_offset / chunk_size_);
|
||||||
auto end_chunk =
|
auto end_chunk =
|
||||||
static_cast<std::size_t>((write_offset + data.size()) / get_chunk_size());
|
static_cast<std::size_t>((write_offset + data.size()) / chunk_size_);
|
||||||
|
|
||||||
update_reader(begin_chunk);
|
update_background_reader(begin_chunk);
|
||||||
|
|
||||||
download_range(begin_chunk, std::min(get_read_state().size() - 1U, end_chunk),
|
download_range(begin_chunk, std::min(get_read_state().size() - 1U, end_chunk),
|
||||||
true);
|
true);
|
||||||
@ -724,7 +738,7 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
||||||
if ((write_offset + data.size()) > get_file_size()) {
|
if ((write_offset + data.size()) > fsi_.size) {
|
||||||
res = resize(write_offset + data.size());
|
res = resize(write_offset + data.size());
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
@ -744,11 +758,11 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto now = std::to_string(utils::time::get_time_now());
|
auto now = std::to_string(utils::time::get_time_now());
|
||||||
res = get_provider().set_item_meta(get_api_path(), {
|
res = provider_.set_item_meta(fsi_.api_path, {
|
||||||
{META_CHANGED, now},
|
{META_CHANGED, now},
|
||||||
{META_MODIFIED, now},
|
{META_MODIFIED, now},
|
||||||
{META_WRITTEN, now},
|
{META_WRITTEN, now},
|
||||||
});
|
});
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(), res,
|
utils::error::raise_api_path_error(function_name, get_api_path(), res,
|
||||||
"failed to set file meta");
|
"failed to set file meta");
|
||||||
|
@ -119,7 +119,7 @@ auto open_file_base::can_close() const -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_complete()) {
|
if (is_download_complete()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,24 +133,6 @@ auto open_file_base::can_close() const -> bool {
|
|||||||
return (duration.count() >= chunk_timeout_);
|
return (duration.count() >= chunk_timeout_);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file_base::close() -> bool {
|
|
||||||
unique_mutex_lock io_lock(io_thread_mtx_);
|
|
||||||
if (io_stop_requested_ || not io_thread_) {
|
|
||||||
io_thread_notify_.notify_all();
|
|
||||||
io_lock.unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io_stop_requested_ = true;
|
|
||||||
io_thread_notify_.notify_all();
|
|
||||||
io_lock.unlock();
|
|
||||||
|
|
||||||
io_thread_->join();
|
|
||||||
io_thread_.reset();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file_base::do_io(std::function<api_error()> action) -> api_error {
|
auto open_file_base::do_io(std::function<api_error()> action) -> api_error {
|
||||||
unique_mutex_lock io_lock(io_thread_mtx_);
|
unique_mutex_lock io_lock(io_thread_mtx_);
|
||||||
auto item = std::make_shared<io_item>(action);
|
auto item = std::make_shared<io_item>(action);
|
||||||
@ -209,36 +191,6 @@ auto open_file_base::get_file_size() const -> std::uint64_t {
|
|||||||
return fsi_.size;
|
return fsi_.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto open_file_base::get_last_chunk_size() const -> std::size_t {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
return last_chunk_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_file_size(std::uint64_t size) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
fsi_.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_last_chunk_size(std::size_t size) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
last_chunk_size_ = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_modified(bool modified) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
modified_ = modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_removed(bool removed) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
removed_ = removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_source_path(std::string source_path) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
fsi_.source_path = std::move(source_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file_base::get_filesystem_item() const -> filesystem_item {
|
auto open_file_base::get_filesystem_item() const -> filesystem_item {
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
return fsi_;
|
return fsi_;
|
||||||
@ -283,11 +235,6 @@ auto open_file_base::get_open_file_count() const -> std::size_t {
|
|||||||
return open_data_.size();
|
return open_data_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file_base::get_source_path() const -> std::string {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
return fsi_.source_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file_base::has_handle(std::uint64_t handle) const -> bool {
|
auto open_file_base::has_handle(std::uint64_t handle) const -> bool {
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
return open_data_.find(handle) != open_data_.end();
|
return open_data_.find(handle) != open_data_.end();
|
||||||
@ -298,16 +245,6 @@ auto open_file_base::is_modified() const -> bool {
|
|||||||
return modified_;
|
return modified_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file_base::is_removed() const -> bool {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
return removed_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::notify_io() {
|
|
||||||
mutex_lock io_lock(io_thread_mtx_);
|
|
||||||
io_thread_notify_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::remove(std::uint64_t handle) {
|
void open_file_base::remove(std::uint64_t handle) {
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
if (open_data_.find(handle) == open_data_.end()) {
|
if (open_data_.find(handle) == open_data_.end()) {
|
||||||
@ -366,12 +303,27 @@ void open_file_base::set_api_path(const std::string &api_path) {
|
|||||||
fsi_.api_parent = utils::path::get_parent_api_path(api_path);
|
fsi_.api_parent = utils::path::get_parent_api_path(api_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file_base::wait_for_io(stop_type &stop_requested) {
|
void open_file_base::set_open_data(
|
||||||
|
std::map<std::uint64_t, open_file_data> open_data) {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
open_data_ = std::move(open_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto open_file_base::close() -> bool {
|
||||||
unique_mutex_lock io_lock(io_thread_mtx_);
|
unique_mutex_lock io_lock(io_thread_mtx_);
|
||||||
if (not stop_requested && io_thread_queue_.empty()) {
|
if (io_stop_requested_ || not io_thread_) {
|
||||||
io_thread_notify_.wait(io_lock);
|
io_thread_notify_.notify_all();
|
||||||
|
io_lock.unlock();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
io_stop_requested_ = true;
|
||||||
io_thread_notify_.notify_all();
|
io_thread_notify_.notify_all();
|
||||||
io_lock.unlock();
|
io_lock.unlock();
|
||||||
|
|
||||||
|
io_thread_->join();
|
||||||
|
io_thread_.reset();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -1,367 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "file_manager/ring_buffer_base.hpp"
|
|
||||||
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "file_manager/events.hpp"
|
|
||||||
#include "file_manager/open_file_base.hpp"
|
|
||||||
#include "platform/platform.hpp"
|
|
||||||
#include "providers/i_provider.hpp"
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
#include "utils/common.hpp"
|
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
ring_buffer_base::ring_buffer_base(std::uint64_t chunk_size,
|
|
||||||
std::uint8_t chunk_timeout,
|
|
||||||
filesystem_item fsi, i_provider &provider,
|
|
||||||
std::size_t ring_size, bool disable_io)
|
|
||||||
: open_file_base(chunk_size, chunk_timeout, fsi, provider, disable_io),
|
|
||||||
read_state_(ring_size),
|
|
||||||
total_chunks_(static_cast<std::size_t>(
|
|
||||||
utils::divide_with_ceiling(fsi.size, chunk_size))) {
|
|
||||||
if (disable_io) {
|
|
||||||
if (fsi.size > 0U) {
|
|
||||||
read_state_.resize(std::min(total_chunks_, read_state_.size()));
|
|
||||||
|
|
||||||
ring_end_ =
|
|
||||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
|
||||||
read_state_.set(0U, read_state_.size(), false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ring_size < min_ring_size) {
|
|
||||||
throw std::runtime_error("ring size must be greater than or equal to 5");
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_end_ = std::min(total_chunks_ - 1U, ring_begin_ + ring_size - 1U);
|
|
||||||
read_state_.set(0U, ring_size, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::check_start() -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (on_check_start()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_system::instance().raise<download_begin>(get_api_path(),
|
|
||||||
get_source_path());
|
|
||||||
reader_thread_ =
|
|
||||||
std::make_unique<std::thread>([this]() { reader_thread(); });
|
|
||||||
return api_error::success;
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(),
|
|
||||||
get_source_path(), ex,
|
|
||||||
"failed to start");
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::close() -> bool {
|
|
||||||
stop_requested_ = true;
|
|
||||||
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
|
|
||||||
auto res = open_file_base::close();
|
|
||||||
|
|
||||||
if (reader_thread_) {
|
|
||||||
reader_thread_->join();
|
|
||||||
reader_thread_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::download_chunk(std::size_t chunk,
|
|
||||||
bool skip_active) -> api_error {
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
const auto unlock_and_notify = [this, &chunk_lock]() {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto unlock_and_return =
|
|
||||||
[&unlock_and_notify](api_error res) -> api_error {
|
|
||||||
unlock_and_notify();
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (chunk < ring_begin_ || chunk > ring_end_) {
|
|
||||||
return unlock_and_return(api_error::invalid_ring_buffer_position);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_active_downloads().find(chunk) != get_active_downloads().end()) {
|
|
||||||
if (skip_active) {
|
|
||||||
return unlock_and_return(api_error::success);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto active_download = get_active_downloads().at(chunk);
|
|
||||||
unlock_and_notify();
|
|
||||||
|
|
||||||
return active_download->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_state_[chunk % read_state_.size()]) {
|
|
||||||
return unlock_and_return(api_error::success);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto active_download{std::make_shared<download>()};
|
|
||||||
get_active_downloads()[chunk] = active_download;
|
|
||||||
|
|
||||||
return use_buffer(chunk, [&](data_buffer &buffer) -> api_error {
|
|
||||||
auto data_offset{chunk * get_chunk_size()};
|
|
||||||
auto data_size{
|
|
||||||
chunk == (total_chunks_ - 1U) ? get_last_chunk_size()
|
|
||||||
: get_chunk_size(),
|
|
||||||
};
|
|
||||||
unlock_and_notify();
|
|
||||||
|
|
||||||
auto result{
|
|
||||||
get_provider().read_file_bytes(get_api_path(), data_size, data_offset,
|
|
||||||
buffer, stop_requested_),
|
|
||||||
};
|
|
||||||
|
|
||||||
chunk_lock.lock();
|
|
||||||
if (chunk < ring_begin_ || chunk > ring_end_) {
|
|
||||||
result = api_error::invalid_ring_buffer_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == api_error::success) {
|
|
||||||
result = on_chunk_downloaded(chunk, buffer);
|
|
||||||
if (result == api_error::success) {
|
|
||||||
read_state_[chunk % read_state_.size()] = true;
|
|
||||||
auto progress = (static_cast<double>(chunk + 1U) /
|
|
||||||
static_cast<double>(total_chunks_)) *
|
|
||||||
100.0;
|
|
||||||
event_system::instance().raise<download_progress>(
|
|
||||||
get_api_path(), get_source_path(), progress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get_active_downloads().erase(chunk);
|
|
||||||
unlock_and_notify();
|
|
||||||
|
|
||||||
active_download->notify(result);
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::forward(std::size_t count) {
|
|
||||||
update_position(count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::get_read_state() const -> boost::dynamic_bitset<> {
|
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
|
||||||
return read_state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::get_read_state(std::size_t chunk) const -> bool {
|
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
|
||||||
return read_state_[chunk % read_state_.size()];
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset,
|
|
||||||
data_buffer &data) -> api_error {
|
|
||||||
if (is_directory()) {
|
|
||||||
return api_error::invalid_operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
read_size =
|
|
||||||
utils::calculate_read_size(get_file_size(), read_size, read_offset);
|
|
||||||
if (read_size == 0U) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto begin_chunk{static_cast<std::size_t>(read_offset / get_chunk_size())};
|
|
||||||
read_offset = read_offset - (begin_chunk * get_chunk_size());
|
|
||||||
|
|
||||||
unique_mutex_lock read_lock(read_mtx_);
|
|
||||||
auto res = check_start();
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t chunk = begin_chunk;
|
|
||||||
not stop_requested_ && (res == api_error::success) && (read_size > 0U);
|
|
||||||
++chunk) {
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
if (chunk > ring_pos_) {
|
|
||||||
forward(chunk - ring_pos_);
|
|
||||||
} else if (chunk < ring_pos_) {
|
|
||||||
reverse(ring_pos_ - chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = download_chunk(chunk, false);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
if (res == api_error::invalid_ring_buffer_position) {
|
|
||||||
read_lock.unlock();
|
|
||||||
|
|
||||||
// TODO limit retry
|
|
||||||
return read(read_size, read_offset, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
std::size_t bytes_read{};
|
|
||||||
res = on_read_chunk(
|
|
||||||
chunk,
|
|
||||||
std::min(static_cast<std::size_t>(get_chunk_size() - read_offset),
|
|
||||||
read_size),
|
|
||||||
read_offset, data, bytes_read);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
read_size -= bytes_read;
|
|
||||||
read_offset = 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stop_requested_ ? api_error::download_stopped : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::reader_thread() {
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
auto next_chunk{ring_pos_};
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
|
|
||||||
while (not stop_requested_) {
|
|
||||||
chunk_lock.lock();
|
|
||||||
|
|
||||||
next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U;
|
|
||||||
const auto check_and_wait = [this, &chunk_lock, &next_chunk]() {
|
|
||||||
if (stop_requested_) {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_read_state().all()) {
|
|
||||||
chunk_notify_.wait(chunk_lock);
|
|
||||||
next_chunk = ring_pos_;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (read_state_[next_chunk % read_state_.size()]) {
|
|
||||||
check_and_wait();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
|
|
||||||
download_chunk(next_chunk, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
event_system::instance().raise<download_end>(
|
|
||||||
get_api_path(), get_source_path(), api_error::download_stopped);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::reverse(std::size_t count) {
|
|
||||||
update_position(count, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::set(std::size_t first_chunk, std::size_t current_chunk) {
|
|
||||||
mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
if (first_chunk >= total_chunks_) {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
throw std::runtime_error("first chunk must be less than total chunks");
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_begin_ = first_chunk;
|
|
||||||
ring_end_ =
|
|
||||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
|
||||||
|
|
||||||
if (current_chunk > ring_end_) {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
throw std::runtime_error(
|
|
||||||
"current chunk must be less than or equal to last chunk");
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_pos_ = current_chunk;
|
|
||||||
read_state_.set(0U, read_state_.size(), true);
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::set_api_path(const std::string &api_path) {
|
|
||||||
mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
open_file_base::set_api_path(api_path);
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::update_position(std::size_t count, bool is_forward) {
|
|
||||||
mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
|
|
||||||
if (is_forward) {
|
|
||||||
if ((ring_pos_ + count) > (total_chunks_ - 1U)) {
|
|
||||||
count = (total_chunks_ - 1U) - ring_pos_;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
count = std::min(ring_pos_, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_forward ? (ring_pos_ + count) <= ring_end_
|
|
||||||
: (ring_pos_ - count) >= ring_begin_) {
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
} else {
|
|
||||||
auto delta = is_forward ? count - (ring_end_ - ring_pos_)
|
|
||||||
: count - (ring_pos_ - ring_begin_);
|
|
||||||
|
|
||||||
if (delta >= read_state_.size()) {
|
|
||||||
read_state_.set(0U, read_state_.size(), false);
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
ring_begin_ += is_forward ? delta : -delta;
|
|
||||||
} else {
|
|
||||||
for (std::size_t idx = 0U; idx < delta; ++idx) {
|
|
||||||
if (is_forward) {
|
|
||||||
read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
|
|
||||||
} else {
|
|
||||||
read_state_[(ring_end_ - idx) % read_state_.size()] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ring_begin_ += is_forward ? delta : -delta;
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_end_ =
|
|
||||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -21,13 +21,18 @@
|
|||||||
*/
|
*/
|
||||||
#include "file_manager/ring_buffer_open_file.hpp"
|
#include "file_manager/ring_buffer_open_file.hpp"
|
||||||
|
|
||||||
|
#include "app_config.hpp"
|
||||||
|
#include "events/event_system.hpp"
|
||||||
|
#include "file_manager/events.hpp"
|
||||||
#include "file_manager/open_file_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
ring_buffer_open_file::ring_buffer_open_file(std::string buffer_directory,
|
ring_buffer_open_file::ring_buffer_open_file(std::string buffer_directory,
|
||||||
@ -36,15 +41,49 @@ ring_buffer_open_file::ring_buffer_open_file(std::string buffer_directory,
|
|||||||
filesystem_item fsi,
|
filesystem_item fsi,
|
||||||
i_provider &provider,
|
i_provider &provider,
|
||||||
std::size_t ring_size)
|
std::size_t ring_size)
|
||||||
: ring_buffer_base(chunk_size, chunk_timeout, fsi, provider, ring_size,
|
: open_file_base(chunk_size, chunk_timeout, fsi, provider),
|
||||||
false),
|
ring_state_(ring_size),
|
||||||
source_path_(utils::path::combine(buffer_directory,
|
total_chunks_(static_cast<std::size_t>(
|
||||||
{
|
utils::divide_with_ceiling(fsi_.size, chunk_size))) {
|
||||||
utils::create_uuid_string(),
|
if ((ring_size % 2U) != 0U) {
|
||||||
})) {
|
throw std::runtime_error("ring size must be a multiple of 2");
|
||||||
if (not can_handle_file(fsi.size, chunk_size, ring_size)) {
|
}
|
||||||
|
|
||||||
|
if (ring_size < 4U) {
|
||||||
|
throw std::runtime_error("ring size must be greater than or equal to 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not can_handle_file(fsi_.size, chunk_size, ring_size)) {
|
||||||
throw std::runtime_error("file size is less than ring buffer size");
|
throw std::runtime_error("file size is less than ring buffer size");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ring_end_ = std::min(total_chunks_ - 1U, ring_begin_ + ring_size - 1U);
|
||||||
|
ring_state_.set(0U, ring_size, true);
|
||||||
|
|
||||||
|
buffer_directory = utils::path::absolute(buffer_directory);
|
||||||
|
if (not utils::file::directory(buffer_directory).create_directory()) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
fmt::format("failed to create buffer directory|path|{}|err|{}",
|
||||||
|
buffer_directory, utils::get_last_error_code()));
|
||||||
|
}
|
||||||
|
|
||||||
|
source_path_ =
|
||||||
|
utils::path::combine(buffer_directory, {utils::create_uuid_string()});
|
||||||
|
nf_ = utils::file::file::open_or_create_file(source_path_);
|
||||||
|
if (not*nf_) {
|
||||||
|
throw std::runtime_error(fmt::format("failed to create buffer file|err|{}",
|
||||||
|
utils::get_last_error_code()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not nf_->truncate(ring_size * chunk_size)) {
|
||||||
|
nf_->close();
|
||||||
|
throw std::runtime_error(fmt::format("failed to resize buffer file|err|{}",
|
||||||
|
utils::get_last_error_code()));
|
||||||
|
}
|
||||||
|
|
||||||
|
reader_thread_ =
|
||||||
|
std::make_unique<std::thread>([this]() { background_reader_thread(); });
|
||||||
|
event_system::instance().raise<download_begin>(fsi_.api_path, source_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ring_buffer_open_file::~ring_buffer_open_file() {
|
ring_buffer_open_file::~ring_buffer_open_file() {
|
||||||
@ -52,24 +91,200 @@ ring_buffer_open_file::~ring_buffer_open_file() {
|
|||||||
|
|
||||||
close();
|
close();
|
||||||
|
|
||||||
if (not nf_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nf_->close();
|
nf_->close();
|
||||||
nf_.reset();
|
|
||||||
|
|
||||||
if (not utils::file::file(source_path_).remove()) {
|
if (not utils::file::file(source_path_).remove()) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, get_api_path(), source_path_,
|
function_name, fsi_.api_path, source_path_,
|
||||||
utils::get_last_error_code(), "failed to delete file");
|
utils::get_last_error_code(), "failed to delete file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader_thread_->join();
|
||||||
|
reader_thread_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ring_buffer_open_file::background_reader_thread() {
|
||||||
|
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
auto next_chunk = ring_pos_;
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
|
||||||
|
while (not stop_requested_) {
|
||||||
|
chunk_lock.lock();
|
||||||
|
|
||||||
|
next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U;
|
||||||
|
const auto check_and_wait = [this, &chunk_lock, &next_chunk]() {
|
||||||
|
if (stop_requested_) {
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_read_state().all()) {
|
||||||
|
chunk_notify_.wait(chunk_lock);
|
||||||
|
next_chunk = ring_pos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (not ring_state_[next_chunk % ring_state_.size()]) {
|
||||||
|
check_and_wait();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
|
||||||
|
download_chunk(next_chunk, true);
|
||||||
|
|
||||||
|
chunk_lock.lock();
|
||||||
|
check_and_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
event_system::instance().raise<download_end>(fsi_.api_path, source_path_,
|
||||||
|
api_error::download_stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::can_handle_file(std::uint64_t file_size,
|
auto ring_buffer_open_file::can_handle_file(std::uint64_t file_size,
|
||||||
std::size_t chunk_size,
|
std::size_t chunk_size,
|
||||||
std::size_t ring_size) -> bool {
|
std::size_t ring_size) -> bool {
|
||||||
return file_size >= (static_cast<std::uint64_t>(ring_size) * chunk_size);
|
return file_size >= (static_cast<std::uint64_t>(ring_size) * chunk_size * 2U);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ring_buffer_open_file::close() -> bool {
|
||||||
|
stop_requested_ = true;
|
||||||
|
|
||||||
|
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
|
||||||
|
return open_file_base::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ring_buffer_open_file::download_chunk(std::size_t chunk, bool skip_active)
|
||||||
|
-> api_error {
|
||||||
|
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
const auto unlock_and_notify = [this, &chunk_lock]() {
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto unlock_and_return =
|
||||||
|
[&unlock_and_notify](api_error res) -> api_error {
|
||||||
|
unlock_and_notify();
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (chunk < ring_begin_ || chunk > ring_end_) {
|
||||||
|
return unlock_and_return(api_error::invalid_ring_buffer_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active_downloads_.find(chunk) != active_downloads_.end()) {
|
||||||
|
if (skip_active) {
|
||||||
|
return unlock_and_return(api_error::success);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto active_download = active_downloads_.at(chunk);
|
||||||
|
unlock_and_notify();
|
||||||
|
|
||||||
|
return active_download->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not ring_state_[chunk % ring_state_.size()]) {
|
||||||
|
return unlock_and_return(api_error::success);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto active_download{std::make_shared<download>()};
|
||||||
|
active_downloads_[chunk] = active_download;
|
||||||
|
ring_state_[chunk % ring_state_.size()] = false;
|
||||||
|
unlock_and_notify();
|
||||||
|
|
||||||
|
data_buffer buffer;
|
||||||
|
auto data_offset{chunk * chunk_size_};
|
||||||
|
auto data_size{
|
||||||
|
chunk == (total_chunks_ - 1U) ? last_chunk_size_ : chunk_size_,
|
||||||
|
};
|
||||||
|
|
||||||
|
event_system::instance().raise<download_chunk_begin>(
|
||||||
|
fsi_.api_path, source_path_, chunk, get_read_state().size(),
|
||||||
|
get_read_state().count());
|
||||||
|
|
||||||
|
auto res{
|
||||||
|
provider_.read_file_bytes(fsi_.api_path, data_size, data_offset, buffer,
|
||||||
|
stop_requested_),
|
||||||
|
};
|
||||||
|
|
||||||
|
chunk_lock.lock();
|
||||||
|
if (res == api_error::success) {
|
||||||
|
auto progress =
|
||||||
|
(static_cast<double>(chunk + 1U) / static_cast<double>(total_chunks_)) *
|
||||||
|
100.0;
|
||||||
|
event_system::instance().raise<download_progress>(fsi_.api_path,
|
||||||
|
source_path_, progress);
|
||||||
|
res = (chunk >= ring_begin_ && chunk <= ring_end_)
|
||||||
|
? do_io([&]() -> api_error {
|
||||||
|
std::size_t bytes_written{};
|
||||||
|
if (nf_->write(buffer,
|
||||||
|
(chunk % ring_state_.size()) * chunk_size_,
|
||||||
|
&bytes_written)) {
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_error::os_error;
|
||||||
|
})
|
||||||
|
: api_error::invalid_ring_buffer_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_system::instance().raise<download_chunk_end>(
|
||||||
|
fsi_.api_path, source_path_, chunk, get_read_state().size(),
|
||||||
|
get_read_state().count(), res);
|
||||||
|
|
||||||
|
active_downloads_.erase(chunk);
|
||||||
|
unlock_and_notify();
|
||||||
|
|
||||||
|
active_download->notify(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ring_buffer_open_file::forward(std::size_t count) {
|
||||||
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
if ((ring_pos_ + count) > (total_chunks_ - 1U)) {
|
||||||
|
count = (total_chunks_ - 1U) - ring_pos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ring_pos_ + count) <= ring_end_) {
|
||||||
|
ring_pos_ += count;
|
||||||
|
} else {
|
||||||
|
auto added = count - (ring_end_ - ring_pos_);
|
||||||
|
if (added >= ring_state_.size()) {
|
||||||
|
ring_state_.set(0U, ring_state_.size(), true);
|
||||||
|
ring_pos_ += count;
|
||||||
|
ring_begin_ += added;
|
||||||
|
} else {
|
||||||
|
for (std::size_t idx = 0U; idx < added; ++idx) {
|
||||||
|
ring_state_[(ring_begin_ + idx) % ring_state_.size()] = true;
|
||||||
|
}
|
||||||
|
ring_begin_ += added;
|
||||||
|
ring_pos_ += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
ring_end_ =
|
||||||
|
std::min(total_chunks_ - 1U, ring_begin_ + ring_state_.size() - 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ring_buffer_open_file::get_read_state() const -> boost::dynamic_bitset<> {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
auto read_state = ring_state_;
|
||||||
|
return read_state.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ring_buffer_open_file::get_read_state(std::size_t chunk) const -> bool {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
return not ring_state_[chunk % ring_state_.size()];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::native_operation(
|
auto ring_buffer_open_file::native_operation(
|
||||||
@ -77,75 +292,137 @@ auto ring_buffer_open_file::native_operation(
|
|||||||
return do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
return do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::on_check_start() -> bool {
|
void ring_buffer_open_file::reverse(std::size_t count) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
count = std::min(ring_pos_, count);
|
||||||
|
|
||||||
if (nf_) {
|
if ((ring_pos_ - count) >= ring_begin_) {
|
||||||
return true;
|
ring_pos_ -= count;
|
||||||
}
|
} else {
|
||||||
|
auto removed = count - (ring_pos_ - ring_begin_);
|
||||||
auto buffer_directory{utils::path::get_parent_path(source_path_)};
|
if (removed >= ring_state_.size()) {
|
||||||
if (not utils::file::directory(buffer_directory).create_directory()) {
|
ring_state_.set(0U, ring_state_.size(), true);
|
||||||
throw std::runtime_error(
|
ring_pos_ -= count;
|
||||||
fmt::format("failed to create buffer directory|path|{}|err|{}",
|
ring_begin_ = ring_pos_;
|
||||||
buffer_directory, utils::get_last_error_code()));
|
} else {
|
||||||
}
|
for (std::size_t idx = 0U; idx < removed; ++idx) {
|
||||||
|
ring_state_[(ring_end_ - idx) % ring_state_.size()] = true;
|
||||||
nf_ = utils::file::file::open_or_create_file(source_path_);
|
}
|
||||||
if (not nf_ || not *nf_) {
|
ring_begin_ -= removed;
|
||||||
throw std::runtime_error(fmt::format("failed to create buffer file|err|{}",
|
ring_pos_ -= count;
|
||||||
utils::get_last_error_code()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not nf_->truncate(get_ring_size() * get_chunk_size())) {
|
|
||||||
nf_->close();
|
|
||||||
nf_.reset();
|
|
||||||
|
|
||||||
throw std::runtime_error(fmt::format("failed to resize buffer file|err|{}",
|
|
||||||
utils::get_last_error_code()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_open_file::on_chunk_downloaded(
|
|
||||||
std::size_t chunk, const data_buffer &buffer) -> api_error {
|
|
||||||
return do_io([&]() -> api_error {
|
|
||||||
std::size_t bytes_written{};
|
|
||||||
if (nf_->write(buffer, (chunk % get_ring_size()) * get_chunk_size(),
|
|
||||||
&bytes_written)) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return api_error::os_error;
|
ring_end_ =
|
||||||
});
|
std::min(total_chunks_ - 1U, ring_begin_ + ring_state_.size() - 1U);
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_open_file::on_read_chunk(
|
|
||||||
std::size_t chunk, std::size_t read_size, std::uint64_t read_offset,
|
|
||||||
data_buffer &data, std::size_t &bytes_read) -> api_error {
|
|
||||||
data_buffer buffer(read_size);
|
|
||||||
auto res = do_io([&]() -> api_error {
|
|
||||||
return nf_->read(
|
|
||||||
buffer,
|
|
||||||
(((chunk % get_ring_size()) * get_chunk_size()) + read_offset),
|
|
||||||
&bytes_read)
|
|
||||||
? api_error::success
|
|
||||||
: api_error::os_error;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.insert(data.end(), buffer.begin(), buffer.end());
|
chunk_notify_.notify_all();
|
||||||
return api_error::success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::use_buffer(
|
auto ring_buffer_open_file::read(std::size_t read_size,
|
||||||
std::size_t /* chunk */,
|
std::uint64_t read_offset, data_buffer &data)
|
||||||
std::function<api_error(data_buffer &)> func) -> api_error {
|
-> api_error {
|
||||||
data_buffer buffer;
|
if (fsi_.directory) {
|
||||||
return func(buffer);
|
return api_error::invalid_operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_timeout();
|
||||||
|
|
||||||
|
read_size = utils::calculate_read_size(fsi_.size, read_size, read_offset);
|
||||||
|
if (read_size == 0U) {
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto begin_chunk{static_cast<std::size_t>(read_offset / chunk_size_)};
|
||||||
|
read_offset = read_offset - (begin_chunk * chunk_size_);
|
||||||
|
|
||||||
|
auto res{api_error::success};
|
||||||
|
|
||||||
|
unique_mutex_lock read_lock(read_mtx_);
|
||||||
|
for (std::size_t chunk = begin_chunk;
|
||||||
|
(res == api_error::success) && (read_size > 0U); ++chunk) {
|
||||||
|
if (chunk > ring_pos_) {
|
||||||
|
forward(chunk - ring_pos_);
|
||||||
|
} else if (chunk < ring_pos_) {
|
||||||
|
reverse(ring_pos_ - chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = download_chunk(chunk, false);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
if (not stop_requested_ &&
|
||||||
|
res == api_error::invalid_ring_buffer_position) {
|
||||||
|
read_lock.unlock();
|
||||||
|
|
||||||
|
// TODO limit retry
|
||||||
|
return read(read_size, read_offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_timeout();
|
||||||
|
|
||||||
|
auto to_read{
|
||||||
|
std::min(static_cast<std::size_t>(chunk_size_ - read_offset),
|
||||||
|
read_size),
|
||||||
|
};
|
||||||
|
|
||||||
|
res = do_io([&]() -> api_error {
|
||||||
|
data_buffer buffer(to_read);
|
||||||
|
|
||||||
|
std::size_t bytes_read{};
|
||||||
|
auto result = nf_->read(buffer,
|
||||||
|
(((chunk % ring_state_.size()) * chunk_size_) +
|
||||||
|
read_offset),
|
||||||
|
&bytes_read)
|
||||||
|
? api_error::success
|
||||||
|
: api_error::os_error;
|
||||||
|
|
||||||
|
if (result != api_error::success) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_timeout();
|
||||||
|
|
||||||
|
data.insert(data.end(), buffer.begin(), buffer.end());
|
||||||
|
read_size -= bytes_read;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
read_offset = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ring_buffer_open_file::set(std::size_t first_chunk,
|
||||||
|
std::size_t current_chunk) {
|
||||||
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
if (first_chunk >= total_chunks_) {
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
throw std::runtime_error("first chunk must be less than total chunks");
|
||||||
|
}
|
||||||
|
|
||||||
|
ring_begin_ = first_chunk;
|
||||||
|
ring_end_ =
|
||||||
|
std::min(total_chunks_ - 1U, ring_begin_ + ring_state_.size() - 1U);
|
||||||
|
|
||||||
|
if (current_chunk > ring_end_) {
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
throw std::runtime_error(
|
||||||
|
"current chunk must be less than or equal to last chunk");
|
||||||
|
}
|
||||||
|
|
||||||
|
ring_pos_ = current_chunk;
|
||||||
|
ring_state_.set(0U, ring_state_.size(), false);
|
||||||
|
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ring_buffer_open_file::set_api_path(const std::string &api_path) {
|
||||||
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
open_file_base::set_api_path(api_path);
|
||||||
|
chunk_notify_.notify_all();
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -51,6 +51,8 @@ void full_server::handle_get_directory_items(const httplib::Request &req,
|
|||||||
|
|
||||||
void full_server::handle_get_drive_information(const httplib::Request & /*req*/,
|
void full_server::handle_get_drive_information(const httplib::Request & /*req*/,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
|
auto dir_size =
|
||||||
|
utils::file::directory(get_config().get_cache_directory()).size();
|
||||||
res.set_content(
|
res.set_content(
|
||||||
json({
|
json({
|
||||||
{"cache_space_used", cache_size_mgr::instance().size()},
|
{"cache_space_used", cache_size_mgr::instance().size()},
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto database_type_from_string(std::string type,
|
auto database_type_from_string(std::string type, database_type default_type)
|
||||||
database_type default_type) -> database_type {
|
-> database_type {
|
||||||
type = utils::string::to_lower(utils::string::trim(type));
|
type = utils::string::to_lower(utils::string::trim(type));
|
||||||
if (type == "rocksdb") {
|
if (type == "rocksdb") {
|
||||||
return database_type::rocksdb;
|
return database_type::rocksdb;
|
||||||
@ -50,17 +50,17 @@ auto database_type_to_string(const database_type &type) -> std::string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto download_type_from_string(std::string type,
|
auto download_type_from_string(std::string type, download_type default_type)
|
||||||
download_type default_type) -> download_type {
|
-> download_type {
|
||||||
type = utils::string::to_lower(utils::string::trim(type));
|
type = utils::string::to_lower(utils::string::trim(type));
|
||||||
if (type == "default") {
|
|
||||||
return download_type::default_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == "direct") {
|
if (type == "direct") {
|
||||||
return download_type::direct;
|
return download_type::direct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == "fallback") {
|
||||||
|
return download_type::fallback;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == "ring_buffer") {
|
if (type == "ring_buffer") {
|
||||||
return download_type::ring_buffer;
|
return download_type::ring_buffer;
|
||||||
}
|
}
|
||||||
@ -70,14 +70,14 @@ auto download_type_from_string(std::string type,
|
|||||||
|
|
||||||
auto download_type_to_string(const download_type &type) -> std::string {
|
auto download_type_to_string(const download_type &type) -> std::string {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case download_type::default_:
|
|
||||||
return "default";
|
|
||||||
case download_type::direct:
|
case download_type::direct:
|
||||||
return "direct";
|
return "direct";
|
||||||
|
case download_type::fallback:
|
||||||
|
return "fallback";
|
||||||
case download_type::ring_buffer:
|
case download_type::ring_buffer:
|
||||||
return "ring_buffer";
|
return "ring_buffer";
|
||||||
default:
|
default:
|
||||||
return "default";
|
return "fallback";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +52,6 @@ auto from_api_error(const api_error &err) -> int {
|
|||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
case api_error::file_in_use:
|
case api_error::file_in_use:
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
case api_error::invalid_handle:
|
|
||||||
return -EBADF;
|
|
||||||
case api_error::invalid_operation:
|
case api_error::invalid_operation:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case api_error::item_not_found:
|
case api_error::item_not_found:
|
||||||
|
@ -29,13 +29,6 @@
|
|||||||
namespace repertory {
|
namespace repertory {
|
||||||
class mock_open_file : public virtual i_closeable_open_file {
|
class mock_open_file : public virtual i_closeable_open_file {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD(void, add, (std::uint64_t handle, open_file_data ofd),
|
|
||||||
(override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, can_close, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, close, (), (override));
|
|
||||||
|
|
||||||
MOCK_METHOD(std::string, get_api_path, (), (const, override));
|
MOCK_METHOD(std::string, get_api_path, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(std::size_t, get_chunk_size, (), (const, override));
|
MOCK_METHOD(std::size_t, get_chunk_size, (), (const, override));
|
||||||
@ -56,28 +49,14 @@ public:
|
|||||||
|
|
||||||
MOCK_METHOD(bool, get_allocated, (), (const, override));
|
MOCK_METHOD(bool, get_allocated, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(std::vector<std::uint64_t>, get_handles, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD((std::map<std::uint64_t, open_file_data> &), get_open_data, (),
|
|
||||||
(override));
|
|
||||||
|
|
||||||
MOCK_METHOD((const std::map<std::uint64_t, open_file_data> &), get_open_data,
|
|
||||||
(), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, get_read_state, (std::size_t chunk), (const, override));
|
MOCK_METHOD(bool, get_read_state, (std::size_t chunk), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(std::string, get_source_path, (), (const, override));
|
MOCK_METHOD(std::string, get_source_path, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(bool, has_handle, (std::uint64_t handle), (const, override));
|
MOCK_METHOD(bool, has_handle, (std::uint64_t handle), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_complete, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_directory, (), (const, override));
|
MOCK_METHOD(bool, is_directory, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_modified, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_write_supported, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(api_error, native_operation, (native_operation_callback callback),
|
MOCK_METHOD(api_error, native_operation, (native_operation_callback callback),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
@ -90,10 +69,6 @@ public:
|
|||||||
data_buffer &data),
|
data_buffer &data),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
MOCK_METHOD(void, remove, (std::uint64_t handle), (override));
|
|
||||||
|
|
||||||
MOCK_METHOD(void, remove_all, (), (override));
|
|
||||||
|
|
||||||
MOCK_METHOD(api_error, resize, (std::uint64_t new_file_size), (override));
|
MOCK_METHOD(api_error, resize, (std::uint64_t new_file_size), (override));
|
||||||
|
|
||||||
MOCK_METHOD(void, set_api_path, (const std::string &api_path), (override));
|
MOCK_METHOD(void, set_api_path, (const std::string &api_path), (override));
|
||||||
@ -102,6 +77,35 @@ public:
|
|||||||
(std::uint64_t write_offset, const data_buffer &data,
|
(std::uint64_t write_offset, const data_buffer &data,
|
||||||
std::size_t &bytes_written),
|
std::size_t &bytes_written),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, add, (std::uint64_t handle, open_file_data ofd),
|
||||||
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, can_close, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, close, (), (override));
|
||||||
|
|
||||||
|
MOCK_METHOD(std::vector<std::uint64_t>, get_handles, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD((std::map<std::uint64_t, open_file_data> &), get_open_data, (),
|
||||||
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD((const std::map<std::uint64_t, open_file_data> &), get_open_data,
|
||||||
|
(), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, is_complete, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, is_modified, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, is_write_supported, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, remove, (std::uint64_t handle), (override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, remove_all, (), (override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, set_open_data,
|
||||||
|
((std::map<std::uint64_t, open_file_data> open_data)),
|
||||||
|
(override));
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -52,14 +52,11 @@ TEST_F(direct_open_file_test, read_full_file) {
|
|||||||
fsi.directory = false;
|
fsi.directory = false;
|
||||||
fsi.size = test_chunk_size * 32U;
|
fsi.size = test_chunk_size * 32U;
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
EXPECT_CALL(provider, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
.WillRepeatedly([&source_file](const std::string & /* api_path */,
|
||||||
const std::string & /* api_path */, std::size_t size,
|
std::size_t size, std::uint64_t offset,
|
||||||
std::uint64_t offset, data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
@ -114,14 +111,11 @@ TEST_F(direct_open_file_test, read_full_file_in_reverse) {
|
|||||||
fsi.directory = false;
|
fsi.directory = false;
|
||||||
fsi.size = test_chunk_size * 32U;
|
fsi.size = test_chunk_size * 32U;
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
EXPECT_CALL(provider, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
.WillRepeatedly([&source_file](const std::string & /* api_path */,
|
||||||
const std::string & /* api_path */, std::size_t size,
|
std::size_t size, std::uint64_t offset,
|
||||||
std::uint64_t offset, data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
@ -176,14 +170,11 @@ TEST_F(direct_open_file_test, read_full_file_in_partial_chunks) {
|
|||||||
fsi.api_path = "/test.txt";
|
fsi.api_path = "/test.txt";
|
||||||
fsi.size = test_chunk_size * 32U;
|
fsi.size = test_chunk_size * 32U;
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
EXPECT_CALL(provider, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
.WillRepeatedly([&source_file](const std::string & /* api_path */,
|
||||||
const std::string & /* api_path */, std::size_t size,
|
std::size_t size, std::uint64_t offset,
|
||||||
std::uint64_t offset, data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
@ -235,14 +226,11 @@ TEST_F(direct_open_file_test, read_full_file_in_partial_chunks_in_reverse) {
|
|||||||
fsi.api_path = "/test.txt";
|
fsi.api_path = "/test.txt";
|
||||||
fsi.size = test_chunk_size * 32U;
|
fsi.size = test_chunk_size * 32U;
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
EXPECT_CALL(provider, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
.WillRepeatedly([&source_file](const std::string & /* api_path */,
|
||||||
const std::string & /* api_path */, std::size_t size,
|
std::size_t size, std::uint64_t offset,
|
||||||
std::uint64_t offset, data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
|
@ -431,6 +431,16 @@ TEST_F(file_manager_test,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::uint64_t handle{};
|
||||||
|
std::shared_ptr<i_open_file> open_file;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
EXPECT_EQ(api_error::success, mgr.open("/test_write_partial_download.txt",
|
||||||
|
false, {}, handle, open_file));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(api_error::success, mgr.open("/test_write_partial_download.txt",
|
||||||
|
false, O_RDWR, handle, open_file));
|
||||||
|
#endif
|
||||||
|
|
||||||
EXPECT_CALL(mp, read_file_bytes)
|
EXPECT_CALL(mp, read_file_bytes)
|
||||||
.WillRepeatedly([&file](const std::string & /* api_path */,
|
.WillRepeatedly([&file](const std::string & /* api_path */,
|
||||||
std::size_t size, std::uint64_t offset,
|
std::size_t size, std::uint64_t offset,
|
||||||
@ -455,17 +465,6 @@ TEST_F(file_manager_test,
|
|||||||
|
|
||||||
return api_error::download_stopped;
|
return api_error::download_stopped;
|
||||||
});
|
});
|
||||||
|
|
||||||
std::uint64_t handle{};
|
|
||||||
std::shared_ptr<i_open_file> open_file;
|
|
||||||
#if defined(_WIN32)
|
|
||||||
EXPECT_EQ(api_error::success, mgr.open("/test_write_partial_download.txt",
|
|
||||||
false, {}, handle, open_file));
|
|
||||||
#else
|
|
||||||
EXPECT_EQ(api_error::success, mgr.open("/test_write_partial_download.txt",
|
|
||||||
false, O_RDWR, handle, open_file));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EXPECT_CALL(mp, set_item_meta("/test_write_partial_download.txt", _))
|
EXPECT_CALL(mp, set_item_meta("/test_write_partial_download.txt", _))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
[](const std::string &, const api_meta_map &meta2) -> api_error {
|
[](const std::string &, const api_meta_map &meta2) -> api_error {
|
||||||
@ -476,10 +475,6 @@ TEST_F(file_manager_test,
|
|||||||
});
|
});
|
||||||
EXPECT_CALL(mp, upload_file).Times(0u);
|
EXPECT_CALL(mp, upload_file).Times(0u);
|
||||||
|
|
||||||
if (not open_file->is_write_supported()) {
|
|
||||||
EXPECT_TRUE(mgr.get_open_file(handle, true, open_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t bytes_written{};
|
std::size_t bytes_written{};
|
||||||
data_buffer data = {0, 1, 2};
|
data_buffer data = {0, 1, 2};
|
||||||
EXPECT_EQ(api_error::success, open_file->write(0u, data, bytes_written));
|
EXPECT_EQ(api_error::success, open_file->write(0u, data, bytes_written));
|
||||||
@ -565,6 +560,7 @@ TEST_F(file_manager_test, upload_occurs_after_write_if_fully_downloaded) {
|
|||||||
EXPECT_STREQ(source_path.c_str(),
|
EXPECT_STREQ(source_path.c_str(),
|
||||||
evt2.get_source().get<std::string>().c_str());
|
evt2.get_source().get<std::string>().c_str());
|
||||||
});
|
});
|
||||||
|
event_capture capture({"download_end"});
|
||||||
|
|
||||||
auto now = utils::time::get_time_now();
|
auto now = utils::time::get_time_now();
|
||||||
auto meta = create_meta_attributes(
|
auto meta = create_meta_attributes(
|
||||||
@ -588,6 +584,16 @@ TEST_F(file_manager_test, upload_occurs_after_write_if_fully_downloaded) {
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::uint64_t handle{};
|
||||||
|
std::shared_ptr<i_open_file> open_file;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
EXPECT_EQ(api_error::success, mgr.open("/test_write_full_download.txt", false,
|
||||||
|
{}, handle, open_file));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(api_error::success, mgr.open("/test_write_full_download.txt", false,
|
||||||
|
O_RDWR, handle, open_file));
|
||||||
|
#endif
|
||||||
|
|
||||||
EXPECT_CALL(mp, read_file_bytes)
|
EXPECT_CALL(mp, read_file_bytes)
|
||||||
.WillRepeatedly([&file](const std::string & /* api_path */,
|
.WillRepeatedly([&file](const std::string & /* api_path */,
|
||||||
std::size_t size, std::uint64_t offset,
|
std::size_t size, std::uint64_t offset,
|
||||||
@ -600,17 +606,6 @@ TEST_F(file_manager_test, upload_occurs_after_write_if_fully_downloaded) {
|
|||||||
EXPECT_EQ(bytes_read, data.size());
|
EXPECT_EQ(bytes_read, data.size());
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
std::uint64_t handle{};
|
|
||||||
std::shared_ptr<i_open_file> open_file;
|
|
||||||
#if defined(_WIN32)
|
|
||||||
EXPECT_EQ(api_error::success, mgr.open("/test_write_full_download.txt", false,
|
|
||||||
{}, handle, open_file));
|
|
||||||
#else
|
|
||||||
EXPECT_EQ(api_error::success, mgr.open("/test_write_full_download.txt", false,
|
|
||||||
O_RDWR, handle, open_file));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EXPECT_CALL(mp, set_item_meta("/test_write_full_download.txt", _))
|
EXPECT_CALL(mp, set_item_meta("/test_write_full_download.txt", _))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
[](const std::string &, const api_meta_map &meta2) -> api_error {
|
[](const std::string &, const api_meta_map &meta2) -> api_error {
|
||||||
@ -619,33 +614,25 @@ TEST_F(file_manager_test, upload_occurs_after_write_if_fully_downloaded) {
|
|||||||
EXPECT_NO_THROW(EXPECT_FALSE(meta2.at(META_WRITTEN).empty()));
|
EXPECT_NO_THROW(EXPECT_FALSE(meta2.at(META_WRITTEN).empty()));
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (not open_file->is_write_supported()) {
|
|
||||||
EXPECT_TRUE(mgr.get_open_file(handle, true, open_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
event_capture capture({
|
|
||||||
"item_timeout",
|
|
||||||
"file_upload_queued",
|
|
||||||
"file_upload_completed",
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_CALL(mp, upload_file("/test_write_full_download.txt", source_path, _))
|
|
||||||
.WillOnce(Return(api_error::success));
|
|
||||||
|
|
||||||
std::size_t bytes_written{};
|
std::size_t bytes_written{};
|
||||||
data_buffer data = {0, 1, 2};
|
data_buffer data = {0, 1, 2};
|
||||||
EXPECT_EQ(api_error::success, open_file->write(0u, data, bytes_written));
|
EXPECT_EQ(api_error::success, open_file->write(0u, data, bytes_written));
|
||||||
EXPECT_EQ(std::size_t(3u), bytes_written);
|
EXPECT_EQ(std::size_t(3u), bytes_written);
|
||||||
|
|
||||||
while (not open_file->is_complete()) {
|
|
||||||
std::this_thread::sleep_for(10ms);
|
|
||||||
}
|
|
||||||
open_file.reset();
|
open_file.reset();
|
||||||
|
|
||||||
|
capture.wait_for_empty();
|
||||||
|
|
||||||
|
EXPECT_CALL(mp, upload_file("/test_write_full_download.txt", source_path, _))
|
||||||
|
.WillOnce(Return(api_error::success));
|
||||||
|
|
||||||
|
event_capture ec2({
|
||||||
|
"item_timeout",
|
||||||
|
"file_upload_queued",
|
||||||
|
"file_upload_completed",
|
||||||
|
});
|
||||||
mgr.close(handle);
|
mgr.close(handle);
|
||||||
|
|
||||||
capture.wait_for_empty();
|
ec2.wait_for_empty();
|
||||||
|
|
||||||
EXPECT_EQ(std::size_t(0U), mgr.get_open_file_count());
|
EXPECT_EQ(std::size_t(0U), mgr.get_open_file_count());
|
||||||
EXPECT_EQ(std::size_t(0U), mgr.get_open_handle_count());
|
EXPECT_EQ(std::size_t(0U), mgr.get_open_handle_count());
|
||||||
@ -710,10 +697,6 @@ TEST_F(file_manager_test, can_evict_file) {
|
|||||||
.WillRepeatedly(Return(api_error::success));
|
.WillRepeatedly(Return(api_error::success));
|
||||||
EXPECT_CALL(mp, upload_file(_, _, _)).WillOnce(Return(api_error::success));
|
EXPECT_CALL(mp, upload_file(_, _, _)).WillOnce(Return(api_error::success));
|
||||||
|
|
||||||
if (not open_file->is_write_supported()) {
|
|
||||||
EXPECT_TRUE(mgr.get_open_file(handle, true, open_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
data_buffer data{{0, 1, 1}};
|
data_buffer data{{0, 1, 1}};
|
||||||
std::size_t bytes_written{};
|
std::size_t bytes_written{};
|
||||||
auto res = open_file->write(0U, data, bytes_written);
|
auto res = open_file->write(0U, data, bytes_written);
|
||||||
@ -730,6 +713,15 @@ TEST_F(file_manager_test, can_evict_file) {
|
|||||||
EXPECT_TRUE(utils::retry_action(
|
EXPECT_TRUE(utils::retry_action(
|
||||||
[&mgr]() -> bool { return not mgr.is_processing("/test_evict.txt"); }));
|
[&mgr]() -> bool { return not mgr.is_processing("/test_evict.txt"); }));
|
||||||
|
|
||||||
|
EXPECT_CALL(mp, get_item_meta(_, META_SOURCE, _))
|
||||||
|
.WillOnce([&source_path](const std::string &api_path,
|
||||||
|
const std::string &key,
|
||||||
|
std::string &value) -> api_error {
|
||||||
|
EXPECT_STREQ("/test_evict.txt", api_path.c_str());
|
||||||
|
EXPECT_STREQ(META_SOURCE.c_str(), key.c_str());
|
||||||
|
value = source_path;
|
||||||
|
return api_error::success;
|
||||||
|
});
|
||||||
EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _))
|
EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _))
|
||||||
.WillOnce([](const std::string &api_path, const std::string &key,
|
.WillOnce([](const std::string &api_path, const std::string &key,
|
||||||
std::string &value) -> api_error {
|
std::string &value) -> api_error {
|
||||||
@ -748,17 +740,6 @@ TEST_F(file_manager_test, evict_file_fails_if_file_is_pinned) {
|
|||||||
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
||||||
file_manager mgr(*cfg, mp);
|
file_manager mgr(*cfg, mp);
|
||||||
|
|
||||||
EXPECT_CALL(mp, get_filesystem_item)
|
|
||||||
.WillRepeatedly([](const std::string &api_path, bool directory,
|
|
||||||
filesystem_item &fsi) -> api_error {
|
|
||||||
fsi.api_path = api_path;
|
|
||||||
fsi.api_parent = utils::path::get_parent_api_path(api_path);
|
|
||||||
fsi.directory = directory;
|
|
||||||
fsi.size = 2U;
|
|
||||||
fsi.source_path = "/test/test_open.src";
|
|
||||||
return api_error::success;
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _))
|
EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _))
|
||||||
.WillOnce([](const std::string &api_path, const std::string &key,
|
.WillOnce([](const std::string &api_path, const std::string &key,
|
||||||
std::string &value) -> api_error {
|
std::string &value) -> api_error {
|
||||||
@ -817,17 +798,28 @@ TEST_F(file_manager_test, evict_file_fails_if_file_is_open) {
|
|||||||
mgr.close(handle);
|
mgr.close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(file_manager_test, evict_file_fails_if_unable_to_get_filesystem_item) {
|
TEST_F(file_manager_test,
|
||||||
|
evict_file_fails_if_unable_to_get_source_path_from_item_meta) {
|
||||||
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
||||||
file_manager mgr(*cfg, mp);
|
file_manager mgr(*cfg, mp);
|
||||||
|
|
||||||
EXPECT_CALL(mp, get_filesystem_item)
|
EXPECT_CALL(mp, get_item_meta(_, META_SOURCE, _))
|
||||||
.WillRepeatedly([](const std::string & /* api_path */,
|
.WillOnce([](const std::string &api_path, const std::string &key,
|
||||||
bool /* directory */,
|
std::string & /*value*/) -> api_error {
|
||||||
filesystem_item & /* fsi */) -> api_error {
|
EXPECT_STREQ("/test_open.txt", api_path.c_str());
|
||||||
|
EXPECT_STREQ(META_SOURCE.c_str(), key.c_str());
|
||||||
return api_error::error;
|
return api_error::error;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _))
|
||||||
|
.WillOnce([](const std::string &api_path, const std::string &key,
|
||||||
|
std::string &value) -> api_error {
|
||||||
|
EXPECT_STREQ("/test_open.txt", api_path.c_str());
|
||||||
|
EXPECT_STREQ(META_PINNED.c_str(), key.c_str());
|
||||||
|
value = "0";
|
||||||
|
return api_error::success;
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_FALSE(mgr.evict_file("/test_open.txt"));
|
EXPECT_FALSE(mgr.evict_file("/test_open.txt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,13 +827,20 @@ TEST_F(file_manager_test, evict_file_fails_if_source_path_is_empty) {
|
|||||||
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
||||||
file_manager mgr(*cfg, mp);
|
file_manager mgr(*cfg, mp);
|
||||||
|
|
||||||
EXPECT_CALL(mp, get_filesystem_item)
|
EXPECT_CALL(mp, get_item_meta(_, META_SOURCE, _))
|
||||||
.WillRepeatedly([](const std::string &api_path, bool directory,
|
.WillOnce([](const std::string &api_path, const std::string &key,
|
||||||
filesystem_item &fsi) -> api_error {
|
std::string &value) -> api_error {
|
||||||
fsi.api_path = api_path;
|
EXPECT_STREQ("/test_open.txt", api_path.c_str());
|
||||||
fsi.api_parent = utils::path::get_parent_api_path(api_path);
|
EXPECT_STREQ(META_SOURCE.c_str(), key.c_str());
|
||||||
fsi.directory = directory;
|
value = "";
|
||||||
fsi.size = 20U;
|
return api_error::success;
|
||||||
|
});
|
||||||
|
EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _))
|
||||||
|
.WillOnce([](const std::string &api_path, const std::string &key,
|
||||||
|
std::string &value) -> api_error {
|
||||||
|
EXPECT_STREQ("/test_open.txt", api_path.c_str());
|
||||||
|
EXPECT_STREQ(META_PINNED.c_str(), key.c_str());
|
||||||
|
value = "0";
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -909,10 +908,6 @@ TEST_F(file_manager_test, evict_file_fails_if_file_is_uploading) {
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (not open_file->is_write_supported()) {
|
|
||||||
EXPECT_TRUE(mgr.get_open_file(handle, true, open_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
data_buffer data{{0, 1, 1}};
|
data_buffer data{{0, 1, 1}};
|
||||||
std::size_t bytes_written{};
|
std::size_t bytes_written{};
|
||||||
EXPECT_EQ(api_error::success, open_file->write(0U, data, bytes_written));
|
EXPECT_EQ(api_error::success, open_file->write(0U, data, bytes_written));
|
||||||
@ -956,7 +951,6 @@ TEST_F(file_manager_test, evict_file_fails_if_file_is_modified) {
|
|||||||
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
EXPECT_CALL(mp, is_read_only()).WillRepeatedly(Return(false));
|
||||||
|
|
||||||
file_manager mgr(*cfg, mp);
|
file_manager mgr(*cfg, mp);
|
||||||
|
|
||||||
EXPECT_CALL(mp, get_filesystem_item)
|
EXPECT_CALL(mp, get_filesystem_item)
|
||||||
.WillOnce([](const std::string &api_path, bool directory,
|
.WillOnce([](const std::string &api_path, bool directory,
|
||||||
filesystem_item &fsi) -> api_error {
|
filesystem_item &fsi) -> api_error {
|
||||||
@ -971,12 +965,11 @@ TEST_F(file_manager_test, evict_file_fails_if_file_is_modified) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
auto file = std::make_shared<mock_open_file>();
|
auto file = std::make_shared<mock_open_file>();
|
||||||
|
EXPECT_CALL(*file, is_directory).WillOnce(Return(false));
|
||||||
EXPECT_CALL(*file, add).WillOnce(Return());
|
EXPECT_CALL(*file, add).WillOnce(Return());
|
||||||
EXPECT_CALL(*file, get_api_path).WillRepeatedly(Return("/test_evict.txt"));
|
EXPECT_CALL(*file, get_api_path).WillRepeatedly(Return("/test_evict.txt"));
|
||||||
EXPECT_CALL(*file, get_source_path).WillRepeatedly(Return("/test_evict.src"));
|
EXPECT_CALL(*file, get_source_path).WillRepeatedly(Return("/test_evict.src"));
|
||||||
EXPECT_CALL(*file, is_directory).WillOnce(Return(false));
|
EXPECT_CALL(*file, is_modified).Times(2).WillRepeatedly(Return(true));
|
||||||
EXPECT_CALL(*file, is_modified).WillRepeatedly(Return(true));
|
|
||||||
EXPECT_CALL(*file, is_write_supported).WillRepeatedly(Return(true));
|
|
||||||
|
|
||||||
std::uint64_t handle{};
|
std::uint64_t handle{};
|
||||||
std::shared_ptr<i_open_file> open_file;
|
std::shared_ptr<i_open_file> open_file;
|
||||||
@ -999,21 +992,20 @@ TEST_F(file_manager_test, evict_file_fails_if_file_is_not_complete) {
|
|||||||
filesystem_item &fsi) -> api_error {
|
filesystem_item &fsi) -> api_error {
|
||||||
EXPECT_STREQ("/test_evict.txt", api_path.c_str());
|
EXPECT_STREQ("/test_evict.txt", api_path.c_str());
|
||||||
EXPECT_FALSE(directory);
|
EXPECT_FALSE(directory);
|
||||||
fsi.api_parent = utils::path::get_parent_api_path(api_path);
|
|
||||||
fsi.api_path = api_path;
|
fsi.api_path = api_path;
|
||||||
|
fsi.api_parent = utils::path::get_parent_api_path(api_path);
|
||||||
fsi.directory = directory;
|
fsi.directory = directory;
|
||||||
fsi.size = 1U;
|
fsi.size = 1U;
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto file = std::make_shared<mock_open_file>();
|
auto file = std::make_shared<mock_open_file>();
|
||||||
|
EXPECT_CALL(*file, is_directory).WillOnce(Return(false));
|
||||||
EXPECT_CALL(*file, add).WillOnce(Return());
|
EXPECT_CALL(*file, add).WillOnce(Return());
|
||||||
EXPECT_CALL(*file, get_api_path).WillRepeatedly(Return("/test_evict.txt"));
|
EXPECT_CALL(*file, get_api_path).WillRepeatedly(Return("/test_evict.txt"));
|
||||||
EXPECT_CALL(*file, get_source_path).WillRepeatedly(Return("/test_evict.src"));
|
EXPECT_CALL(*file, get_source_path).WillRepeatedly(Return("/test_evict.src"));
|
||||||
EXPECT_CALL(*file, is_complete).WillRepeatedly(Return(false));
|
EXPECT_CALL(*file, is_modified).Times(2).WillRepeatedly(Return(false));
|
||||||
EXPECT_CALL(*file, is_directory).WillOnce(Return(false));
|
EXPECT_CALL(*file, is_complete).Times(2).WillRepeatedly(Return(false));
|
||||||
EXPECT_CALL(*file, is_modified).WillRepeatedly(Return(false));
|
|
||||||
EXPECT_CALL(*file, is_write_supported).WillRepeatedly(Return(true));
|
|
||||||
EXPECT_CALL(mp, set_item_meta("/test_evict.txt", META_SOURCE, _))
|
EXPECT_CALL(mp, set_item_meta("/test_evict.txt", META_SOURCE, _))
|
||||||
.WillOnce(Return(api_error::success));
|
.WillOnce(Return(api_error::success));
|
||||||
|
|
||||||
@ -1469,26 +1461,6 @@ TEST_F(file_manager_test, file_is_closed_after_download_timeout) {
|
|||||||
|
|
||||||
event_capture capture({"item_timeout"});
|
event_capture capture({"item_timeout"});
|
||||||
|
|
||||||
EXPECT_CALL(mp, read_file_bytes)
|
|
||||||
.WillRepeatedly([](const std::string & /* api_path */, std::size_t size,
|
|
||||||
std::uint64_t offset, data_buffer &data,
|
|
||||||
stop_type &stop_requested) -> api_error {
|
|
||||||
if (stop_requested) {
|
|
||||||
return api_error::download_stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset == 0U) {
|
|
||||||
data.resize(size);
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (not stop_requested) {
|
|
||||||
std::this_thread::sleep_for(100ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::download_stopped;
|
|
||||||
});
|
|
||||||
|
|
||||||
std::uint64_t handle{};
|
std::uint64_t handle{};
|
||||||
std::shared_ptr<i_open_file> open_file;
|
std::shared_ptr<i_open_file> open_file;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -1499,15 +1471,33 @@ TEST_F(file_manager_test, file_is_closed_after_download_timeout) {
|
|||||||
O_RDWR, handle, open_file));
|
O_RDWR, handle, open_file));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
EXPECT_CALL(mp, read_file_bytes)
|
||||||
|
.WillRepeatedly([](const std::string & /* api_path */,
|
||||||
|
std::size_t /*size*/, std::uint64_t offset,
|
||||||
|
data_buffer & /*data*/,
|
||||||
|
stop_type &stop_requested) -> api_error {
|
||||||
|
if (stop_requested) {
|
||||||
|
return api_error::download_stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset == 0U) {
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (not stop_requested) {
|
||||||
|
std::this_thread::sleep_for(100ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_error::download_stopped;
|
||||||
|
});
|
||||||
|
|
||||||
data_buffer data{};
|
data_buffer data{};
|
||||||
EXPECT_EQ(api_error::success, open_file->read(1U, 0U, data));
|
EXPECT_EQ(api_error::success, open_file->read(1U, 0U, data));
|
||||||
|
|
||||||
mgr.close(handle);
|
mgr.close(handle);
|
||||||
|
|
||||||
if (open_file->is_write_supported()) {
|
EXPECT_CALL(mp, set_item_meta("/test_download_timeout.txt", META_SOURCE, _))
|
||||||
EXPECT_CALL(mp, set_item_meta("/test_download_timeout.txt", META_SOURCE, _))
|
.WillOnce(Return(api_error::success));
|
||||||
.WillOnce(Return(api_error::success));
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPECT_EQ(std::size_t(1U), mgr.get_open_file_count());
|
EXPECT_EQ(std::size_t(1U), mgr.get_open_file_count());
|
||||||
capture.wait_for_empty();
|
capture.wait_for_empty();
|
||||||
|
@ -213,9 +213,9 @@ TEST(json_serialize, can_handle_download_type) {
|
|||||||
EXPECT_EQ(download_type::direct, data.get<download_type>());
|
EXPECT_EQ(download_type::direct, data.get<download_type>());
|
||||||
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
||||||
|
|
||||||
data = download_type::default_;
|
data = download_type::fallback;
|
||||||
EXPECT_EQ(download_type::default_, data.get<download_type>());
|
EXPECT_EQ(download_type::fallback, data.get<download_type>());
|
||||||
EXPECT_STREQ("default", data.get<std::string>().c_str());
|
EXPECT_STREQ("fallback", data.get<std::string>().c_str());
|
||||||
|
|
||||||
data = download_type::ring_buffer;
|
data = download_type::ring_buffer;
|
||||||
EXPECT_EQ(download_type::ring_buffer, data.get<download_type>());
|
EXPECT_EQ(download_type::ring_buffer, data.get<download_type>());
|
||||||
@ -237,9 +237,9 @@ TEST(json_serialize, can_handle_atomic_download_type) {
|
|||||||
EXPECT_EQ(download_type::direct, data.get<atomic<download_type>>());
|
EXPECT_EQ(download_type::direct, data.get<atomic<download_type>>());
|
||||||
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
||||||
|
|
||||||
data = atomic<download_type>{download_type::default_};
|
data = atomic<download_type>{download_type::fallback};
|
||||||
EXPECT_EQ(download_type::default_, data.get<download_type>());
|
EXPECT_EQ(download_type::fallback, data.get<download_type>());
|
||||||
EXPECT_STREQ("default", data.get<std::string>().c_str());
|
EXPECT_STREQ("fallback", data.get<std::string>().c_str());
|
||||||
|
|
||||||
data = atomic<download_type>{download_type::ring_buffer};
|
data = atomic<download_type>{download_type::ring_buffer};
|
||||||
EXPECT_EQ(download_type::ring_buffer, data.get<atomic<download_type>>());
|
EXPECT_EQ(download_type::ring_buffer, data.get<atomic<download_type>>());
|
||||||
|
@ -308,14 +308,11 @@ TEST_F(ring_buffer_open_file_test, read_full_file) {
|
|||||||
fsi.size = test_chunk_size * 33u + 11u;
|
fsi.size = test_chunk_size * 33u + 11u;
|
||||||
fsi.source_path = test::generate_test_file_name("ring_buffer_open_file");
|
fsi.source_path = test::generate_test_file_name("ring_buffer_open_file");
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(mp, read_file_bytes)
|
EXPECT_CALL(mp, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &nf](const std::string & /* api_path */,
|
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||||
std::size_t size, std::uint64_t offset,
|
std::size_t size, std::uint64_t offset,
|
||||||
data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
@ -374,14 +371,11 @@ TEST_F(ring_buffer_open_file_test, read_full_file_in_reverse) {
|
|||||||
fsi.size = test_chunk_size * 32u;
|
fsi.size = test_chunk_size * 32u;
|
||||||
fsi.source_path = test::generate_test_file_name("ring_buffer_open_file");
|
fsi.source_path = test::generate_test_file_name("ring_buffer_open_file");
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(mp, read_file_bytes)
|
EXPECT_CALL(mp, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &nf](const std::string & /* api_path */,
|
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||||
std::size_t size, std::uint64_t offset,
|
std::size_t size, std::uint64_t offset,
|
||||||
data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
@ -440,14 +434,11 @@ TEST_F(ring_buffer_open_file_test, read_full_file_in_partial_chunks) {
|
|||||||
fsi.size = test_chunk_size * 32u;
|
fsi.size = test_chunk_size * 32u;
|
||||||
fsi.source_path = test::generate_test_file_name("test");
|
fsi.source_path = test::generate_test_file_name("test");
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(mp, read_file_bytes)
|
EXPECT_CALL(mp, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &nf](const std::string & /* api_path */,
|
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||||
std::size_t size, std::uint64_t offset,
|
std::size_t size, std::uint64_t offset,
|
||||||
data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
@ -508,14 +499,11 @@ TEST_F(ring_buffer_open_file_test,
|
|||||||
fsi.size = test_chunk_size * 32u;
|
fsi.size = test_chunk_size * 32u;
|
||||||
fsi.source_path = test::generate_test_file_name("ring_buffer_open_file");
|
fsi.source_path = test::generate_test_file_name("ring_buffer_open_file");
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(mp, read_file_bytes)
|
EXPECT_CALL(mp, read_file_bytes)
|
||||||
.WillRepeatedly([&read_mtx, &nf](const std::string & /* api_path */,
|
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||||
std::size_t size, std::uint64_t offset,
|
std::size_t size, std::uint64_t offset,
|
||||||
data_buffer &data,
|
data_buffer &data,
|
||||||
stop_type &stop_requested) -> api_error {
|
stop_type &stop_requested) -> api_error {
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
EXPECT_FALSE(stop_requested);
|
||||||
std::size_t bytes_read{};
|
std::size_t bytes_read{};
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
|
Reference in New Issue
Block a user