| 201 | namespace fs = std::filesystem; |
| 202 | |
| 203 | TernError SharedRocksDB::snapshot(const std::string& path) { |
| 204 | std::shared_lock<std::shared_mutex> _(_stateMutex); |
| 205 | ALWAYS_ASSERT(_db.get() != nullptr); |
| 206 | LOG_INFO(_env, "Creating snapshot in %s", path); |
| 207 | std::error_code ec; |
| 208 | if (fs::is_directory(path, ec)) { |
| 209 | LOG_INFO(_env, "Snapshot exists in %s", path); |
| 210 | return TernError::NO_ERROR; |
| 211 | } |
| 212 | if (fs::exists(path, ec)) { |
| 213 | LOG_ERROR(_env, "Provided path exists and is not an existing snapshot %s", path); |
| 214 | return TernError::CANNOT_CREATE_DB_SNAPSHOT; |
| 215 | } |
| 216 | std::string tmpPath; |
| 217 | { |
| 218 | fs::path p{path}; |
| 219 | if (!p.has_parent_path()) { |
| 220 | LOG_ERROR(_env, "Path %s does not have parent", path); |
| 221 | return TernError::CANNOT_CREATE_DB_SNAPSHOT; |
| 222 | } |
| 223 | p = p.parent_path(); |
| 224 | if (!fs::is_directory(p, ec)) { |
| 225 | LOG_ERROR(_env, "Parent path of %s is not a directory", path); |
| 226 | return TernError::CANNOT_CREATE_DB_SNAPSHOT; |
| 227 | } |
| 228 | p /= "tmp-snapshot-" + std::to_string(ternNow().ns); |
| 229 | if (fs::exists(p, ec)) { |
| 230 | LOG_ERROR(_env, "Tmp path exists %s", p.generic_string()); |
| 231 | return TernError::CANNOT_CREATE_DB_SNAPSHOT; |
| 232 | } |
| 233 | tmpPath = p.generic_string(); |
| 234 | } |
| 235 | |
| 236 | std::unique_ptr<rocksdb::Checkpoint> checkpoint; |
| 237 | auto status = rocksdb::Checkpoint::Create(_db.get(), (rocksdb::Checkpoint**)(&checkpoint)); |
| 238 | if (!status.ok()) { |
| 239 | LOG_ERROR(_env, "Failed creating checkpint (%s)", status.ToString()); |
| 240 | return TernError::CANNOT_CREATE_DB_SNAPSHOT; |
| 241 | } |
| 242 | |
| 243 | status = checkpoint->CreateCheckpoint(tmpPath); |
| 244 | if (!status.ok()) { |
| 245 | LOG_ERROR(_env, "Failed storing checkpint (%s)", status.ToString()); |
| 246 | // try to cleanup tmpPath |
| 247 | fs::remove_all(tmpPath, ec); |
| 248 | return TernError::CANNOT_CREATE_DB_SNAPSHOT; |
| 249 | } |
| 250 | fs::rename(tmpPath, path, ec); |
| 251 | if (ec) { |
| 252 | LOG_ERROR(_env, "Failed moving temp dir to requested path error (%s)", ec.message()); |
| 253 | // try to cleanup tmpPath |
| 254 | fs::remove_all(tmpPath, ec); |
| 255 | return TernError::CANNOT_CREATE_DB_SNAPSHOT; |
| 256 | } |
| 257 | return TernError::NO_ERROR; |
| 258 | } |
no test coverage detected