tugraph/
lib.rs

1// Copyright 2023 antkiller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! # Know issues
16//! ## Memory leak
17//! TuGraph use a smart pointer type([`GCRefCountedPtr<T>`]) and its wingman scoped reference([`ScopedRef<T>`]) to
18//! manage long-living objects which have few construct/destruct and a lot of references. If the last `GCRefCountedPtr` is
19//! destructed but with some ScopedRefs alive, the underlying T* deallocation task will be sent into [`TimedTaskScheduler`].
20//! If `TimedTaskScheduler` runs long enough, the underlying T* will be deallocated(GC). However, `TimedTaskScheduler`
21//! is a static singleton mananger, its [`destructor`] will be called when the program is going to shutdown, make some underlying T*
22//! deallocation task cancelled and leave some T* leak. It is the root cause to memory leak.
23//!
24//! What's worse, there is no api to wait until all tasks in `TimedTaskScheduler` to be finished in order to make sure all T* are deallocated.
25//!
26//! [`GCRefCountedPtr<T>`]: https://github.com/TuGraph-family/tugraph-db/blob/dc8f9b479f9ded9020536dd395903d9855191a58/src/core/managed_object.h#L152
27//! [`ScopedRef<T>`]: https://github.com/TuGraph-family/tugraph-db/blob/dc8f9b479f9ded9020536dd395903d9855191a58/src/core/managed_object.h#LL94C7-L94C16
28//! [`TimedTaskScheduler`]: https://github.com/TuGraph-family/fma-common/blob/7007036315e861e1d53174784592c337c22cbeb9/fma-common/timed_task.h#L88
29//! [`destructor`]: https://github.com/TuGraph-family/fma-common/blob/7007036315e861e1d53174784592c337c22cbeb9/fma-common/timed_task.h#L118
30
31pub mod cursor;
32pub mod db;
33pub mod field;
34pub mod index;
35mod raw;
36// pub mod rc;
37pub mod role_info;
38pub mod txn;
39pub mod types;
40pub mod user_info;
41use libtugraph_sys as ffi;
42use std::{error, fmt, result};
43
44/// `ErrorKind` ports all exceptions from lgraph_exceptions.h
45///
46/// > **Note:** Some expections not in lgraph_exceptions.h, for example std::runtime_error("custom error msg"),
47/// > are ported as Unknown
48#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
49#[non_exhaustive]
50pub enum ErrorKind {
51    // InvalidParameterError
52    InvalidParameter,
53    // OutOfRangeError
54    OutOfRange,
55    // InvalidGalaxyError
56    InvalidGalaxy,
57    // InvalidGraphDBError
58    InvalidGraphDB,
59    // InvalidTxnError
60    InvalidTxn,
61    // InvalidIteratorError
62    InvalidIterator,
63    // InvalidForkError
64    InvalidFork,
65    // TxnConflictError
66    TxnConflict,
67    // WriteNotAllowedError,
68    WriteNotAllowed,
69    // DBNotExistError
70    DBNotExist,
71    // IOError
72    IOError,
73    // UnauthorizedError
74    Unauthorized,
75    // Errors not in lgraph_exceptions.h but from C++ std::exception
76    // e.g. OutOfBound("whose msg is variant"), std::runtime_error("custom error msg")
77    Other,
78}
79
80/// `Error` contains the message from what() yield by C++  std::exception
81#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct Error {
83    message: String,
84}
85
86impl Error {
87    fn new(message: String) -> Error {
88        Error { message }
89    }
90
91    /// Converts `Error` into a `String`.
92    pub fn into_string(self) -> String {
93        self.msg().to_string()
94    }
95
96    /// Get the message contained in `Error`.
97    pub fn msg(&self) -> &str {
98        &self.message
99    }
100
101    /// Parse corresponding [`ErrorKind`] from message contained in `Error`.
102    pub fn kind(&self) -> ErrorKind {
103        match self.message.as_str() {
104            "Invalid parameter." => ErrorKind::InvalidParameter,
105            "Invalid Galaxy." => ErrorKind::InvalidGalaxy,
106            "Invalid GraphDB." => ErrorKind::InvalidGraphDB,
107            "Invalid transaction." => ErrorKind::InvalidTxn,
108            "Invalid iterator." => ErrorKind::InvalidIterator,
109            "Write transactions cannot be forked." => ErrorKind::InvalidFork,
110            "Transaction conflicts with an earlier one." => ErrorKind::TxnConflict,
111            "Access denied." => ErrorKind::WriteNotAllowed,
112            "The specified TuGraph DB does not exist." => ErrorKind::DBNotExist,
113            "IO Error." => ErrorKind::IOError,
114            "Unauthorized." => ErrorKind::Unauthorized,
115            _ => ErrorKind::Other,
116        }
117    }
118}
119
120impl AsRef<str> for Error {
121    fn as_ref(&self) -> &str {
122        &self.message
123    }
124}
125
126impl error::Error for Error {}
127
128impl fmt::Display for Error {
129    fn fmt(&self, formatter: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
130        self.message.fmt(formatter)
131    }
132}
133
134pub type Result<T> = result::Result<T, Error>;
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139
140    #[test]
141    fn test_error() {
142        [
143            ("Invalid parameter.", ErrorKind::InvalidParameter),
144            ("Invalid Galaxy.", ErrorKind::InvalidGalaxy),
145            ("Invalid GraphDB.", ErrorKind::InvalidGraphDB),
146            ("Invalid transaction.", ErrorKind::InvalidTxn),
147            ("Invalid iterator.", ErrorKind::InvalidIterator),
148            (
149                "Write transactions cannot be forked.",
150                ErrorKind::InvalidFork,
151            ),
152            (
153                "Transaction conflicts with an earlier one.",
154                ErrorKind::TxnConflict,
155            ),
156            ("Access denied.", ErrorKind::WriteNotAllowed),
157            (
158                "The specified TuGraph DB does not exist.",
159                ErrorKind::DBNotExist,
160            ),
161            ("IO Error.", ErrorKind::IOError),
162            ("Unauthorized.", ErrorKind::Unauthorized),
163            ("Other Unkown error.", ErrorKind::Other),
164        ]
165        .into_iter()
166        .for_each(|(msg, kind)| {
167            let e = Error::new(msg.into());
168            assert_eq!(e.as_ref(), msg);
169            assert_eq!(e.msg(), msg);
170            assert_eq!(e.kind(), kind);
171        })
172    }
173}