tosnativeclient 1.0.2__tar.gz → 1.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tosnativeclient might be problematic. Click here for more details.
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/Cargo.lock +1 -1
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/Cargo.toml +1 -1
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/PKG-INFO +1 -1
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/python/tosnativeclient/tosnativeclient.pyi +15 -4
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/list_stream.rs +42 -5
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/read_stream.rs +17 -11
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/tos_client.rs +44 -4
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/tos_error.rs +14 -2
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/tos_model.rs +2 -2
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/tos_raw_client.rs +92 -25
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/write_stream.rs +31 -8
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/.github/workflows/CI.yml +0 -0
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/.gitignore +0 -0
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/build.sh +0 -0
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/pyproject.toml +0 -0
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/python/tosnativeclient/__init__.py +0 -0
- {tosnativeclient-1.0.2 → tosnativeclient-1.0.5}/src/lib.rs +0 -0
|
@@ -31,6 +31,8 @@ class ListStream(object):
|
|
|
31
31
|
prefix: str
|
|
32
32
|
delimiter: str
|
|
33
33
|
max_keys: int
|
|
34
|
+
continuation_token: str
|
|
35
|
+
start_after: str
|
|
34
36
|
|
|
35
37
|
def __iter__(self) -> ListStream: ...
|
|
36
38
|
|
|
@@ -38,6 +40,10 @@ class ListStream(object):
|
|
|
38
40
|
|
|
39
41
|
def close(self) -> None: ...
|
|
40
42
|
|
|
43
|
+
def current_prefix(self) -> Optional[str]: ...
|
|
44
|
+
|
|
45
|
+
def current_continuation_token(self) -> Optional[str]: ...
|
|
46
|
+
|
|
41
47
|
|
|
42
48
|
class ReadStream(object):
|
|
43
49
|
bucket: str
|
|
@@ -45,7 +51,7 @@ class ReadStream(object):
|
|
|
45
51
|
size: int
|
|
46
52
|
etag: str
|
|
47
53
|
|
|
48
|
-
def read(self, offset: int, length: int) -> bytes:
|
|
54
|
+
def read(self, offset: int, length: int) -> Optional[bytes]:
|
|
49
55
|
...
|
|
50
56
|
|
|
51
57
|
def close(self) -> None:
|
|
@@ -72,13 +78,18 @@ class TosClient(object):
|
|
|
72
78
|
part_size: int
|
|
73
79
|
max_retry_count: int
|
|
74
80
|
max_prefetch_tasks: int
|
|
81
|
+
directives: str
|
|
82
|
+
directory: str
|
|
83
|
+
file_name_prefix: str
|
|
84
|
+
shared_prefetch_tasks: int
|
|
75
85
|
|
|
76
86
|
def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', part_size: int = 8388608,
|
|
77
87
|
max_retry_count: int = 3, max_prefetch_tasks: int = 3, directives: str = '', directory: str = '',
|
|
78
88
|
file_name_prefix: str = '', shared_prefetch_tasks: int = 20):
|
|
79
89
|
...
|
|
80
90
|
|
|
81
|
-
def list_objects(self, bucket: str, prefix: str = '', max_keys: int = 1000, delimiter: str = ''
|
|
91
|
+
def list_objects(self, bucket: str, prefix: str = '', max_keys: int = 1000, delimiter: str = '',
|
|
92
|
+
continuation_token: str = '', start_after: str = '') -> ListStream:
|
|
82
93
|
...
|
|
83
94
|
|
|
84
95
|
def head_object(self, bucket: str, key: str) -> TosObject:
|
|
@@ -147,10 +158,10 @@ class GetObjectOutput(object):
|
|
|
147
158
|
content_range: str
|
|
148
159
|
hash_crc64ecma: int
|
|
149
160
|
|
|
150
|
-
def read_all(self) -> bytes:
|
|
161
|
+
def read_all(self) -> Optional[bytes]:
|
|
151
162
|
...
|
|
152
163
|
|
|
153
|
-
def read(self) -> bytes:
|
|
164
|
+
def read(self) -> Optional[bytes]:
|
|
154
165
|
...
|
|
155
166
|
|
|
156
167
|
|
|
@@ -3,7 +3,8 @@ use crate::tos_error::{map_error_from_string, map_tos_error};
|
|
|
3
3
|
use crate::tos_model::ListObjectsResult;
|
|
4
4
|
use arc_swap::ArcSwap;
|
|
5
5
|
use async_channel::Receiver;
|
|
6
|
-
use pyo3::
|
|
6
|
+
use pyo3::types::PyTuple;
|
|
7
|
+
use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyRefMut, PyResult, Python};
|
|
7
8
|
use std::sync::atomic::{AtomicI8, Ordering};
|
|
8
9
|
use std::sync::{Arc, RwLock};
|
|
9
10
|
use tokio::runtime::Runtime;
|
|
@@ -12,7 +13,7 @@ use ve_tos_rust_sdk::error::TosError;
|
|
|
12
13
|
use ve_tos_rust_sdk::object::{ListObjectsType2Input, ListObjectsType2Output};
|
|
13
14
|
|
|
14
15
|
const DEFAULT_TASK_COUNT: usize = 5;
|
|
15
|
-
#[pyclass(name = "ListStream")]
|
|
16
|
+
#[pyclass(name = "ListStream", module = "tosnativeclient")]
|
|
16
17
|
pub struct ListStream {
|
|
17
18
|
client: Arc<InnerTosClient>,
|
|
18
19
|
runtime: Arc<Runtime>,
|
|
@@ -26,6 +27,10 @@ pub struct ListStream {
|
|
|
26
27
|
delimiter: String,
|
|
27
28
|
#[pyo3(get)]
|
|
28
29
|
max_keys: isize,
|
|
30
|
+
#[pyo3(get)]
|
|
31
|
+
continuation_token: String,
|
|
32
|
+
#[pyo3(get)]
|
|
33
|
+
start_after: String,
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
#[pymethods]
|
|
@@ -63,6 +68,22 @@ impl ListStream {
|
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
}
|
|
71
|
+
|
|
72
|
+
pub fn current_prefix(&self) -> PyResult<Option<String>> {
|
|
73
|
+
let pg = self.paginator.read().unwrap();
|
|
74
|
+
match pg.as_ref() {
|
|
75
|
+
None => Ok(None),
|
|
76
|
+
Some(pg) => Ok(Some(pg.current_prefix())),
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub fn current_continuation_token(&self) -> PyResult<Option<String>> {
|
|
81
|
+
let pg = self.paginator.read().unwrap();
|
|
82
|
+
match pg.as_ref() {
|
|
83
|
+
None => Ok(None),
|
|
84
|
+
Some(pg) => Ok(Some(pg.current_continuation_token())),
|
|
85
|
+
}
|
|
86
|
+
}
|
|
66
87
|
}
|
|
67
88
|
|
|
68
89
|
impl ListStream {
|
|
@@ -73,6 +94,8 @@ impl ListStream {
|
|
|
73
94
|
prefix: String,
|
|
74
95
|
delimiter: String,
|
|
75
96
|
max_keys: isize,
|
|
97
|
+
continuation_token: String,
|
|
98
|
+
start_after: String,
|
|
76
99
|
) -> Self {
|
|
77
100
|
Self {
|
|
78
101
|
client,
|
|
@@ -83,6 +106,8 @@ impl ListStream {
|
|
|
83
106
|
prefix,
|
|
84
107
|
delimiter,
|
|
85
108
|
max_keys,
|
|
109
|
+
continuation_token,
|
|
110
|
+
start_after,
|
|
86
111
|
}
|
|
87
112
|
}
|
|
88
113
|
|
|
@@ -93,7 +118,12 @@ impl ListStream {
|
|
|
93
118
|
input.set_prefix(self.prefix.as_str());
|
|
94
119
|
input.set_max_keys(self.max_keys);
|
|
95
120
|
input.set_delimiter(self.delimiter.as_str());
|
|
96
|
-
|
|
121
|
+
if self.continuation_token != "" {
|
|
122
|
+
input.set_continuation_token(self.continuation_token.as_str());
|
|
123
|
+
}
|
|
124
|
+
if self.start_after != "" {
|
|
125
|
+
input.set_start_after(self.start_after.as_str());
|
|
126
|
+
}
|
|
97
127
|
py.allow_threads(|| {
|
|
98
128
|
self.runtime.spawn(async move {
|
|
99
129
|
let mut need_break = false;
|
|
@@ -157,6 +187,7 @@ impl ListStream {
|
|
|
157
187
|
is_end: ArcSwap::new(Arc::new(false)),
|
|
158
188
|
last_err: ArcSwap::new(Arc::new(None)),
|
|
159
189
|
current_prefix: ArcSwap::new(Arc::new(self.prefix.clone())),
|
|
190
|
+
current_continuation_token: ArcSwap::new(Arc::new(self.continuation_token.clone())),
|
|
160
191
|
receiver,
|
|
161
192
|
})
|
|
162
193
|
}
|
|
@@ -195,6 +226,7 @@ pub(crate) struct Paginator {
|
|
|
195
226
|
is_end: ArcSwap<bool>,
|
|
196
227
|
last_err: ArcSwap<Option<TosError>>,
|
|
197
228
|
current_prefix: ArcSwap<String>,
|
|
229
|
+
current_continuation_token: ArcSwap<String>,
|
|
198
230
|
receiver: Receiver<(bool, Result<ListObjectsType2Output, TosError>)>,
|
|
199
231
|
}
|
|
200
232
|
|
|
@@ -206,8 +238,11 @@ impl Paginator {
|
|
|
206
238
|
Ok(!*self.is_end.load().as_ref())
|
|
207
239
|
}
|
|
208
240
|
|
|
209
|
-
fn current_prefix(&self) ->
|
|
210
|
-
self.current_prefix.load().
|
|
241
|
+
fn current_prefix(&self) -> String {
|
|
242
|
+
self.current_prefix.load().to_string()
|
|
243
|
+
}
|
|
244
|
+
fn current_continuation_token(&self) -> String {
|
|
245
|
+
self.current_continuation_token.load().to_string()
|
|
211
246
|
}
|
|
212
247
|
async fn next_page(&self) -> Result<ListObjectsType2Output, TosError> {
|
|
213
248
|
if let Some(e) = self.last_err.load().as_ref() {
|
|
@@ -236,6 +271,8 @@ impl Paginator {
|
|
|
236
271
|
Ok(output) => {
|
|
237
272
|
self.current_prefix
|
|
238
273
|
.store(Arc::new(output.prefix().to_string()));
|
|
274
|
+
self.current_continuation_token
|
|
275
|
+
.store(Arc::new(output.continuation_token().to_string()));
|
|
239
276
|
if is_end {
|
|
240
277
|
self.is_end.store(Arc::new(true));
|
|
241
278
|
}
|
|
@@ -4,8 +4,8 @@ use crate::tos_model::TosObject;
|
|
|
4
4
|
use async_channel::{Receiver, Sender};
|
|
5
5
|
use bytes::Bytes;
|
|
6
6
|
use futures_util::StreamExt;
|
|
7
|
-
use pyo3::types::PyBytes;
|
|
8
|
-
use pyo3::{pyclass, pymethods, Bound, PyRef, PyResult};
|
|
7
|
+
use pyo3::types::{PyBytes, PyTuple};
|
|
8
|
+
use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyResult};
|
|
9
9
|
use std::collections::LinkedList;
|
|
10
10
|
use std::sync::atomic::{AtomicI8, AtomicIsize, Ordering};
|
|
11
11
|
use std::sync::Arc;
|
|
@@ -24,7 +24,7 @@ const DEFAULT_PART_SIZE: isize = 8 * 1024 * 1024;
|
|
|
24
24
|
const DEFAULT_FETCH_RETRY_COUNT: isize = 3;
|
|
25
25
|
const DEFAULT_SHARED_PREFETCH_TASK_LIMIT: isize = 100;
|
|
26
26
|
|
|
27
|
-
#[pyclass(name = "ReadStream")]
|
|
27
|
+
#[pyclass(name = "ReadStream", module = "tosnativeclient")]
|
|
28
28
|
pub struct ReadStream {
|
|
29
29
|
object_fetcher: Arc<ObjectFetcher>,
|
|
30
30
|
runtime: Arc<Runtime>,
|
|
@@ -117,6 +117,7 @@ impl ReadStream {
|
|
|
117
117
|
Self {
|
|
118
118
|
object_fetcher: Arc::new(ObjectFetcher {
|
|
119
119
|
client,
|
|
120
|
+
runtime: runtime.clone(),
|
|
120
121
|
closed: Arc::new(AtomicI8::new(0)),
|
|
121
122
|
pc,
|
|
122
123
|
fc: Mutex::new(fc),
|
|
@@ -149,6 +150,7 @@ impl ReadStream {
|
|
|
149
150
|
|
|
150
151
|
struct ObjectFetcher {
|
|
151
152
|
client: Arc<InnerTosClient>,
|
|
153
|
+
runtime: Arc<Runtime>,
|
|
152
154
|
closed: Arc<AtomicI8>,
|
|
153
155
|
pc: PrefetchConfig,
|
|
154
156
|
fc: Mutex<FetchContext>,
|
|
@@ -295,7 +297,7 @@ impl ObjectFetcher {
|
|
|
295
297
|
if fc.has_tasks() {
|
|
296
298
|
fc.current = fc.pop_task()
|
|
297
299
|
} else {
|
|
298
|
-
fc.current = self.start_fetch_task(fc);
|
|
300
|
+
fc.current = self.start_fetch_task(fc, self.runtime.clone());
|
|
299
301
|
}
|
|
300
302
|
}
|
|
301
303
|
Some(current) => {
|
|
@@ -304,17 +306,17 @@ impl ObjectFetcher {
|
|
|
304
306
|
if fc.has_tasks() {
|
|
305
307
|
fc.current = fc.pop_task()
|
|
306
308
|
} else {
|
|
307
|
-
fc.current = self.start_fetch_task(fc);
|
|
309
|
+
fc.current = self.start_fetch_task(fc, self.runtime.clone());
|
|
308
310
|
}
|
|
309
311
|
} else if fc.exceed_sequential_read_threshold() {
|
|
310
312
|
if fc.can_add_task(self.pc.max_prefetch_tasks) {
|
|
311
|
-
if let Some(next) = self.start_fetch_task(fc) {
|
|
313
|
+
if let Some(next) = self.start_fetch_task(fc, self.runtime.clone()) {
|
|
312
314
|
fc.push_task(next, false);
|
|
313
315
|
}
|
|
314
316
|
} else if fc.can_steal_shared_task(self.pc.shared_prefetch_task_limit)
|
|
315
317
|
&& fc.pcontext.try_steal_shared_prefetch_task()
|
|
316
318
|
{
|
|
317
|
-
match self.start_fetch_task(fc) {
|
|
319
|
+
match self.start_fetch_task(fc, self.runtime.clone()) {
|
|
318
320
|
Some(mut next) => {
|
|
319
321
|
next.is_shared = true;
|
|
320
322
|
fc.steal_shared_task();
|
|
@@ -330,14 +332,18 @@ impl ObjectFetcher {
|
|
|
330
332
|
}
|
|
331
333
|
}
|
|
332
334
|
|
|
333
|
-
fn start_fetch_task(
|
|
335
|
+
fn start_fetch_task(
|
|
336
|
+
&self,
|
|
337
|
+
fc: &mut MutexGuard<'_, FetchContext>,
|
|
338
|
+
runtime: Arc<Runtime>,
|
|
339
|
+
) -> Option<FetchTask> {
|
|
334
340
|
if fc.next_request_offset >= self.om.size {
|
|
335
341
|
return None;
|
|
336
342
|
}
|
|
337
343
|
|
|
338
344
|
let task = self.new_fetch_task(fc);
|
|
339
345
|
self.revise_next_request_offset_and_size(fc, task.size);
|
|
340
|
-
task.async_fetch(self.client.clone());
|
|
346
|
+
task.async_fetch(self.client.clone(), runtime);
|
|
341
347
|
Some(task)
|
|
342
348
|
}
|
|
343
349
|
|
|
@@ -660,9 +666,9 @@ impl FetchTask {
|
|
|
660
666
|
self.start_offset + self.fetched_size.load(Ordering::Acquire)
|
|
661
667
|
}
|
|
662
668
|
|
|
663
|
-
fn async_fetch(&self, client: Arc<InnerTosClient>) {
|
|
669
|
+
fn async_fetch(&self, client: Arc<InnerTosClient>, runtime: Arc<Runtime>) {
|
|
664
670
|
let fetch_task_context = FetchTaskContext::new(self, client);
|
|
665
|
-
|
|
671
|
+
runtime.spawn(async move {
|
|
666
672
|
fetch_task_context.fetch_from_server().await;
|
|
667
673
|
fetch_task_context.chunk_queue.close();
|
|
668
674
|
});
|
|
@@ -5,7 +5,9 @@ use crate::tos_model::TosObject;
|
|
|
5
5
|
use crate::write_stream::WriteStream;
|
|
6
6
|
use async_trait::async_trait;
|
|
7
7
|
use futures_util::future::BoxFuture;
|
|
8
|
-
use pyo3::
|
|
8
|
+
use pyo3::prelude::PyDictMethods;
|
|
9
|
+
use pyo3::types::{PyDict, PyTuple};
|
|
10
|
+
use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyAny, PyObject, PyRef, PyRefMut, PyResult};
|
|
9
11
|
use std::future::Future;
|
|
10
12
|
use std::sync::atomic::{AtomicIsize, Ordering};
|
|
11
13
|
use std::sync::Arc;
|
|
@@ -53,7 +55,7 @@ impl AsyncRuntime for TokioRuntime {
|
|
|
53
55
|
pub(crate) type InnerTosClient =
|
|
54
56
|
TosClientImpl<CommonCredentialsProvider<CommonCredentials>, CommonCredentials, TokioRuntime>;
|
|
55
57
|
|
|
56
|
-
#[pyclass(name = "TosClient")]
|
|
58
|
+
#[pyclass(name = "TosClient", module = "tosnativeclient")]
|
|
57
59
|
pub struct TosClient {
|
|
58
60
|
rclient: Arc<InnerTosClient>,
|
|
59
61
|
wclient: Arc<InnerTosClient>,
|
|
@@ -75,6 +77,14 @@ pub struct TosClient {
|
|
|
75
77
|
max_retry_count: isize,
|
|
76
78
|
#[pyo3(get)]
|
|
77
79
|
max_prefetch_tasks: isize,
|
|
80
|
+
#[pyo3(get)]
|
|
81
|
+
directives: String,
|
|
82
|
+
#[pyo3(get)]
|
|
83
|
+
directory: String,
|
|
84
|
+
#[pyo3(get)]
|
|
85
|
+
file_name_prefix: String,
|
|
86
|
+
#[pyo3(get)]
|
|
87
|
+
shared_prefetch_tasks: isize,
|
|
78
88
|
}
|
|
79
89
|
|
|
80
90
|
#[pymethods]
|
|
@@ -97,7 +107,11 @@ impl TosClient {
|
|
|
97
107
|
) -> PyResult<Self> {
|
|
98
108
|
let mut _guard = None;
|
|
99
109
|
if directives != "" {
|
|
100
|
-
_guard = Some(init_tracing_log(
|
|
110
|
+
_guard = Some(init_tracing_log(
|
|
111
|
+
directives.clone(),
|
|
112
|
+
directory.clone(),
|
|
113
|
+
file_name_prefix.clone(),
|
|
114
|
+
));
|
|
101
115
|
}
|
|
102
116
|
|
|
103
117
|
let logical_cores = num_cpus::get();
|
|
@@ -142,16 +156,22 @@ impl TosClient {
|
|
|
142
156
|
part_size,
|
|
143
157
|
max_retry_count,
|
|
144
158
|
max_prefetch_tasks,
|
|
159
|
+
directives,
|
|
160
|
+
directory,
|
|
161
|
+
file_name_prefix,
|
|
162
|
+
shared_prefetch_tasks,
|
|
145
163
|
})
|
|
146
164
|
}
|
|
147
165
|
|
|
148
|
-
#[pyo3(signature = (bucket, prefix=String::from(""), max_keys=1000, delimiter=String::from("")))]
|
|
166
|
+
#[pyo3(signature = (bucket, prefix=String::from(""), max_keys=1000, delimiter=String::from(""), continuation_token=String::from(""), start_after=String::from("")))]
|
|
149
167
|
pub fn list_objects(
|
|
150
168
|
&self,
|
|
151
169
|
bucket: String,
|
|
152
170
|
prefix: String,
|
|
153
171
|
max_keys: isize,
|
|
154
172
|
delimiter: String,
|
|
173
|
+
continuation_token: String,
|
|
174
|
+
start_after: String,
|
|
155
175
|
) -> ListStream {
|
|
156
176
|
ListStream::new(
|
|
157
177
|
self.rclient.clone(),
|
|
@@ -160,6 +180,8 @@ impl TosClient {
|
|
|
160
180
|
prefix,
|
|
161
181
|
delimiter,
|
|
162
182
|
max_keys,
|
|
183
|
+
continuation_token,
|
|
184
|
+
start_after,
|
|
163
185
|
)
|
|
164
186
|
}
|
|
165
187
|
pub fn head_object(slf: PyRef<'_, Self>, bucket: String, key: String) -> PyResult<TosObject> {
|
|
@@ -210,6 +232,24 @@ impl TosClient {
|
|
|
210
232
|
})
|
|
211
233
|
})
|
|
212
234
|
}
|
|
235
|
+
|
|
236
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
237
|
+
let py = slf.py();
|
|
238
|
+
let state = [
|
|
239
|
+
slf.region.clone().into_pyobject(py)?.into_any(),
|
|
240
|
+
slf.endpoint.clone().into_pyobject(py)?.into_any(),
|
|
241
|
+
slf.ak.clone().into_pyobject(py)?.into_any(),
|
|
242
|
+
slf.sk.clone().into_pyobject(py)?.into_any(),
|
|
243
|
+
slf.part_size.into_pyobject(py)?.into_any(),
|
|
244
|
+
slf.max_retry_count.into_pyobject(py)?.into_any(),
|
|
245
|
+
slf.max_prefetch_tasks.into_pyobject(py)?.into_any(),
|
|
246
|
+
"".into_pyobject(py)?.into_any(),
|
|
247
|
+
"".into_pyobject(py)?.into_any(),
|
|
248
|
+
"".into_pyobject(py)?.into_any(),
|
|
249
|
+
slf.shared_prefetch_tasks.into_pyobject(py)?.into_any(),
|
|
250
|
+
];
|
|
251
|
+
PyTuple::new(py, state)
|
|
252
|
+
}
|
|
213
253
|
}
|
|
214
254
|
|
|
215
255
|
pub(crate) struct SharedPrefetchContext {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
use pyo3::exceptions::PyException;
|
|
2
|
-
use pyo3::
|
|
2
|
+
use pyo3::types::PyTuple;
|
|
3
|
+
use pyo3::{create_exception, pyclass, pymethods, Bound, IntoPyObject, PyErr, PyRef, PyResult};
|
|
3
4
|
use std::error::Error;
|
|
4
5
|
|
|
5
|
-
#[pyclass]
|
|
6
6
|
#[derive(Clone)]
|
|
7
|
+
#[pyclass(name = "TosError", module = "tosnativeclient")]
|
|
7
8
|
pub struct TosError {
|
|
8
9
|
#[pyo3(get)]
|
|
9
10
|
message: String,
|
|
@@ -43,6 +44,17 @@ impl TosError {
|
|
|
43
44
|
request_id,
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
|
|
48
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
49
|
+
let py = slf.py();
|
|
50
|
+
let state = [
|
|
51
|
+
slf.message.clone().into_pyobject(py)?.into_any(),
|
|
52
|
+
slf.status_code.clone().into_pyobject(py)?.into_any(),
|
|
53
|
+
slf.ec.clone().into_pyobject(py)?.into_any(),
|
|
54
|
+
slf.request_id.clone().into_pyobject(py)?.into_any(),
|
|
55
|
+
];
|
|
56
|
+
PyTuple::new(py, state)
|
|
57
|
+
}
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
create_exception!(tosnativeclient, TosException, PyException);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use pyo3::pyclass;
|
|
2
2
|
use ve_tos_rust_sdk::object::{HeadObjectOutput, ListObjectsType2Output};
|
|
3
3
|
|
|
4
|
-
#[pyclass(name = "ListObjectsResult")]
|
|
4
|
+
#[pyclass(name = "ListObjectsResult", module = "tosnativeclient")]
|
|
5
5
|
pub struct ListObjectsResult {
|
|
6
6
|
#[pyo3(get)]
|
|
7
7
|
contents: Vec<TosObject>,
|
|
@@ -33,7 +33,7 @@ impl ListObjectsResult {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
#[derive(Clone)]
|
|
36
|
-
#[pyclass(name = "TosObject")]
|
|
36
|
+
#[pyclass(name = "TosObject", module = "tosnativeclient")]
|
|
37
37
|
pub struct TosObject {
|
|
38
38
|
#[pyo3(get)]
|
|
39
39
|
pub(crate) bucket: String,
|
|
@@ -2,8 +2,10 @@ use crate::tos_client::{InnerTosClient, TokioRuntime};
|
|
|
2
2
|
use crate::tos_error::{map_error, map_tos_error};
|
|
3
3
|
use bytes::Buf;
|
|
4
4
|
use futures_util::StreamExt;
|
|
5
|
-
use pyo3::
|
|
5
|
+
use pyo3::types::PyTuple;
|
|
6
|
+
use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyRefMut, PyResult};
|
|
6
7
|
use std::collections::HashMap;
|
|
8
|
+
use std::sync::atomic::{AtomicI8, Ordering};
|
|
7
9
|
use std::sync::Arc;
|
|
8
10
|
use tokio::runtime;
|
|
9
11
|
use tokio::runtime::Runtime;
|
|
@@ -11,7 +13,7 @@ use tokio::sync::Mutex;
|
|
|
11
13
|
use ve_tos_rust_sdk::asynchronous::object::{ObjectAPI, ObjectContent};
|
|
12
14
|
use ve_tos_rust_sdk::asynchronous::tos;
|
|
13
15
|
|
|
14
|
-
#[pyclass(name = "TosRawClient")]
|
|
16
|
+
#[pyclass(name = "TosRawClient", module = "tosnativeclient")]
|
|
15
17
|
pub struct TosRawClient {
|
|
16
18
|
client: Arc<InnerTosClient>,
|
|
17
19
|
runtime: Arc<Runtime>,
|
|
@@ -158,7 +160,7 @@ impl TosRawClient {
|
|
|
158
160
|
content_range: output.content_range().to_string(),
|
|
159
161
|
hash_crc64ecma: output.hash_crc64ecma(),
|
|
160
162
|
output: Arc::new(Mutex::new(output)),
|
|
161
|
-
runtime
|
|
163
|
+
runtime,
|
|
162
164
|
}),
|
|
163
165
|
}
|
|
164
166
|
})
|
|
@@ -218,9 +220,24 @@ impl TosRawClient {
|
|
|
218
220
|
})
|
|
219
221
|
})
|
|
220
222
|
}
|
|
223
|
+
|
|
224
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
225
|
+
let py = slf.py();
|
|
226
|
+
let state = [
|
|
227
|
+
slf.region.clone().into_pyobject(py)?.into_any(),
|
|
228
|
+
slf.endpoint.clone().into_pyobject(py)?.into_any(),
|
|
229
|
+
slf.ak.clone().into_pyobject(py)?.into_any(),
|
|
230
|
+
slf.sk.clone().into_pyobject(py)?.into_any(),
|
|
231
|
+
slf.connection_timeout.into_pyobject(py)?.into_any(),
|
|
232
|
+
slf.request_timeout.into_pyobject(py)?.into_any(),
|
|
233
|
+
slf.max_connections.into_pyobject(py)?.into_any(),
|
|
234
|
+
slf.max_retry_count.into_pyobject(py)?.into_any(),
|
|
235
|
+
];
|
|
236
|
+
PyTuple::new(py, state)
|
|
237
|
+
}
|
|
221
238
|
}
|
|
222
239
|
|
|
223
|
-
#[pyclass(name = "HeadObjectInput")]
|
|
240
|
+
#[pyclass(name = "HeadObjectInput", module = "tosnativeclient")]
|
|
224
241
|
pub struct HeadObjectInput {
|
|
225
242
|
#[pyo3(get, set)]
|
|
226
243
|
pub(crate) bucket: String,
|
|
@@ -241,9 +258,18 @@ impl HeadObjectInput {
|
|
|
241
258
|
version_id: version_id.to_string(),
|
|
242
259
|
})
|
|
243
260
|
}
|
|
261
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
262
|
+
let py = slf.py();
|
|
263
|
+
let state = [
|
|
264
|
+
slf.bucket.clone().into_pyobject(py)?.into_any(),
|
|
265
|
+
slf.key.clone().into_pyobject(py)?.into_any(),
|
|
266
|
+
slf.version_id.clone().into_pyobject(py)?.into_any(),
|
|
267
|
+
];
|
|
268
|
+
PyTuple::new(py, state)
|
|
269
|
+
}
|
|
244
270
|
}
|
|
245
271
|
|
|
246
|
-
#[pyclass(name = "HeadObjectOutput")]
|
|
272
|
+
#[pyclass(name = "HeadObjectOutput", module = "tosnativeclient")]
|
|
247
273
|
pub struct HeadObjectOutput {
|
|
248
274
|
#[pyo3(get)]
|
|
249
275
|
pub(crate) request_id: String,
|
|
@@ -261,7 +287,7 @@ pub struct HeadObjectOutput {
|
|
|
261
287
|
pub(crate) hash_crc64ecma: u64,
|
|
262
288
|
}
|
|
263
289
|
|
|
264
|
-
#[pyclass(name = "DeleteObjectInput")]
|
|
290
|
+
#[pyclass(name = "DeleteObjectInput", module = "tosnativeclient")]
|
|
265
291
|
pub struct DeleteObjectInput {
|
|
266
292
|
#[pyo3(get, set)]
|
|
267
293
|
pub(crate) bucket: String,
|
|
@@ -282,9 +308,18 @@ impl DeleteObjectInput {
|
|
|
282
308
|
version_id: version_id.to_string(),
|
|
283
309
|
})
|
|
284
310
|
}
|
|
311
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
312
|
+
let py = slf.py();
|
|
313
|
+
let state = [
|
|
314
|
+
slf.bucket.clone().into_pyobject(py)?.into_any(),
|
|
315
|
+
slf.key.clone().into_pyobject(py)?.into_any(),
|
|
316
|
+
slf.version_id.clone().into_pyobject(py)?.into_any(),
|
|
317
|
+
];
|
|
318
|
+
PyTuple::new(py, state)
|
|
319
|
+
}
|
|
285
320
|
}
|
|
286
321
|
|
|
287
|
-
#[pyclass(name = "DeleteObjectOutput")]
|
|
322
|
+
#[pyclass(name = "DeleteObjectOutput", module = "tosnativeclient")]
|
|
288
323
|
pub struct DeleteObjectOutput {
|
|
289
324
|
#[pyo3(get)]
|
|
290
325
|
pub(crate) request_id: String,
|
|
@@ -297,7 +332,7 @@ pub struct DeleteObjectOutput {
|
|
|
297
332
|
#[pyo3(get)]
|
|
298
333
|
pub(crate) version_id: String,
|
|
299
334
|
}
|
|
300
|
-
#[pyclass(name = "GetObjectInput")]
|
|
335
|
+
#[pyclass(name = "GetObjectInput", module = "tosnativeclient")]
|
|
301
336
|
pub struct GetObjectInput {
|
|
302
337
|
#[pyo3(get, set)]
|
|
303
338
|
pub(crate) bucket: String,
|
|
@@ -321,9 +356,19 @@ impl GetObjectInput {
|
|
|
321
356
|
range: range.to_string(),
|
|
322
357
|
})
|
|
323
358
|
}
|
|
359
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
360
|
+
let py = slf.py();
|
|
361
|
+
let state = [
|
|
362
|
+
slf.bucket.clone().into_pyobject(py)?.into_any(),
|
|
363
|
+
slf.key.clone().into_pyobject(py)?.into_any(),
|
|
364
|
+
slf.version_id.clone().into_pyobject(py)?.into_any(),
|
|
365
|
+
slf.range.clone().into_pyobject(py)?.into_any(),
|
|
366
|
+
];
|
|
367
|
+
PyTuple::new(py, state)
|
|
368
|
+
}
|
|
324
369
|
}
|
|
325
370
|
|
|
326
|
-
#[pyclass(name = "GetObjectOutput")]
|
|
371
|
+
#[pyclass(name = "GetObjectOutput", module = "tosnativeclient")]
|
|
327
372
|
pub struct GetObjectOutput {
|
|
328
373
|
#[pyo3(get)]
|
|
329
374
|
pub(crate) request_id: String,
|
|
@@ -350,30 +395,34 @@ impl GetObjectOutput {
|
|
|
350
395
|
pub fn read_all(slf: PyRefMut<'_, Self>) -> PyResult<Option<Vec<u8>>> {
|
|
351
396
|
let runtime = slf.runtime.clone();
|
|
352
397
|
let output = slf.output.clone();
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
398
|
+
slf.py().allow_threads(|| {
|
|
399
|
+
runtime.block_on(async move {
|
|
400
|
+
match output.lock().await.read_all().await {
|
|
401
|
+
Err(ex) => Err(map_tos_error(ex)),
|
|
402
|
+
Ok(buf) => Ok(Some(buf)),
|
|
403
|
+
}
|
|
404
|
+
})
|
|
358
405
|
})
|
|
359
406
|
}
|
|
360
407
|
|
|
361
408
|
pub fn read(slf: PyRefMut<'_, Self>) -> PyResult<Option<Vec<u8>>> {
|
|
362
409
|
let runtime = slf.runtime.clone();
|
|
363
410
|
let output = slf.output.clone();
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
411
|
+
slf.py().allow_threads(|| {
|
|
412
|
+
runtime.block_on(async move {
|
|
413
|
+
match output.lock().await.next().await {
|
|
414
|
+
None => Ok(None),
|
|
415
|
+
Some(result) => match result {
|
|
416
|
+
Err(ex) => Err(map_error(ex)),
|
|
417
|
+
Ok(buf) => Ok(Some(buf.chunk().to_vec())),
|
|
418
|
+
},
|
|
419
|
+
}
|
|
420
|
+
})
|
|
372
421
|
})
|
|
373
422
|
}
|
|
374
423
|
}
|
|
375
424
|
|
|
376
|
-
#[pyclass(name = "PutObjectFromBufferInput")]
|
|
425
|
+
#[pyclass(name = "PutObjectFromBufferInput", module = "tosnativeclient")]
|
|
377
426
|
pub struct PutObjectFromBufferInput {
|
|
378
427
|
#[pyo3(get, set)]
|
|
379
428
|
pub(crate) bucket: String,
|
|
@@ -394,9 +443,18 @@ impl PutObjectFromBufferInput {
|
|
|
394
443
|
content: content.to_vec(),
|
|
395
444
|
})
|
|
396
445
|
}
|
|
446
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
447
|
+
let py = slf.py();
|
|
448
|
+
let state = [
|
|
449
|
+
slf.bucket.clone().into_pyobject(py)?.into_any(),
|
|
450
|
+
slf.key.clone().into_pyobject(py)?.into_any(),
|
|
451
|
+
slf.content.clone().into_pyobject(py)?.into_any(),
|
|
452
|
+
];
|
|
453
|
+
PyTuple::new(py, state)
|
|
454
|
+
}
|
|
397
455
|
}
|
|
398
456
|
|
|
399
|
-
#[pyclass(name = "PutObjectFromFileInput")]
|
|
457
|
+
#[pyclass(name = "PutObjectFromFileInput", module = "tosnativeclient")]
|
|
400
458
|
pub struct PutObjectFromFileInput {
|
|
401
459
|
#[pyo3(get, set)]
|
|
402
460
|
pub(crate) bucket: String,
|
|
@@ -417,9 +475,18 @@ impl PutObjectFromFileInput {
|
|
|
417
475
|
file_path: file_path.to_string(),
|
|
418
476
|
})
|
|
419
477
|
}
|
|
478
|
+
pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
|
|
479
|
+
let py = slf.py();
|
|
480
|
+
let state = [
|
|
481
|
+
slf.bucket.clone().into_pyobject(py)?.into_any(),
|
|
482
|
+
slf.key.clone().into_pyobject(py)?.into_any(),
|
|
483
|
+
slf.file_path.clone().into_pyobject(py)?.into_any(),
|
|
484
|
+
];
|
|
485
|
+
PyTuple::new(py, state)
|
|
486
|
+
}
|
|
420
487
|
}
|
|
421
488
|
|
|
422
|
-
#[pyclass(name = "PutObjectOutput")]
|
|
489
|
+
#[pyclass(name = "PutObjectOutput", module = "tosnativeclient")]
|
|
423
490
|
pub struct PutObjectOutput {
|
|
424
491
|
#[pyo3(get)]
|
|
425
492
|
pub(crate) request_id: String,
|
|
@@ -2,7 +2,8 @@ use crate::tos_client::InnerTosClient;
|
|
|
2
2
|
use crate::tos_error::map_tos_error;
|
|
3
3
|
use async_channel::{Receiver, Sender};
|
|
4
4
|
use futures_util::future::join_all;
|
|
5
|
-
use pyo3::
|
|
5
|
+
use pyo3::types::PyTuple;
|
|
6
|
+
use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyRefMut, PyResult};
|
|
6
7
|
use std::collections::HashMap;
|
|
7
8
|
use std::sync::atomic::{AtomicI8, AtomicIsize, Ordering};
|
|
8
9
|
use std::sync::Arc;
|
|
@@ -29,7 +30,7 @@ const MAX_PART_NUMBER: isize = 10000;
|
|
|
29
30
|
const OTHER_MU_KICK_OFF: i8 = 1;
|
|
30
31
|
const RELEASE_MU_KICK_OFF: i8 = 2;
|
|
31
32
|
|
|
32
|
-
#[pyclass(name = "WriteStream")]
|
|
33
|
+
#[pyclass(name = "WriteStream", module = "tosnativeclient")]
|
|
33
34
|
pub struct WriteStream {
|
|
34
35
|
object_writer: Arc<ObjectWriter>,
|
|
35
36
|
runtime: Arc<Runtime>,
|
|
@@ -93,8 +94,15 @@ impl WriteStream {
|
|
|
93
94
|
let _key = key.clone();
|
|
94
95
|
let _storage_class = storage_class.clone();
|
|
95
96
|
|
|
96
|
-
let object_writer =
|
|
97
|
-
|
|
97
|
+
let object_writer = ObjectWriter::new(
|
|
98
|
+
client,
|
|
99
|
+
runtime.clone(),
|
|
100
|
+
_bucket,
|
|
101
|
+
_key,
|
|
102
|
+
_storage_class,
|
|
103
|
+
part_size,
|
|
104
|
+
)
|
|
105
|
+
.await?;
|
|
98
106
|
Ok(Self {
|
|
99
107
|
object_writer: Arc::new(object_writer),
|
|
100
108
|
runtime,
|
|
@@ -134,6 +142,7 @@ struct ObjectWriter {
|
|
|
134
142
|
impl ObjectWriter {
|
|
135
143
|
async fn new(
|
|
136
144
|
client: Arc<InnerTosClient>,
|
|
145
|
+
runtime: Arc<Runtime>,
|
|
137
146
|
bucket: String,
|
|
138
147
|
key: String,
|
|
139
148
|
storage_class: Option<String>,
|
|
@@ -144,7 +153,15 @@ impl ObjectWriter {
|
|
|
144
153
|
key,
|
|
145
154
|
storage_class,
|
|
146
155
|
});
|
|
147
|
-
let ou = ObjectUploader::new(
|
|
156
|
+
let ou = ObjectUploader::new(
|
|
157
|
+
client,
|
|
158
|
+
runtime,
|
|
159
|
+
wp,
|
|
160
|
+
part_size,
|
|
161
|
+
0,
|
|
162
|
+
Arc::new(AtomicI8::new(0)),
|
|
163
|
+
)
|
|
164
|
+
.await?;
|
|
148
165
|
Ok(Self {
|
|
149
166
|
ctx: Mutex::new((ou, 0)),
|
|
150
167
|
closed: Arc::new(AtomicI8::new(0)),
|
|
@@ -263,6 +280,7 @@ struct WriteParam {
|
|
|
263
280
|
struct ObjectUploader {
|
|
264
281
|
next_write_offset: isize,
|
|
265
282
|
uc: Arc<UploadContext>,
|
|
283
|
+
runtime: Arc<Runtime>,
|
|
266
284
|
current: Option<Part>,
|
|
267
285
|
part_size: isize,
|
|
268
286
|
max_size: isize,
|
|
@@ -277,6 +295,7 @@ struct ObjectUploader {
|
|
|
277
295
|
impl ObjectUploader {
|
|
278
296
|
async fn new(
|
|
279
297
|
client: Arc<InnerTosClient>,
|
|
298
|
+
runtime: Arc<Runtime>,
|
|
280
299
|
wp: Arc<WriteParam>,
|
|
281
300
|
part_size: isize,
|
|
282
301
|
next_write_offset: isize,
|
|
@@ -293,6 +312,7 @@ impl ObjectUploader {
|
|
|
293
312
|
let mut ou = Self {
|
|
294
313
|
next_write_offset,
|
|
295
314
|
uc: Arc::new(UploadContext::new(created, wp, client)),
|
|
315
|
+
runtime,
|
|
296
316
|
current: None,
|
|
297
317
|
part_size,
|
|
298
318
|
max_size,
|
|
@@ -474,7 +494,7 @@ impl ObjectUploader {
|
|
|
474
494
|
let dp = self.dp.clone();
|
|
475
495
|
let st = self.st.clone();
|
|
476
496
|
let uc = self.uc.clone();
|
|
477
|
-
self.wait_dispatch = Some(
|
|
497
|
+
self.wait_dispatch = Some(self.runtime.spawn(async move {
|
|
478
498
|
loop {
|
|
479
499
|
match dp.pull().await {
|
|
480
500
|
None => return,
|
|
@@ -499,12 +519,13 @@ impl ObjectUploader {
|
|
|
499
519
|
}
|
|
500
520
|
|
|
501
521
|
async fn execute(&mut self) {
|
|
522
|
+
let runtime = self.runtime.clone();
|
|
502
523
|
let dp = self.dp.clone();
|
|
503
524
|
let st = self.st.clone();
|
|
504
525
|
let ta = self.ta.clone();
|
|
505
526
|
let uc = self.uc.clone();
|
|
506
527
|
let mu_ctx = self.mu_ctx.clone();
|
|
507
|
-
self.wait_execute = Some(
|
|
528
|
+
self.wait_execute = Some(self.runtime.spawn(async move {
|
|
508
529
|
let mut wait_async_uploads = Vec::with_capacity(16);
|
|
509
530
|
loop {
|
|
510
531
|
match st.pull().await {
|
|
@@ -518,6 +539,7 @@ impl ObjectUploader {
|
|
|
518
539
|
wait_async_uploads.push(
|
|
519
540
|
uc.clone()
|
|
520
541
|
.async_upload(
|
|
542
|
+
runtime.clone(),
|
|
521
543
|
dp.clone(),
|
|
522
544
|
st.clone(),
|
|
523
545
|
ta.clone(),
|
|
@@ -589,6 +611,7 @@ impl UploadContext {
|
|
|
589
611
|
|
|
590
612
|
async fn async_upload(
|
|
591
613
|
self: Arc<Self>,
|
|
614
|
+
runtime: Arc<Runtime>,
|
|
592
615
|
dp: Arc<Dispatcher>,
|
|
593
616
|
st: Arc<Store>,
|
|
594
617
|
ta: Arc<TokenAcquirer>,
|
|
@@ -596,7 +619,7 @@ impl UploadContext {
|
|
|
596
619
|
mut si: StoreItem,
|
|
597
620
|
) -> JoinHandle<()> {
|
|
598
621
|
let aborted = self.aborted.clone();
|
|
599
|
-
|
|
622
|
+
runtime.spawn(async move {
|
|
600
623
|
let _ = ta.acquire().await;
|
|
601
624
|
if aborted.load(Ordering::Acquire) == 1 {
|
|
602
625
|
si.release();
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|