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}