Skip to main content

opendal_service_tikv/
backend.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt::Debug;
19use std::sync::Arc;
20
21use asyncband::once::OnceCell;
22
23use super::TIKV_SCHEME;
24use super::config::TikvConfig;
25use super::core::*;
26use super::deleter::TikvDeleter;
27use super::reader::*;
28use super::writer::TikvWriter;
29use opendal_core::raw::oio;
30use opendal_core::raw::*;
31use opendal_core::*;
32
33/// TiKV backend builder
34#[doc = include_str!("docs.md")]
35#[derive(Debug, Default)]
36pub struct TikvBuilder {
37    pub(super) config: TikvConfig,
38}
39
40impl TikvBuilder {
41    /// Set the network address of the TiKV service.
42    pub fn endpoints(mut self, endpoints: Vec<String>) -> Self {
43        if !endpoints.is_empty() {
44            self.config.endpoints = Some(endpoints)
45        }
46        self
47    }
48
49    /// Set the insecure connection to TiKV.
50    pub fn insecure(mut self) -> Self {
51        self.config.insecure = true;
52        self
53    }
54
55    /// Set the certificate authority file path.
56    pub fn ca_path(mut self, ca_path: &str) -> Self {
57        if !ca_path.is_empty() {
58            self.config.ca_path = Some(ca_path.to_string())
59        }
60        self
61    }
62
63    /// Set the certificate file path.
64    pub fn cert_path(mut self, cert_path: &str) -> Self {
65        if !cert_path.is_empty() {
66            self.config.cert_path = Some(cert_path.to_string())
67        }
68        self
69    }
70
71    /// Set the key file path.
72    pub fn key_path(mut self, key_path: &str) -> Self {
73        if !key_path.is_empty() {
74            self.config.key_path = Some(key_path.to_string())
75        }
76        self
77    }
78}
79
80impl Builder for TikvBuilder {
81    type Config = TikvConfig;
82
83    fn build(self) -> Result<impl Service> {
84        let endpoints = self.config.endpoints.ok_or_else(|| {
85            Error::new(
86                ErrorKind::ConfigInvalid,
87                "endpoints is required but not set",
88            )
89            .with_context("service", TIKV_SCHEME)
90        })?;
91
92        if self.config.insecure
93            && (self.config.ca_path.is_some()
94                || self.config.key_path.is_some()
95                || self.config.cert_path.is_some())
96        {
97            Err(
98                Error::new(ErrorKind::ConfigInvalid, "invalid tls configuration")
99                    .with_context("service", TIKV_SCHEME)
100                    .with_context("endpoints", format!("{endpoints:?}")),
101            )?;
102        }
103
104        Ok(TikvBackend::new(TikvCore {
105            client: OnceCell::new(),
106            endpoints,
107            insecure: self.config.insecure,
108            ca_path: self.config.ca_path.clone(),
109            cert_path: self.config.cert_path.clone(),
110            key_path: self.config.key_path.clone(),
111        }))
112    }
113}
114
115/// Backend for TiKV service
116#[derive(Clone, Debug)]
117pub struct TikvBackend {
118    pub(crate) core: Arc<TikvCore>,
119    pub(crate) root: String,
120    pub(crate) info: ServiceInfo,
121    pub(crate) capability: Capability,
122}
123
124impl TikvBackend {
125    fn new(core: TikvCore) -> Self {
126        let info = ServiceInfo::new(TIKV_SCHEME, "/", "TiKV");
127        let capability = Capability {
128            read: true,
129            stat: true,
130            write: true,
131            write_can_empty: true,
132            delete: true,
133            shared: true,
134            ..Default::default()
135        };
136
137        Self {
138            core: Arc::new(core),
139            root: "/".to_string(),
140            info,
141            capability,
142        }
143    }
144}
145
146impl Service for TikvBackend {
147    type Reader = oio::StreamReader<TikvReader>;
148    type Writer = TikvWriter;
149    type Lister = ();
150    type Deleter = oio::OneShotDeleter<TikvDeleter>;
151    type Copier = ();
152    type Composer = ();
153
154    fn info(&self) -> ServiceInfo {
155        self.info.clone()
156    }
157
158    fn capability(&self) -> Capability {
159        self.capability
160    }
161
162    async fn create_dir(
163        &self,
164        _ctx: &OperationContext,
165        _path: &str,
166        _args: OpCreateDir,
167    ) -> Result<RpCreateDir> {
168        Err(Error::new(
169            ErrorKind::Unsupported,
170            "operation is not supported",
171        ))
172    }
173
174    async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
175        let p = build_abs_path(&self.root, path);
176
177        if p == build_abs_path(&self.root, "") {
178            Ok(RpStat::new(MetadataBuilder::dir().build()))
179        } else {
180            let bs = self.core.get(&p).await?;
181            match bs {
182                Some(bs) => Ok(RpStat::new({
183                    let metadata = MetadataBuilder::file(bs.len() as u64);
184                    metadata.build()
185                })),
186                None => Err(Error::new(ErrorKind::NotFound, "kv not found in tikv")),
187            }
188        }
189    }
190    fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
191        let output: oio::StreamReader<TikvReader> = {
192            Ok(oio::StreamReader::new(TikvReader::new(
193                self.clone(),
194                path,
195                args,
196            )))
197        }?;
198
199        Ok(output)
200    }
201
202    fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
203        let output: TikvWriter = {
204            let p = build_abs_path(&self.root, path);
205            Ok(TikvWriter::new(self.core.clone(), p))
206        }?;
207
208        Ok(output)
209    }
210
211    fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
212        let output: oio::OneShotDeleter<TikvDeleter> = {
213            Ok(oio::OneShotDeleter::new(TikvDeleter::new(
214                self.core.clone(),
215                self.root.clone(),
216            )))
217        }?;
218
219        Ok(output)
220    }
221
222    fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
223        Err(Error::new(
224            ErrorKind::Unsupported,
225            "operation is not supported",
226        ))
227    }
228
229    fn copy(
230        &self,
231        _ctx: &OperationContext,
232        _from: &str,
233        _to: &str,
234        _args: OpCopy,
235    ) -> Result<Self::Copier> {
236        Err(Error::new(
237            ErrorKind::Unsupported,
238            "operation is not supported",
239        ))
240    }
241
242    async fn rename(
243        &self,
244        _ctx: &OperationContext,
245        _from: &str,
246        _to: &str,
247        _args: OpRename,
248    ) -> Result<RpRename> {
249        Err(Error::new(
250            ErrorKind::Unsupported,
251            "operation is not supported",
252        ))
253    }
254
255    async fn presign(
256        &self,
257        _ctx: &OperationContext,
258        _path: &str,
259        _args: OpPresign,
260    ) -> Result<RpPresign> {
261        Err(Error::new(
262            ErrorKind::Unsupported,
263            "operation is not supported",
264        ))
265    }
266}