diff --git a/cpp/arcticdb/python/python_module.cpp b/cpp/arcticdb/python/python_module.cpp index 762a74cb1b..8a89dce921 100644 --- a/cpp/arcticdb/python/python_module.cpp +++ b/cpp/arcticdb/python/python_module.cpp @@ -237,6 +237,9 @@ void register_error_code_ecosystem(py::module& m, py::exception(m, "DuplicateKeyException", storage_exception.ptr()); + py::register_exception(m, "PermissionException", storage_exception.ptr()); + py::register_exception(m, "SchemaException", compat_exception.ptr()); py::register_exception(m, "NormalizationException", compat_exception.ptr()); py::register_exception(m, "MissingDataException", compat_exception.ptr()); @@ -321,7 +324,7 @@ PYBIND11_MODULE(arcticdb_ext, m) { auto storage_submodule = m.def_submodule("storage", "Segment storage implementation apis"); auto no_data_found_exception = py::register_exception( storage_submodule, "NoDataFoundException", base_exception.ptr()); - arcticdb::storage::apy::register_bindings(storage_submodule, base_exception); + arcticdb::storage::apy::register_bindings(storage_submodule); arcticdb::stream::register_bindings(m); arcticdb::toolbox::apy::register_bindings(m); diff --git a/cpp/arcticdb/storage/library.hpp b/cpp/arcticdb/storage/library.hpp index 049a1209b8..a347277158 100644 --- a/cpp/arcticdb/storage/library.hpp +++ b/cpp/arcticdb/storage/library.hpp @@ -72,8 +72,9 @@ class Library { void write(Composite&& kvs) { ARCTICDB_SAMPLE(LibraryWrite, 0) - if (open_mode() < OpenMode::WRITE) - throw PermissionException(library_path_, open_mode(), "write"); + if (open_mode() < OpenMode::WRITE) { + throw LibraryPermissionException(library_path_, open_mode(), "write"); + } [[maybe_unused]] const size_t total_size = kvs.fold( [](size_t s, const KeySegmentPair& seg) { return s + seg.segment().total_segment_size(); }, @@ -86,8 +87,9 @@ class Library { void update(Composite&& kvs, storage::UpdateOpts opts) { ARCTICDB_SAMPLE(LibraryUpdate, 0) - if (open_mode() < OpenMode::WRITE) - throw PermissionException(library_path_, open_mode(), "update"); + if (open_mode() < OpenMode::WRITE) { + throw LibraryPermissionException(library_path_, open_mode(), "update"); + } [[maybe_unused]] const size_t total_size = kvs.fold( [](size_t s, const KeySegmentPair& seg) { return s + seg.segment().total_segment_size(); }, @@ -104,8 +106,9 @@ class Library { } void remove(Composite&& ks, storage::RemoveOpts opts) { - if (open_mode() < arcticdb::storage::OpenMode::DELETE) - throw PermissionException(library_path_, open_mode(), "delete"); + if (open_mode() < arcticdb::storage::OpenMode::DELETE) { + throw LibraryPermissionException(library_path_, open_mode(), "delete"); + } ARCTICDB_SAMPLE(LibraryRemove, 0) storages_->remove(std::move(ks), opts); diff --git a/cpp/arcticdb/storage/mongo/mongo_client_wrapper.hpp b/cpp/arcticdb/storage/mongo/mongo_client_wrapper.hpp index bb19822e6b..c87f989d0d 100644 --- a/cpp/arcticdb/storage/mongo/mongo_client_wrapper.hpp +++ b/cpp/arcticdb/storage/mongo/mongo_client_wrapper.hpp @@ -21,6 +21,7 @@ enum class MongoError { UnknownError = 8, UserNotFound = 11, UnAuthorized = 13, + AuthenticationFailed = 18, ExceededTimeLimit = 50, WriteConflict = 112, KeyNotFound = 211, diff --git a/cpp/arcticdb/storage/mongo/mongo_mock_client.cpp b/cpp/arcticdb/storage/mongo/mongo_mock_client.cpp index 5b40bb47f4..605991d21b 100644 --- a/cpp/arcticdb/storage/mongo/mongo_mock_client.cpp +++ b/cpp/arcticdb/storage/mongo/mongo_mock_client.cpp @@ -118,15 +118,20 @@ UpdateResult MockMongoClient::update_segment( const std::string& collection_name, storage::KeySegmentPair&& kv, bool upsert) { - auto key_found = has_key(MongoKey(database_name, collection_name, kv.variant_key())); + auto key = MongoKey(database_name, collection_name, kv.variant_key()); + + auto failure = has_failure_trigger(key, StorageOperation::WRITE); + if (failure.has_value()) { + throw_if_exception(failure.value()); + return {std::nullopt}; + } + auto key_found = has_key(key); if (!upsert && !key_found) { return {0}; // upsert is false, don't update and return 0 as modified_count } - if (!write_segment(database_name, collection_name, std::move(kv))) { - return {std::nullopt}; - } + mongo_contents.insert_or_assign(key, std::move(kv.segment())); return {key_found ? 1 : 0}; } diff --git a/cpp/arcticdb/storage/mongo/mongo_storage.cpp b/cpp/arcticdb/storage/mongo/mongo_storage.cpp index 6eecb46ea6..1ca7f808ee 100644 --- a/cpp/arcticdb/storage/mongo/mongo_storage.cpp +++ b/cpp/arcticdb/storage/mongo/mongo_storage.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include namespace arcticdb::storage::mongo { @@ -27,6 +29,40 @@ std::string MongoStorage::collection_name(KeyType k) { return (fmt::format("{}{}", prefix_, k)); } +/* + * Mongo error handling notes: + * All the exceptions thrown by mongocxx are derived from mongocxx::exception. https://mongocxx.org/api/mongocxx-3.5.1/classmongocxx_1_1exception.html + * - The exceptions that triggered by read, write, delete operations are derived from mongocxx::operation_exception. + * - mongocxx::operation_exception has an error_code which is returned by the server as documented here: https://www.mongodb.com/docs/manual/reference/error-codes/ + * - some relevant error codes returned by the server are defined in MongoError enum. + */ +void raise_mongo_exception(const mongocxx::operation_exception& e) { + auto error_code = e.code().value(); + + if (error_code == static_cast(MongoError::NoSuchKey) || error_code == static_cast(MongoError::KeyNotFound)) { + throw KeyNotFoundException(fmt::format("Key Not Found Error: MongoError#{}: {}", error_code, e.what())); + } + + if (error_code == static_cast(MongoError::UnAuthorized) || error_code == static_cast(MongoError::AuthenticationFailed)) { + raise(fmt::format("Permission error: MongoError#{}: {}", error_code, e.what())); + } + + raise(fmt::format("Unexpected Mongo Error: MongoError#{}: {} {} {}", + error_code, e.code().category().name(), e.code().message(), e.what())); +} + +bool is_expected_error_type(int error_code) { + return error_code == static_cast(MongoError::KeyNotFound) || error_code == static_cast(MongoError::NoSuchKey); +} + +void raise_if_unexpected_error(const mongocxx::operation_exception& e) { + auto error_code = e.code().value(); + + if (!is_expected_error_type(error_code)) { + raise_mongo_exception(e); + } +} + void MongoStorage::do_write(Composite&& kvs) { namespace fg = folly::gen; auto fmt_db = [](auto &&kv) { return kv.key_type(); }; @@ -37,8 +73,12 @@ void MongoStorage::do_write(Composite&& kvs) { for (auto &kv : group.values()) { auto collection = collection_name(kv.key_type()); auto key_view = kv.key_view(); - auto success = client_->write_segment(db_, collection, std::move(kv)); - util::check(success, "Mongo error while putting key {}", key_view); + try { + auto success = client_->write_segment(db_, collection, std::move(kv)); + storage::check(success, "Mongo did not acknowledge write for key {}", key_view); + } catch (const mongocxx::operation_exception& ex) { + raise_mongo_exception(ex); + } } }); } @@ -53,18 +93,27 @@ void MongoStorage::do_update(Composite&& kvs, UpdateOpts opts) { for (auto &kv : group.values()) { auto collection = collection_name(kv.key_type()); auto key_view = kv.key_view(); - auto result = client_->update_segment(db_, collection, std::move(kv), opts.upsert_); - util::check(result.modified_count.has_value(), "Mongo error while updating key {}", key_view); - util::check(opts.upsert_ || result.modified_count.value() > 0, "update called with upsert=false but key does not exist"); + try { + auto result = client_->update_segment(db_, collection, std::move(kv), opts.upsert_); + storage::check(result.modified_count.has_value(), + "Mongo did not acknowledge write for key {}", + key_view); + if (!opts.upsert_ && result.modified_count.value() == 0) { + throw storage::KeyNotFoundException( + fmt::format("update called with upsert=false but key does not exist: {}", key_view)); + } + } catch (const mongocxx::operation_exception& ex) { + raise_mongo_exception(ex); + } } }); } -void MongoStorage::do_read(Composite&& ks, const ReadVisitor& visitor, ReadKeyOpts) { +void MongoStorage::do_read(Composite&& ks, const ReadVisitor& visitor, ReadKeyOpts opts) { namespace fg = folly::gen; auto fmt_db = [](auto &&k) { return variant_key_type(k); }; ARCTICDB_SAMPLE(MongoStorageRead, 0) - std::vector failed_reads; + std::vector keys_not_found; (fg::from(ks.as_range()) | fg::move | fg::groupBy(fmt_db)).foreach([&](auto &&group) { for (auto &k : group.values()) { @@ -72,23 +121,30 @@ void MongoStorage::do_read(Composite&& ks, const ReadVisitor& visito try { auto kv = client_->read_segment(db_, collection, k); // later we should add the key to failed_reads in this case - if(!kv.has_value()) { - throw std::runtime_error(fmt::format("Missing key in mongo: {}", k)); + if (!kv.has_value() || !kv.value().has_segment()) { + keys_not_found.push_back(k); } - if (kv.value().has_segment()) + else { visitor(k, std::move(kv.value().segment())); - else - failed_reads.push_back(k); - } - catch(const std::exception &ex) { - log::storage().info("Segment read error: {}", ex.what()); - throw storage::KeyNotFoundException{Composite{VariantKey{k}}}; + } + + } catch (const mongocxx::operation_exception& ex) { + raise_if_unexpected_error(ex); + + log::storage().log( + opts.dont_warn_about_missing_key ? spdlog::level::debug : spdlog::level::warn, + "Failed to find segment for key '{}' {}: {}", + variant_key_view(k), + ex.code().value(), + ex.what()); + keys_not_found.push_back(k); } } }); - if(!failed_reads.empty()) - throw KeyNotFoundException(Composite{std::move(failed_reads)}); + if (!keys_not_found.empty()) { + throw KeyNotFoundException(Composite{std::move(keys_not_found)}); + } } bool MongoStorage::do_fast_delete() { @@ -99,29 +155,51 @@ bool MongoStorage::do_fast_delete() { return true; } -void MongoStorage::do_remove(Composite&& ks, RemoveOpts) { +void MongoStorage::do_remove(Composite&& ks, RemoveOpts opts) { namespace fg = folly::gen; auto fmt_db = [](auto &&k) { return variant_key_type(k); }; ARCTICDB_SAMPLE(MongoStorageRemove, 0) + Composite keys_not_found; (fg::from(ks.as_range()) | fg::move | fg::groupBy(fmt_db)).foreach([&](auto &&group) { for (auto &k : group.values()) { auto collection = collection_name(variant_key_type(k)); - auto result = client_->remove_keyvalue(db_, collection, k); - if (result.delete_count.has_value()) { - util::warn(result.delete_count.value() == 1, "Expect to delete a single document with key {}", - k); - } else - throw std::runtime_error(fmt::format("Mongo error deleting data for key {}", k)); + try { + auto result = client_->remove_keyvalue(db_, collection, k); + storage::check(result.delete_count.has_value(), + "Mongo did not acknowledge deletion for key {}", k); + util::warn(result.delete_count.value() == 1, + "Expected to delete a single document with key {} deleted {} documents", + k, result.delete_count.value()); + if (result.delete_count.value() == 0 && !opts.ignores_missing_key_) { + keys_not_found.push_back(k); + } + } catch (const mongocxx::operation_exception& ex) { + // mongo delete does not throw exception if key not found, it returns 0 as delete count + raise_mongo_exception(ex); + } } }); + if (!keys_not_found.empty()) { + throw KeyNotFoundException(std::move(keys_not_found)); + } } void MongoStorage::do_iterate_type(KeyType key_type, const IterateTypeVisitor& visitor, const std::string &prefix) { auto collection = collection_name(key_type); auto func = folly::Function(visitor); ARCTICDB_SAMPLE(MongoStorageItType, 0) - auto keys = client_->list_keys(db_, collection, key_type, prefix); + std::vector keys; + try { + keys = client_->list_keys(db_, collection, key_type, prefix); + } catch (const mongocxx::operation_exception& ex) { + // We don't raise when key is not found because we want to return an empty list instead of raising. + raise_if_unexpected_error(ex); + log::storage().warn("Failed to iterate key type with key '{}' {}: {}", + key_type, + ex.code().value(), + ex.what()); + } for (auto &key : keys) { func(std::move(key)); } @@ -131,11 +209,11 @@ bool MongoStorage::do_key_exists(const VariantKey& key) { auto collection = collection_name(variant_key_type(key)); try { return client_->key_exists(db_, collection, key); + } catch (const mongocxx::operation_exception& ex) { + raise_if_unexpected_error(ex); } - catch(const std::exception& ex) { - log::storage().error(fmt::format("Key exists error: {}", ex.what())); - throw; - } + + return false; } diff --git a/cpp/arcticdb/storage/python_bindings.cpp b/cpp/arcticdb/storage/python_bindings.cpp index ef1b56f4e1..62d852705d 100644 --- a/cpp/arcticdb/storage/python_bindings.cpp +++ b/cpp/arcticdb/storage/python_bindings.cpp @@ -34,7 +34,7 @@ std::shared_ptr create_library_index(const std::string &environmen return std::make_shared(EnvironmentName{environment_name}, mem_resolver); } -void register_bindings(py::module& storage, py::exception& base_exception) { +void register_bindings(py::module& storage) { storage.attr("CONFIG_LIBRARY_NAME") = py::str(arcticdb::storage::CONFIG_LIBRARY_NAME); py::enum_(storage, "KeyType") @@ -191,9 +191,6 @@ void register_bindings(py::module& storage, py::exception(storage, "DuplicateKeyException", base_exception.ptr()); - py::register_exception(storage, "PermissionException", base_exception.ptr()); } } // namespace arcticdb::storage::apy diff --git a/cpp/arcticdb/storage/python_bindings.hpp b/cpp/arcticdb/storage/python_bindings.hpp index 8f68eafad9..5bab4f25d5 100644 --- a/cpp/arcticdb/storage/python_bindings.hpp +++ b/cpp/arcticdb/storage/python_bindings.hpp @@ -18,6 +18,6 @@ namespace arcticdb::storage::apy { namespace py = pybind11; -void register_bindings(py::module &m, py::exception& base_exception); +void register_bindings(py::module &m); } // namespace arcticdb diff --git a/cpp/arcticdb/storage/storage_exceptions.hpp b/cpp/arcticdb/storage/storage_exceptions.hpp index d04afe227a..49f9e38478 100644 --- a/cpp/arcticdb/storage/storage_exceptions.hpp +++ b/cpp/arcticdb/storage/storage_exceptions.hpp @@ -13,25 +13,23 @@ namespace arcticdb::storage { -class PermissionException : public std::exception { +class LibraryPermissionException : public PermissionException { public: - PermissionException(const LibraryPath &path, OpenMode mode, std::string_view operation) : - lib_path_(path), mode_(mode), msg_(fmt::format( - "{} not permitted. lib={}, mode={}", operation, lib_path_, mode_) - ) {} - - const char *what() const noexcept override { - return msg_.data(); - } + LibraryPermissionException(const LibraryPath &path, OpenMode mode, std::string_view operation) : + PermissionException(fmt::format("{} not permitted. lib={}, mode={}", operation, path, mode)), + lib_path_(path), mode_(mode) {} const LibraryPath &library_path() const { return lib_path_; } + OpenMode mode() const { + return mode_; + } + private: LibraryPath lib_path_; OpenMode mode_; - std::string msg_; }; } \ No newline at end of file diff --git a/cpp/arcticdb/storage/test/test_storage_exceptions.cpp b/cpp/arcticdb/storage/test/test_storage_exceptions.cpp index 6bc42ebcad..8226046896 100644 --- a/cpp/arcticdb/storage/test/test_storage_exceptions.cpp +++ b/cpp/arcticdb/storage/test/test_storage_exceptions.cpp @@ -277,19 +277,19 @@ TEST(S3MockStorageTest, TestPermissionErrorException) { ASSERT_THROW({ read_in_store(*storage, failureSymbol); - }, StoragePermissionException); + }, PermissionException); failureSymbol = s3::MockS3Client::get_failure_trigger("sym2", StorageOperation::DELETE, Aws::S3::S3Errors::ACCESS_DENIED); ASSERT_THROW({ remove_in_store(*storage, {failureSymbol}); - }, StoragePermissionException); + }, PermissionException); failureSymbol = s3::MockS3Client::get_failure_trigger("sym3", StorageOperation::WRITE, Aws::S3::S3Errors::INVALID_ACCESS_KEY_ID); ASSERT_THROW({ update_in_store(*storage, failureSymbol); - }, StoragePermissionException); + }, PermissionException); } @@ -338,14 +338,14 @@ TEST(AzureMockStorageTest, TestPermissionErrorException) { Azure::Core::Http::HttpStatusCode::Forbidden); ASSERT_THROW({ update_in_store(*storage, failureSymbol); - }, StoragePermissionException); + }, PermissionException); failureSymbol = azure::MockAzureClient::get_failure_trigger("sym1", StorageOperation::DELETE, azure::AzureErrorCode_to_string(azure::AzureErrorCode::UnauthorizedBlobOverwrite), Azure::Core::Http::HttpStatusCode::Forbidden); ASSERT_THROW({ remove_in_store(*storage, {failureSymbol}); - }, StoragePermissionException); + }, PermissionException); } @@ -390,19 +390,19 @@ TEST(MongoMockStorageTest, TestPermissionErrorException) { ASSERT_THROW({ read_in_store(*storage, failureSymbol); - }, KeyNotFoundException); // should throw permission error after exception normalization + }, PermissionException); - failureSymbol = mongo::MockMongoClient::get_failure_trigger("sym2", StorageOperation::DELETE, mongo::MongoError::UserNotFound); + failureSymbol = mongo::MockMongoClient::get_failure_trigger("sym2", StorageOperation::DELETE, mongo::MongoError::AuthenticationFailed); write_in_store(*storage, failureSymbol); ASSERT_THROW({ remove_in_store(*storage, {failureSymbol}); - }, std::runtime_error); // should throw permission error after exception normalization + }, PermissionException); failureSymbol = mongo::MockMongoClient::get_failure_trigger("sym3", StorageOperation::WRITE, mongo::MongoError::UnAuthorized); ASSERT_THROW({ update_in_store(*storage, failureSymbol); - }, std::runtime_error); // should throw permission error after exception normalization + }, PermissionException); } @@ -414,7 +414,7 @@ TEST(MongoMockStorageTest, MongoUnexpectedException) { ASSERT_THROW({ read_in_store(*storage, failureSymbol); - }, std::runtime_error); // should throw MongoUnexpectedException after exception normalization + }, UnexpectedMongoException); } TEST(MongoMockStorageTest, test_remove) { @@ -432,9 +432,14 @@ TEST(MongoMockStorageTest, test_remove) { // Attempt to remove 2, 3 and 4, should succeed till 3. ASSERT_THROW( remove_in_store(*store, {"symbol_2", "symbol_3", mongo::MockMongoClient::get_failure_trigger("symbol_4", StorageOperation::DELETE, mongo::MongoError::HostUnreachable)}), - std::runtime_error); // Should throw MongoUnexpectedException after exception normalization + UnexpectedMongoException); remaining = std::set{"symbol_4"}; ASSERT_EQ(list_in_store(*store), remaining); + + ASSERT_THROW( + remove_in_store(*store, {"symbol_non_existent"}), + KeyNotFoundException); // removing non-existent keys should throw KeyNotFoundException in Mongo storage + ASSERT_EQ(list_in_store(*store), remaining); } TEST(MongoMockStorageTest, test_list) { @@ -450,7 +455,7 @@ TEST(MongoMockStorageTest, test_list) { write_in_store(*store, mongo::MockMongoClient::get_failure_trigger("symbol_99", StorageOperation::LIST, mongo::MongoError::HostNotFound)); - ASSERT_THROW(list_in_store(*store), std::runtime_error); // should throw MongoUnexpectedException after exception normalization + ASSERT_THROW(list_in_store(*store), UnexpectedMongoException); } TEST(MongoMockStorageTest, drop_collection) { diff --git a/cpp/arcticdb/util/error_code.hpp b/cpp/arcticdb/util/error_code.hpp index 625466171c..c8c0bb30e0 100644 --- a/cpp/arcticdb/util/error_code.hpp +++ b/cpp/arcticdb/util/error_code.hpp @@ -84,6 +84,8 @@ inline std::unordered_map get_error_category_names() ERROR_CODE(5006, E_S3_RETRYABLE) \ ERROR_CODE(5007, E_UNEXPECTED_AZURE_ERROR) \ ERROR_CODE(5008, E_UNEXPECTED_ROCKSDB_ERROR) \ + ERROR_CODE(5009, E_MONGO_BULK_OP_NO_REPLY) \ + ERROR_CODE(5010, E_UNEXPECTED_MONGO_ERROR) \ ERROR_CODE(6000, E_UNSORTED_DATA) \ ERROR_CODE(7000, E_INVALID_USER_ARGUMENT) \ ERROR_CODE(7001, E_INVALID_DECIMAL_STRING) \ @@ -157,11 +159,13 @@ using NormalizationException = ArcticCategorizedException; using StorageException = ArcticCategorizedException; using MissingDataException = ArcticCategorizedException; -using StoragePermissionException = ArcticSpecificException; +using PermissionException = ArcticSpecificException; using UnexpectedS3ErrorException = ArcticSpecificException; using S3RetryableException = ArcticSpecificException; using UnexpectedAzureException = ArcticSpecificException; using UnexpectedRocksDBErrorException = ArcticSpecificException; +using MongoOperationNoReplyException = ArcticSpecificException; +using UnexpectedMongoException = ArcticSpecificException; using SortingException = ArcticCategorizedException; using UnsortedDataException = ArcticSpecificException; using UserInputException = ArcticCategorizedException; @@ -198,6 +202,16 @@ template<> throw ArcticSpecificException(msg); } +template<> +[[noreturn]] inline void throw_error(const std::string& msg) { + throw ArcticSpecificException(msg); +} + +template<> +[[noreturn]] inline void throw_error(const std::string& msg) { + throw ArcticSpecificException(msg); +} + template<> [[noreturn]] inline void throw_error(const std::string& msg) { throw ArcticSpecificException(msg); diff --git a/cpp/arcticdb/version/symbol_list.cpp b/cpp/arcticdb/version/symbol_list.cpp index 826ddd5f53..6298a76c60 100644 --- a/cpp/arcticdb/version/symbol_list.cpp +++ b/cpp/arcticdb/version/symbol_list.cpp @@ -755,7 +755,7 @@ std::set SymbolList::load( } else { ARCTICDB_RUNTIME_DEBUG(log::symbol(),"Not compacting the symbol list due to lock contention"); } - } catch (const storage::PermissionException& ex) { + } catch (const storage::LibraryPermissionException& ex) { // Note: this only reflects AN's permission check and is not thrown by the Storage ARCTICDB_RUNTIME_DEBUG(log::symbol(),"Not compacting the symbol list due to lack of permission", ex.what()); } catch (const std::exception& ex) { diff --git a/docs/mkdocs/docs/error_messages.md b/docs/mkdocs/docs/error_messages.md index 517ce97aa8..65c0c82010 100644 --- a/docs/mkdocs/docs/error_messages.md +++ b/docs/mkdocs/docs/error_messages.md @@ -51,17 +51,19 @@ For legacy reasons, the terms `symbol`, `stream`, and `stream ID` are used inter ### Storage Errors -| Error Code | Cause | Resolution | -|------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 5000 | A missing key has been requested. | ArcticDB has requested a key that does not exist in storage. Ensure that you have requested a `symbol`, `snapshot`, `version`, or column statistic that exists. | -| 5001 | ArcticDB is attempting to write to an already-existing key in storage. | This error is unexpected - please ensure that no other tools are writing data the same storage location that may conflict with ArcticDB. | -| 5002 | The symbol being worked on does not exist. | ArcticDB has requested a key that does not exist in storage. Ensure that the symbol exists. | -| 5003 | The LMDB map is full. | Close and reopen your LMDB backed Arctic instance with a larger map size. For example to open `/tmp/a/b/` with a map size of 5GB, use `adb.Arctic("lmdb:///tmp/a/b?map_size=5GB")`. Also see the [LMDB documentation](http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5). | -| 5004 | Don't have permissions to carry out the operation. | Ensure that you have the permissions to perform the requested operation on the given key. | -| 5005 | An unexpected S3 error occurred. e.g. Network error, Service not available, Throttling failure etc. | Varies depending on the type of failure. | -| 5006 | An unexpected S3 error occurred which is retryable. | Varies depending on the type of failure. | -| 5007 | An unexpected Azure error occurred with a given status code and error code. | Varies depending on the type of failure. Read more on [Azure Blob Storage error code docs](https://learn.microsoft.com/en-us/rest/api/storageservices/blob-service-error-codes). | -| 5008 | An unexpected RocksDB error occurred. | Varies depending on the type of failure. Check [RocksDB statuses](https://github.com/facebook/rocksdb/blob/main/util/status.cc). | +| Error Code | Cause | Resolution | +|------------|-----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 5000 | A missing key has been requested. | ArcticDB has requested a key that does not exist in storage. Ensure that you have requested a `symbol`, `snapshot`, `version`, or column statistic that exists. | +| 5001 | ArcticDB is attempting to write to an already-existing key in storage. | This error is unexpected - please ensure that no other tools are writing data the same storage location that may conflict with ArcticDB. | +| 5002 | The symbol being worked on does not exist. | ArcticDB has requested a key that does not exist in storage. Ensure that the symbol exists. | +| 5003 | The LMDB map is full. | Close and reopen your LMDB backed Arctic instance with a larger map size. For example to open `/tmp/a/b/` with a map size of 5GB, use `adb.Arctic("lmdb:///tmp/a/b?map_size=5GB")`. Also see the [LMDB documentation](http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5). | +| 5004 | Don't have permissions to carry out the operation. | Ensure that you have the permissions to perform the requested operation on the given key. | +| 5005 | An unexpected S3 error occurred. e.g. Network error, Service not available, Throttling failure etc. | Varies depending on the type of failure. | +| 5006 | An unexpected S3 error occurred which is retryable. | Varies depending on the type of failure. | +| 5007 | An unexpected Azure error occurred with a given status code and error code. | Varies depending on the type of failure. Read more on [Azure Blob Storage error code docs](https://learn.microsoft.com/en-us/rest/api/storageservices/blob-service-error-codes). | +| 5008 | An unexpected RocksDB error occurred. | Varies depending on the type of failure. Check [RocksDB statuses](https://github.com/facebook/rocksdb/blob/main/util/status.cc). | +| 5009 | Mongo didn't acknowledge the operation. This means that the mongo apis didn't confirm whether the operation was successful. | Retry running the previous operation. | +| 5010 | An unexpected Mongo error occurred with a given error code. | Varies depending on the type of failure. Check [MongoDB error codes](https://www.mongodb.com/docs/manual/reference/error-codes/). | ### Sorting Errors @@ -166,17 +168,17 @@ ArcticDB exceptions are exposed in `arcticdb.exceptions` and sit in a hierarchy: RuntimeError └-- ArcticException |-- ArcticDbNotYetImplemented - |-- DuplicateKeyException |-- MissingDataException |-- NoDataFoundException |-- NoSuchVersionException |-- NormalizationException - |-- PermissionException |-- SchemaException |-- SortingException | └-- UnsortedDataException |-- StorageException | └-- LmdbMapFullError + | └-- PermissionException + | └-- DuplicateKeyException |-- StreamDescriptorMismatch └-- InternalException ``` diff --git a/python/arcticdb/exceptions.py b/python/arcticdb/exceptions.py index c733ddf7e7..1c42b9d5b5 100644 --- a/python/arcticdb/exceptions.py +++ b/python/arcticdb/exceptions.py @@ -6,8 +6,8 @@ As of the Change Date specified in that file, in accordance with the Business Source License, use of this software will be governed by the Apache License, version 2.0. """ from arcticdb_ext.exceptions import * -from arcticdb_ext.exceptions import ArcticException as ArcticNativeException -from arcticdb_ext.storage import DuplicateKeyException, NoDataFoundException, PermissionException +from arcticdb_ext.exceptions import ArcticException as ArcticNativeException, DuplicateKeyException, PermissionException +from arcticdb_ext.storage import NoDataFoundException from arcticdb_ext.version_store import NoSuchVersionException, StreamDescriptorMismatch