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 mea::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
153    fn info(&self) -> ServiceInfo {
154        self.info.clone()
155    }
156
157    fn capability(&self) -> Capability {
158        self.capability
159    }
160
161    async fn create_dir(
162        &self,
163        _ctx: &OperationContext,
164        _path: &str,
165        _args: OpCreateDir,
166    ) -> Result<RpCreateDir> {
167        Err(Error::new(
168            ErrorKind::Unsupported,
169            "operation is not supported",
170        ))
171    }
172
173    async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
174        let p = build_abs_path(&self.root, path);
175
176        if p == build_abs_path(&self.root, "") {
177            Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
178        } else {
179            let bs = self.core.get(&p).await?;
180            match bs {
181                Some(bs) => Ok(RpStat::new(
182                    Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
183                )),
184                None => Err(Error::new(ErrorKind::NotFound, "kv not found in tikv")),
185            }
186        }
187    }
188    fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
189        let output: oio::StreamReader<TikvReader> = {
190            Ok(oio::StreamReader::new(TikvReader::new(
191                self.clone(),
192                path,
193                args,
194            )))
195        }?;
196
197        Ok(output)
198    }
199
200    fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
201        let output: TikvWriter = {
202            let p = build_abs_path(&self.root, path);
203            Ok(TikvWriter::new(self.core.clone(), p))
204        }?;
205
206        Ok(output)
207    }
208
209    fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
210        let output: oio::OneShotDeleter<TikvDeleter> = {
211            Ok(oio::OneShotDeleter::new(TikvDeleter::new(
212                self.core.clone(),
213                self.root.clone(),
214            )))
215        }?;
216
217        Ok(output)
218    }
219
220    fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
221        Err(Error::new(
222            ErrorKind::Unsupported,
223            "operation is not supported",
224        ))
225    }
226
227    fn copy(
228        &self,
229        _ctx: &OperationContext,
230        _from: &str,
231        _to: &str,
232        _args: OpCopy,
233        _opts: OpCopier,
234    ) -> Result<Self::Copier> {
235        Err(Error::new(
236            ErrorKind::Unsupported,
237            "operation is not supported",
238        ))
239    }
240
241    async fn rename(
242        &self,
243        _ctx: &OperationContext,
244        _from: &str,
245        _to: &str,
246        _args: OpRename,
247    ) -> Result<RpRename> {
248        Err(Error::new(
249            ErrorKind::Unsupported,
250            "operation is not supported",
251        ))
252    }
253
254    async fn presign(
255        &self,
256        _ctx: &OperationContext,
257        _path: &str,
258        _args: OpPresign,
259    ) -> Result<RpPresign> {
260        Err(Error::new(
261            ErrorKind::Unsupported,
262            "operation is not supported",
263        ))
264    }
265}