From 225b1dcd6c62a9375657eb70ae6407acfc10dc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Satabin?= Date: Tue, 13 Oct 2026 09:49:09 +0200 Subject: [PATCH 1/2] =?UTF-8?q?Les=20erreurs=20d'acc=C3=A8s=20au=20stockag?= =?UTF-8?q?e=20sont=20remont=C3=A9es=20sous=20forme=20d'exceptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmake/modules/FindBoostLog.cmake | 9 +-- cmake/modules/dependencies.cmake | 2 - include/rok4/storage/Context.h | 18 ++++- include/rok4/thirdparty/json11.hpp | 1 + include/rok4/utils/Exception.h | 85 +++++++++++++++++++++ src/datasource/StoreDataSource.cpp | 83 ++++++++++---------- src/datasource/StoreDataSource.h | 6 ++ src/image/file/Rok4Image.cpp | 109 ++++++++++++++++----------- src/storage/FileContext.cpp | 47 ++++++------ src/storage/S3Context.cpp | 62 ++++++++------- src/storage/SwiftContext.cpp | 69 +++++++++-------- src/storage/ceph/CephPoolContext.cpp | 94 +++++++++++------------ src/style/Style.cpp | 20 +++-- src/utils/Level.cpp | 13 +++- src/utils/Pyramid.cpp | 9 ++- src/utils/TileMatrixSet.cpp | 20 +++-- 16 files changed, 392 insertions(+), 255 deletions(-) create mode 100644 include/rok4/utils/Exception.h diff --git a/cmake/modules/FindBoostLog.cmake b/cmake/modules/FindBoostLog.cmake index 6c3d16f7..aa911fd9 100644 --- a/cmake/modules/FindBoostLog.cmake +++ b/cmake/modules/FindBoostLog.cmake @@ -25,13 +25,6 @@ FIND_LIBRARY(BOOSTLOGSETUP_LIBRARY NAMES libboost_log_setup.so PATHS /usr/lib64 ) -FIND_LIBRARY(BOOSTSYSTEM_LIBRARY NAMES libboost_system.so PATHS - /usr/lib/x86_64-linux-gnu/ - /usr/local/lib - /usr/lib - /usr/lib64 - ) - FIND_LIBRARY(BOOSTFILESYSTEM_LIBRARY NAMES libboost_filesystem.so PATHS /usr/lib/x86_64-linux-gnu/ /usr/local/lib @@ -47,4 +40,4 @@ FIND_LIBRARY(BOOSTTHREAD_LIBRARY NAMES libboost_thread.so PATHS ) INCLUDE( "FindPackageHandleStandardArgs" ) -FIND_PACKAGE_HANDLE_STANDARD_ARGS( "BoostLog" DEFAULT_MSG BOOSTLOG_INCLUDE_DIR BOOSTLOG_LIBRARY BOOSTLOGSETUP_LIBRARY BOOSTTHREAD_LIBRARY BOOSTFILESYSTEM_LIBRARY BOOSTSYSTEM_LIBRARY) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( "BoostLog" DEFAULT_MSG BOOSTLOG_INCLUDE_DIR BOOSTLOG_LIBRARY BOOSTLOGSETUP_LIBRARY BOOSTTHREAD_LIBRARY BOOSTFILESYSTEM_LIBRARY) diff --git a/cmake/modules/dependencies.cmake b/cmake/modules/dependencies.cmake index 06e069d6..8f86fc7a 100644 --- a/cmake/modules/dependencies.cmake +++ b/cmake/modules/dependencies.cmake @@ -17,8 +17,6 @@ if(NOT TARGET boostlog) set_property(TARGET boostlogsetup PROPERTY IMPORTED_LOCATION ${BOOSTLOGSETUP_LIBRARY}) add_library(boostthread SHARED IMPORTED) set_property(TARGET boostthread PROPERTY IMPORTED_LOCATION ${BOOSTTHREAD_LIBRARY}) - add_library(boostsystem SHARED IMPORTED) - set_property(TARGET boostsystem PROPERTY IMPORTED_LOCATION ${BOOSTSYSTEM_LIBRARY}) add_library(boostfilesystem SHARED IMPORTED) set_property(TARGET boostfilesystem PROPERTY IMPORTED_LOCATION ${BOOSTFILESYSTEM_LIBRARY}) add_definitions(-DBOOST_LOG_DYN_LINK -DBOOST_SYSTEM_USE_UTF8) diff --git a/include/rok4/storage/Context.h b/include/rok4/storage/Context.h index a281f5ba..156123b3 100644 --- a/include/rok4/storage/Context.h +++ b/include/rok4/storage/Context.h @@ -54,6 +54,8 @@ #include #include +#include "utils/Exception.h" + #define ROK4_OBJECT_READ_ATTEMPTS "ROK4_OBJECT_READ_ATTEMPTS" #define ROK4_OBJECT_WRITE_ATTEMPTS "ROK4_OBJECT_WRITE_ATTEMPTS" #define ROK4_OBJECT_ATTEMPTS_WAIT "ROK4_OBJECT_ATTEMPTS_WAIT" @@ -234,13 +236,19 @@ class Context { * \param[in] offset À partir d'où on veut lire * \param[in] size Nombre d'octet que l'on veut lire * \param[in] name Nom de l'objet que l'on veut lire - * \return Taille effectivement lue, un nombre négatif en cas d'erreur + * \return Taille effectivement lue + * \throw NotFoundStorageException + * \throw UnreachableStorageException + * \throw ForbiddenStorageException * \~english \brief Get the data in the named object * \param[in,out] data Buffer where to store read data. Have to be initialized * \param[in] offset From where we want to read * \param[in] size Number of bytes we want to read * \param[in] name Object's name we want to read - * \return Real size of read data, negative integer if an error occured + * \return Real size of read data + * \throw NotFoundStorageException + * \throw UnreachableStorageException + * \throw ForbiddenStorageException */ virtual int read(uint8_t* data, int offset, int size, std::string name) = 0; @@ -250,10 +258,16 @@ class Context { * \param[in,out] size Taille effectivement lue, un nombre négatif en cas d'erreur * \param[in] name Nom de l'objet que l'on veut lire * \return Buffer stockant la donnée lue. + * \throw NotFoundStorageException + * \throw UnreachableStorageException + * \throw ForbiddenStorageException * \~english \brief Get the data in the named object or file * \param[in,out] size Real size of read data, negative integer if an error occured * \param[in] name Object's name we want to read * \return Buffer where read data is stored. + * \throw NotFoundStorageException + * \throw UnreachableStorageException + * \throw ForbiddenStorageException */ virtual uint8_t* read_full(int& size, std::string name) = 0; diff --git a/include/rok4/thirdparty/json11.hpp b/include/rok4/thirdparty/json11.hpp index 0c47d050..73cc4a7b 100644 --- a/include/rok4/thirdparty/json11.hpp +++ b/include/rok4/thirdparty/json11.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #ifdef _MSC_VER diff --git a/include/rok4/utils/Exception.h b/include/rok4/utils/Exception.h new file mode 100644 index 00000000..b1a3388b --- /dev/null +++ b/include/rok4/utils/Exception.h @@ -0,0 +1,85 @@ +/* + * Copyright © (2011) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +/** + * \file Exception.h + * \~french + * \brief Définition de la gestion des exceptions + * \~english + * \brief Define the exceptions handler + */ + +#pragma once + +using namespace std; + +#include + +/** + * \author Institut national de l'information géographique et forestière + * \~french + * \brief Erreur de stockage + */ +class StorageException : public exception { + private: + string message; + + public: + // Constructor accepting const char* + StorageException(const char* msg) : message(msg) {} + + // Override what() method, marked + // noexcept for modern C++ + const char* what() const noexcept { + return message.c_str(); + } +}; + +class NotFoundStorageException : public StorageException { + public: + NotFoundStorageException(std::string msg) : StorageException(msg.c_str()) {} +}; + +class UnreachableStorageException : public StorageException { + public: + UnreachableStorageException(std::string msg) : StorageException(msg.c_str()) {} +}; + +class ForbiddenStorageException : public StorageException { + public: + ForbiddenStorageException(std::string msg) : StorageException(msg.c_str()) {} +}; \ No newline at end of file diff --git a/src/datasource/StoreDataSource.cpp b/src/datasource/StoreDataSource.cpp index b9c9f19a..cf8195e8 100644 --- a/src/datasource/StoreDataSource.cpp +++ b/src/datasource/StoreDataSource.cpp @@ -93,15 +93,15 @@ const uint8_t* StoreDataSource::get_data ( size_t &tile_size ) { if (tile_indice == -1) { // On a directement la taille et l'offset data = new uint8_t[wanted_size]; - int read_size = context->read(data, offset, wanted_size, name); - if (read_size < 0) { - BOOST_LOG_TRIVIAL(error) << "Cannot read " << context->get_path(name) << " from size and offset" ; + try { + int read_size = context->read(data, offset, wanted_size, name); + tile_size = read_size; + size = tile_size; + } catch (StorageException& err) { delete[] data; data = NULL; - return NULL; + throw; } - tile_size = read_size; - size = tile_size; } else { // Nous n'avons pas les infos de taille et d'offset pour la tuile, nous allons devoir les récupérer lire // On va regarder si on n'a pas nos informations dans le cache @@ -114,29 +114,30 @@ const uint8_t* StoreDataSource::get_data ( size_t &tile_size ) { // Rien de valide dans le cache, on va lire l'index de la dalle BOOST_LOG_TRIVIAL(debug) << "pas de cache"; - std::string originalFullName (full_name); - std::string originalTrayName (context->get_tray()); + std::string original_full_name (full_name); + std::string original_tray_name (context->get_tray()); - int headerIndexSize = ROK4_IMAGE_HEADER_SIZE + 2 * 4 * tiles_number; - uint8_t* indexheader = new uint8_t[headerIndexSize]; - int realSize = context->read(indexheader, 0, headerIndexSize, name); + int header_index_size = ROK4_IMAGE_HEADER_SIZE + 2 * 4 * tiles_number; + uint8_t* index_header = new uint8_t[header_index_size]; + int real_size; - if ( realSize < 0) { - BOOST_LOG_TRIVIAL(error) << "Cannot read header and index of slab " << full_name ; - delete[] indexheader; - return NULL; + try { + real_size = context->read(index_header, 0, header_index_size, name); + } catch (StorageException& err) { + delete[] index_header; + throw; } - if ( realSize < headerIndexSize ) { + if ( real_size < header_index_size ) { // On a lu moins que ce qu'on voulait : // - soit c'est une dalle symbolique, ce qu'on va confirmer via la signature // - soit c'est une dalle cassée // Dans le cas d'un header de type objet lien, on verifie d'abord que la signature concernée est bien presente dans le header de l'objet - if ( realSize < ROK4_SYMLINK_SIGNATURE_SIZE || strncmp((char*) indexheader, ROK4_SYMLINK_SIGNATURE, ROK4_SYMLINK_SIGNATURE_SIZE) != 0 ) { + if ( real_size < ROK4_SYMLINK_SIGNATURE_SIZE || strncmp((char*) index_header, ROK4_SYMLINK_SIGNATURE, ROK4_SYMLINK_SIGNATURE_SIZE) != 0 ) { BOOST_LOG_TRIVIAL(error) << "Read data in " << full_name << " is neither an header and an index (too small) nor a link (no signature)"; - delete[] indexheader; + delete[] index_header; return NULL; } @@ -144,10 +145,10 @@ const uint8_t* StoreDataSource::get_data ( size_t &tile_size ) { BOOST_LOG_TRIVIAL(debug) << "dalle symbolique"; - char tmpName[realSize-ROK4_SYMLINK_SIGNATURE_SIZE+1]; - memcpy((uint8_t*) tmpName, indexheader+ROK4_SYMLINK_SIGNATURE_SIZE,realSize-ROK4_SYMLINK_SIGNATURE_SIZE); - tmpName[realSize-ROK4_SYMLINK_SIGNATURE_SIZE] = '\0'; - full_name = std::string (tmpName); + char tmp_name[real_size-ROK4_SYMLINK_SIGNATURE_SIZE+1]; + memcpy((uint8_t*) tmp_name, index_header+ROK4_SYMLINK_SIGNATURE_SIZE,real_size-ROK4_SYMLINK_SIGNATURE_SIZE); + tmp_name[real_size-ROK4_SYMLINK_SIGNATURE_SIZE] = '\0'; + full_name = std::string (tmp_name); name = full_name; @@ -162,7 +163,7 @@ const uint8_t* StoreDataSource::get_data ( size_t &tile_size ) { std::string tray_name = token; name.erase(0, tray_name.length() + 1); - if (originalTrayName != tray_name) { + if (original_tray_name != tray_name) { // Récupération ou ajout du nouveau contexte de stockage // On reprécise le contexte d'origine, pour utiliser le même cluster en cas S3 context = StoragePool::get_context(context->get_type(), tray_name, context); @@ -174,27 +175,27 @@ const uint8_t* StoreDataSource::get_data ( size_t &tile_size ) { } } - BOOST_LOG_TRIVIAL(debug) << "Symbolic slab detected : " << originalFullName << " -> " << full_name ; - - int realSize = context->read(indexheader, 0, headerIndexSize, name); + BOOST_LOG_TRIVIAL(debug) << "Symbolic slab detected : " << original_full_name << " -> " << full_name ; - if ( realSize < 0) { - BOOST_LOG_TRIVIAL(error) << "Cannot read header and index of slab " << full_name ; - delete[] indexheader; - return NULL; + try { + real_size = context->read(index_header, 0, header_index_size, name); + } catch (StorageException& err) { + delete[] index_header; + throw; } - if ( realSize < headerIndexSize ) { - BOOST_LOG_TRIVIAL(error) << "Read data in slab " << full_name << " (referenced by " << originalFullName << ") is too small to be an header and an index"; - delete[] indexheader; + + if ( real_size < header_index_size ) { + BOOST_LOG_TRIVIAL(error) << "Read data in slab " << full_name << " (referenced by " << original_full_name << ") is too small to be an header and an index"; + delete[] index_header; return NULL; } } - IndexCache::add_slab_infos(originalFullName, context, name, tiles_number, indexheader + ROK4_IMAGE_HEADER_SIZE, indexheader + ROK4_IMAGE_HEADER_SIZE + 4 * tiles_number); - offset = *((uint32_t*) (indexheader + ROK4_IMAGE_HEADER_SIZE + 4 * tile_indice )); - wanted_size = *((uint32_t*) (indexheader + ROK4_IMAGE_HEADER_SIZE + 4 * tiles_number + 4 * tile_indice )); - delete[] indexheader; + IndexCache::add_slab_infos(original_full_name, context, name, tiles_number, index_header + ROK4_IMAGE_HEADER_SIZE, index_header + ROK4_IMAGE_HEADER_SIZE + 4 * tiles_number); + offset = *((uint32_t*) (index_header + ROK4_IMAGE_HEADER_SIZE + 4 * tile_indice )); + wanted_size = *((uint32_t*) (index_header + ROK4_IMAGE_HEADER_SIZE + 4 * tiles_number + 4 * tile_indice )); + delete[] index_header; } if ( wanted_size == 0 ) { @@ -205,11 +206,13 @@ const uint8_t* StoreDataSource::get_data ( size_t &tile_size ) { // Lecture de la tuile data = new uint8_t[wanted_size]; - if (context->read(data, offset, wanted_size, name) < 0) { + + try { + context->read(data, offset, wanted_size, name); + } catch (StorageException& err) { delete[] data; data = NULL; - BOOST_LOG_TRIVIAL(error) << "Erreur lors de la lecture de la tuile dans l'objet " << full_name ; - return NULL; + throw; } tile_size = wanted_size; diff --git a/src/datasource/StoreDataSource.h b/src/datasource/StoreDataSource.h index 0421fc9e..54de282f 100644 --- a/src/datasource/StoreDataSource.h +++ b/src/datasource/StoreDataSource.h @@ -184,6 +184,9 @@ class StoreDataSource : public DataSource { * Dans le cas d'une lecture partielle, on lit la position de la donnée (#posoff), la taille de la donnée (#possize), et on lit la tuile. * \param[out] tile_size Taille utile dans le buffer pointé en sortie * \return Un pointeur vers la donnée + * \throw NotFoundStorageException + * \throw UnreachableStorageException + * \throw ForbiddenStorageException ** \~english * \brief Get the data from the source * \details If data is already read (#data is not null), it's returned without re-reading. @@ -193,6 +196,9 @@ class StoreDataSource : public DataSource { * For partially reading, We read tile's position (#posoff), tile's size (#possize), then we read the data. * \param[out] tile_size Real size of data in the returned pointed buffer * \return Data pointer + * \throw NotFoundStorageException + * \throw UnreachableStorageException + * \throw ForbiddenStorageException */ virtual const uint8_t* get_data ( size_t &tile_size ); diff --git a/src/image/file/Rok4Image.cpp b/src/image/file/Rok4Image.cpp index 5abd7202..e62cad3d 100644 --- a/src/image/file/Rok4Image.cpp +++ b/src/image/file/Rok4Image.cpp @@ -246,15 +246,19 @@ Rok4Image* Rok4Image::create_to_read ( std::string name, BoundingBox< double > b StoreDataSource* sds = new StoreDataSource(name, c, 0, ROK4_IMAGE_HEADER_SIZE, ""); - size_t tmpSize; - const uint8_t* hdr = sds->get_data(tmpSize); - if ( hdr == NULL ) { + size_t tmp_size; + const uint8_t* hdr; + + try { + hdr = sds->get_data(tmp_size); + } catch (StorageException err) { BOOST_LOG_TRIVIAL(error) << "Cannot read header of Rok4Image " << name ; return NULL; } - if ( tmpSize < ROK4_IMAGE_HEADER_SIZE ) { - BOOST_LOG_TRIVIAL(error) << tmpSize ; + if ( tmp_size < ROK4_IMAGE_HEADER_SIZE ) { + + BOOST_LOG_TRIVIAL(error) << tmp_size ; // S'il s'agit potentiellement d'un objet lien, on verifie d'abord que la signature de ce type d'objet est bien presente dans le header if ( strncmp((char*) hdr, ROK4_SYMLINK_SIGNATURE, ROK4_SYMLINK_SIGNATURE_SIZE) != 0 ) { @@ -263,13 +267,13 @@ Rok4Image* Rok4Image::create_to_read ( std::string name, BoundingBox< double > b return NULL; } - std::string originalName (name); - std::string originalTrayName (c->get_tray()); + std::string original_name (name); + std::string original_tray_name (c->get_tray()); - char tmpName[tmpSize-ROK4_SYMLINK_SIGNATURE_SIZE+1]; - memcpy((uint8_t*) tmpName, hdr+ROK4_SYMLINK_SIGNATURE_SIZE,tmpSize-ROK4_SYMLINK_SIGNATURE_SIZE); - tmpName[tmpSize-ROK4_SYMLINK_SIGNATURE_SIZE] = '\0'; - std::string full_name = std::string (tmpName); + char tmp_name[tmp_size-ROK4_SYMLINK_SIGNATURE_SIZE+1]; + memcpy((uint8_t*) tmp_name, hdr+ROK4_SYMLINK_SIGNATURE_SIZE,tmp_size-ROK4_SYMLINK_SIGNATURE_SIZE); + tmp_name[tmp_size-ROK4_SYMLINK_SIGNATURE_SIZE] = '\0'; + std::string full_name = std::string (tmp_name); delete sds; std::string tray_name; @@ -284,7 +288,7 @@ Rok4Image* Rok4Image::create_to_read ( std::string name, BoundingBox< double > b name.erase(0, tray_name.length() + 1); } - if (originalTrayName != tray_name) { + if (original_tray_name != tray_name) { // Récupération ou ajout du nouveau contexte de stockage c = StoragePool::get_context(c->get_type(), tray_name); // Problème lors de l'ajout ou de la récupération de ce contexte de stockage @@ -294,18 +298,19 @@ Rok4Image* Rok4Image::create_to_read ( std::string name, BoundingBox< double > b } } - BOOST_LOG_TRIVIAL(debug) << "Symbolic slab detected : " << originalName << " -> " << full_name ; + BOOST_LOG_TRIVIAL(debug) << "Symbolic slab detected : " << original_name << " -> " << full_name ; sds = new StoreDataSource(name, c, 0, ROK4_IMAGE_HEADER_SIZE, ""); - hdr = sds->get_data(tmpSize); - - if ( hdr == NULL) { + try { + hdr = sds->get_data(tmp_size); + } catch (StorageException err) { BOOST_LOG_TRIVIAL(error) << "Erreur lors de la lecture du header et de l'index dans l'objet/fichier " << name ; delete sds; return NULL; } - if ( tmpSize < ROK4_IMAGE_HEADER_SIZE ) { - BOOST_LOG_TRIVIAL(error) << "Erreur lors de la lecture : une dalle symbolique " << originalName << " référence une autre dalle symbolique " << name ; + + if ( tmp_size < ROK4_IMAGE_HEADER_SIZE ) { + BOOST_LOG_TRIVIAL(error) << "Erreur lors de la lecture : une dalle symbolique " << original_name << " référence une autre dalle symbolique " << name ; delete sds; return NULL; } @@ -531,17 +536,20 @@ boolean Rok4Image::memorize_raw_tiles ( int tilesLine ) pour faire la lecture en une seule fois. Les tuiles ne sont pas parfaitement jointes sur le stockage, car les offset sont callées sur des multiples de 16 */ - int firstTileIndex = tilesLine * tiles_widthwise; - int firstTileOffset = tiles_offsets[firstTileIndex]; + int first_tile_index = tilesLine * tiles_widthwise; + int first_tile_offset = tiles_offsets[first_tile_index]; - int lastTileIndex = firstTileIndex + tiles_widthwise - 1; - int lastTileOffset = tiles_offsets[lastTileIndex]; - int lastTileSize = tiles_sizes[lastTileIndex]; + int last_tile_index = first_tile_index + tiles_widthwise - 1; + int last_tile_offset = tiles_offsets[last_tile_index]; + int last_tile_size = tiles_sizes[last_tile_index]; - StoreDataSource* totalDS = new StoreDataSource (name.c_str(), context, firstTileOffset, lastTileOffset - firstTileOffset + lastTileSize, ""); + StoreDataSource* total_ds = new StoreDataSource (name.c_str(), context, first_tile_offset, last_tile_offset - first_tile_offset + last_tile_size, ""); size_t total_size; - const uint8_t* enc_data = totalDS->get_data(total_size); - if (enc_data == NULL) { + const uint8_t* enc_data; + + try { + enc_data = total_ds->get_data(total_size); + } catch (StorageException err) { BOOST_LOG_TRIVIAL(error) << "Cannot read tiles line data"; return false; } @@ -550,41 +558,42 @@ boolean Rok4Image::memorize_raw_tiles ( int tilesLine ) for (size_t i = 0; i < tiles_widthwise; i++) { // Pour avoir l'offset de lecture de la tuile à décoder dans le buffer total, on utilise l'offset dans la dalle, // en déduisant l'offset de la première tuile (qui correspond au 0 de notre buffer total) - RawDataSource* encDS = new RawDataSource ( enc_data + tiles_offsets[firstTileIndex + i] - firstTileOffset, tiles_sizes[firstTileIndex + i]); + RawDataSource* encoded_datasource = new RawDataSource ( enc_data + tiles_offsets[first_tile_index + i] - first_tile_offset, tiles_sizes[first_tile_index + i]); - DataSource* decDS; - size_t tmpSize; + DataSource* decoded_datasource; + size_t tmp_size; if ( compression == Compression::NONE ) { - decDS = encDS; + decoded_datasource = encoded_datasource; } else if ( compression == Compression::JPEG ) { - decDS = new DataSourceDecoder ( encDS ); + decoded_datasource = new DataSourceDecoder ( encoded_datasource ); } else if ( compression == Compression::JPEG90 ) { - decDS = new DataSourceDecoder ( encDS ); + decoded_datasource = new DataSourceDecoder ( encoded_datasource ); } else if ( compression == Compression::LZW ) { - decDS = new DataSourceDecoder ( encDS ); + decoded_datasource = new DataSourceDecoder ( encoded_datasource ); } else if ( compression == Compression::PACKBITS ) { - decDS = new DataSourceDecoder ( encDS ); + decoded_datasource = new DataSourceDecoder ( encoded_datasource ); } else if ( compression == Compression::DEFLATE || compression == Compression::PNG ) { /* Avec une telle compression dans l'en-tête TIFF, on peut avoir : * - des tuiles compressée en deflate (format "officiel") * - des tuiles en PNG, format propre à ROK4 * Pour distinguer les deux cas (pas le même décodeur), on va tester la présence d'un en-tête PNG */ - const uint8_t* header = encDS->get_data(tmpSize); + + const uint8_t* header = encoded_datasource->get_data(tmp_size); if (header == NULL) { BOOST_LOG_TRIVIAL(error) << "Cannot read header to discrimine PNG and DEFLATE" ; return false; } if (memcmp(PNG_HEADER, header, 8)) { - decDS = new DataSourceDecoder ( encDS ); + decoded_datasource = new DataSourceDecoder ( encoded_datasource ); } else { compression = Compression::PNG; - decDS = new DataSourceDecoder ( encDS ); + decoded_datasource = new DataSourceDecoder ( encoded_datasource ); } } else { @@ -592,21 +601,21 @@ boolean Rok4Image::memorize_raw_tiles ( int tilesLine ) return false; } - const uint8_t* dec_data = decDS->get_data(tmpSize); + const uint8_t* dec_data = decoded_datasource->get_data(tmp_size); - if (! dec_data || tmpSize == 0) { + if (! dec_data || tmp_size == 0) { BOOST_LOG_TRIVIAL(error) << "Unable to decompress tile " << i << " of tiles- line " << tilesLine; return false; - } else if (tmpSize != raw_tile_size) { - BOOST_LOG_TRIVIAL(warning) << "Raw tile size should have been " << raw_tile_size << ", and not " << tmpSize; + } else if (tmp_size != raw_tile_size) { + BOOST_LOG_TRIVIAL(warning) << "Raw tile size should have been " << raw_tile_size << ", and not " << tmp_size; } memcpy(memorized_tiles + i * raw_tile_size, dec_data, raw_tile_size ); - delete decDS; + delete decoded_datasource; } - delete totalDS; + delete total_ds; memorized_tiles_line = tilesLine; return true; @@ -699,9 +708,17 @@ bool Rok4Image::load_index() StoreDataSource* sds = new StoreDataSource (name, context, ROK4_IMAGE_HEADER_SIZE, 2 * 4 * tiles_count, ""); - size_t tmpSize; - uint32_t* index = (uint32_t*) sds->get_data(tmpSize); - if ( tmpSize != 2 * 4 * tiles_count ) { + size_t tmp_size; + uint32_t* index; + + try { + index = (uint32_t*) sds->get_data(tmp_size); + } catch (StorageException err) { + BOOST_LOG_TRIVIAL(error) << "Cannot read index of Rok4Image " << name ; + return false; + } + + if ( tmp_size != 2 * 4 * tiles_count ) { BOOST_LOG_TRIVIAL(error) << "Cannot read index of Rok4Image " << name ; return false; } diff --git a/src/storage/FileContext.cpp b/src/storage/FileContext.cpp index c7a3dee5..4c2e29ea 100644 --- a/src/storage/FileContext.cpp +++ b/src/storage/FileContext.cpp @@ -46,8 +46,6 @@ * \details * \li FileContext : file system use */ - -#include "storage/FileContext.h" #include #include #include @@ -55,6 +53,8 @@ using namespace std; +#include "storage/FileContext.h" + FileContext::FileContext (std::string root) : Context(), root_dir(root) {} bool FileContext::connection() { @@ -63,27 +63,23 @@ bool FileContext::connection() { } int FileContext::read(uint8_t* data, int offset, int size, std::string name) { - std::string fullName = root_dir + name; - BOOST_LOG_TRIVIAL(debug) << "File read : " << size << " bytes (from the " << offset << " one) in the file " << fullName; + std::string full_name = root_dir + name; + BOOST_LOG_TRIVIAL(debug) << "File read : " << size << " bytes (from the " << offset << " one) in the file " << full_name; // Ouverture du fichier - int fildes = open( fullName.c_str(), O_RDONLY ); + + int fildes = open( full_name.c_str(), O_RDONLY ); if ( fildes < 0 ) { - BOOST_LOG_TRIVIAL(debug) << "Can't open file " << fullName ; - return -1; + throw NotFoundStorageException("Cannot open file " + full_name); } size_t read_size = pread ( fildes, data, size, offset ); + close ( fildes ); if ( read_size != size ) { - BOOST_LOG_TRIVIAL(error) << "Impossible de lire la tuile dans le fichier " << fullName ; - if ( read_size<0 ) BOOST_LOG_TRIVIAL(error) << "Code erreur="< read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) from the S3 object " << bucket_name << "@" << ((cluster_name != "") ? cluster_name : host) << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot partially read S3 object " + full_url + ": " + std::to_string(res)); } else { sleep(waiting_time); continue; @@ -371,13 +372,16 @@ int S3Context::read(uint8_t *data, int offset, int size, std::string name) { long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); - if (http_code < 200 || http_code > 299) { + if (http_code == 404) { + throw NotFoundStorageException("Cannot found S3 object " + full_url); + } else if (http_code < 200 || http_code > 299) { BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; BOOST_LOG_TRIVIAL(error) << "Response HTTP code : " << http_code; attempt++; if (attempt > read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) from the S3 object " << bucket_name << "@" << ((cluster_name != "") ? cluster_name : host) << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot partially read S3 object " + full_url + ": " + std::to_string(http_code)); } else { sleep(waiting_time); continue; @@ -389,9 +393,8 @@ int S3Context::read(uint8_t *data, int offset, int size, std::string name) { return chunk.size; } - BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) from the S3 object " << bucket_name << "@" << ((cluster_name != "") ? cluster_name : host) << " / " << name << " after " << read_attempts << " tries" ; - - return -1; + BOOST_LOG_TRIVIAL(error) << "On ne devrait jamais passer par là (S3Context::read)" ; + throw UnreachableStorageException("Cannot partially read S3 object"); } uint8_t *S3Context::read_full(int &size, std::string name) { @@ -411,7 +414,7 @@ uint8_t *S3Context::read_full(int &size, std::string name) { CURL *curl = CurlPool::get_curl_env(); - std::string fullUrl = url + "/" + bucket_name + "/" + name; + std::string full_url = url + "/" + bucket_name + "/" + name; time_t current; @@ -426,8 +429,8 @@ uint8_t *S3Context::read_full(int &size, std::string name) { std::string content_type = "application/octet-stream"; std::string resource = "/" + bucket_name + "/" + name; - std::string stringToSign = "GET\n\n" + content_type + "\n" + std::string(gmt_time) + "\n" + resource; - std::string signature = getAuthorizationHeader(stringToSign); + std::string string_to_sign = "GET\n\n" + content_type + "\n" + std::string(gmt_time) + "\n" + resource; + std::string signature = getAuthorizationHeader(string_to_sign); // Constitution du header @@ -452,7 +455,7 @@ uint8_t *S3Context::read_full(int &size, std::string name) { list = curl_slist_append(list, auth); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); - curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); if (ssl_no_verify) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); } @@ -475,7 +478,8 @@ uint8_t *S3Context::read_full(int &size, std::string name) { attempt++; if (attempt > read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to full read S3 object" << bucket_name << "@" << ((cluster_name != "") ? cluster_name : host) << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot fully read S3 object " + full_url + ": " + std::to_string(res)); } else { sleep(waiting_time); continue; @@ -484,13 +488,16 @@ uint8_t *S3Context::read_full(int &size, std::string name) { long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); - if (http_code < 200 || http_code > 299) { + if (http_code == 404) { + throw NotFoundStorageException("Cannot found S3 object " + full_url); + } else if (http_code < 200 || http_code > 299) { BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; BOOST_LOG_TRIVIAL(error) << "Response HTTP code : " << http_code; attempt++; if (attempt > read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to full read S3 object" << bucket_name << "@" << ((cluster_name != "") ? cluster_name : host) << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot fully read S3 object " + full_url + ": " + std::to_string(res)); } else { sleep(waiting_time); continue; @@ -503,9 +510,8 @@ uint8_t *S3Context::read_full(int &size, std::string name) { return data; } - BOOST_LOG_TRIVIAL(error) << "Unable to full read S3 object" << bucket_name << "@" << ((cluster_name != "") ? cluster_name : host) << " / " << name << " after " << read_attempts << " tries" ; - - return NULL; + BOOST_LOG_TRIVIAL(error) << "On ne devrait jamais passer par là (S3Context::read_full)" ; + throw UnreachableStorageException("Cannot fully read S3 object"); } bool S3Context::write(uint8_t *data, int offset, int size, std::string name) { @@ -600,7 +606,7 @@ bool S3Context::close_to_write(std::string name) { struct curl_slist *list = NULL; CURL *curl = CurlPool::get_curl_env(); - std::string fullUrl = url + "/" + bucket_name + "/" + name; + std::string full_url = url + "/" + bucket_name + "/" + name; time_t current; @@ -615,8 +621,8 @@ bool S3Context::close_to_write(std::string name) { std::string content_type = "application/octet-stream"; std::string resource = "/" + bucket_name + "/" + name; - std::string stringToSign = "PUT\n\n" + content_type + "\n" + std::string(gmt_time) + "\n" + resource; - std::string signature = getAuthorizationHeader(stringToSign); + std::string string_to_sign = "PUT\n\n" + content_type + "\n" + std::string(gmt_time) + "\n" + resource; + std::string signature = getAuthorizationHeader(string_to_sign); // Constitution du header @@ -644,7 +650,7 @@ bool S3Context::close_to_write(std::string name) { list = curl_slist_append(list, auth); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); - curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); if (ssl_no_verify) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); } @@ -708,7 +714,7 @@ bool S3Context::exists(std::string name) { CURL *curl = CurlPool::get_curl_env(); - std::string fullUrl = url + "/" + bucket_name + "/" + name; + std::string full_url = url + "/" + bucket_name + "/" + name; time_t current; @@ -723,8 +729,8 @@ bool S3Context::exists(std::string name) { std::string content_type = "application/octet-stream"; std::string resource = "/" + bucket_name + "/" + name; - std::string stringToSign = "HEAD\n\n" + content_type + "\n" + std::string(gmt_time) + "\n" + resource; - std::string signature = getAuthorizationHeader(stringToSign); + std::string string_to_sign = "HEAD\n\n" + content_type + "\n" + std::string(gmt_time) + "\n" + resource; + std::string signature = getAuthorizationHeader(string_to_sign); // Constitution du header @@ -746,7 +752,7 @@ bool S3Context::exists(std::string name) { list = curl_slist_append(list, auth); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); - curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD"); curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); if (ssl_no_verify) { diff --git a/src/storage/SwiftContext.cpp b/src/storage/SwiftContext.cpp index 6eb7610c..37913e4e 100644 --- a/src/storage/SwiftContext.cpp +++ b/src/storage/SwiftContext.cpp @@ -294,7 +294,7 @@ int SwiftContext::read(uint8_t* data, int offset, int size, std::string name) { if (! connected) { BOOST_LOG_TRIVIAL(error) << "Impossible de lire via un contexte non connecté"; - return -1; + throw ForbiddenStorageException("Cannot read in the unconnected Swift context for container " + container_name); } BOOST_LOG_TRIVIAL(debug) << "Swift read : " << size << " bytes (from the " << offset << " one) in the object " << container_name << " / " << name; @@ -316,8 +316,8 @@ int SwiftContext::read(uint8_t* data, int offset, int size, std::string name) { // On constitue le header et le moyen de récupération des informations (avec les structures de LibcurlStruct) - std::string fullUrl; - fullUrl = public_url + "/" + container_name + "/" + name; + std::string full_url; + full_url = public_url + "/" + container_name + "/" + name; char range[50]; sprintf(range, "Range: bytes=%d-%d", offset, lastBytes); @@ -326,7 +326,7 @@ int SwiftContext::read(uint8_t* data, int offset, int size, std::string name) { list = curl_slist_append(list, range); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); - curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); if(ssl_no_verify){ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); } @@ -345,12 +345,13 @@ int SwiftContext::read(uint8_t* data, int offset, int size, std::string name) { curl_slist_free_all(list); if( CURLE_OK != res) { - BOOST_LOG_TRIVIAL(error) << "Cannot read data from Swift : " << size << " bytes (from the " << offset << " one) in the object " << name; + BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; BOOST_LOG_TRIVIAL(error) << curl_easy_strerror(res); attempt++; if (attempt > write_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) from the Swift object " << container_name << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot partially read Swift object " + full_url + ": " + std::to_string(res)); } else { sleep(waiting_time); continue; @@ -369,20 +370,23 @@ int SwiftContext::read(uint8_t* data, int offset, int size, std::string name) { token = ""; use_token_from_file = false; if (! connection()) { - BOOST_LOG_TRIVIAL(error) << "Reconnection attempt failed."; - return -1; + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) from the Swift object " << container_name << " / " << name << " because of disconnection" ; + throw ForbiddenStorageException("Cannot reconnect Swift context for container " + container_name); } BOOST_LOG_TRIVIAL(debug) << "Successfully reconnected."; continue; } - if (http_code < 200 || http_code > 299) { + if (http_code == 404) { + throw NotFoundStorageException("Cannot found Swift object " + full_url); + } else if (http_code < 200 || http_code > 299) { BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; BOOST_LOG_TRIVIAL(error) << "Response HTTP code : " << http_code; attempt++; if (attempt > read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) from the Swift object " << container_name << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot partially read Swift object " + full_url + ": " + std::to_string(http_code)); } else { sleep(waiting_time); continue; @@ -393,8 +397,8 @@ int SwiftContext::read(uint8_t* data, int offset, int size, std::string name) { return chunk.size; } - BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) from the Swift object " << container_name << " / " << name << " after " << read_attempts << " tries" ; - return -1; + BOOST_LOG_TRIVIAL(error) << "On ne devrait jamais passer par là (SwiftContext::read)" ; + throw UnreachableStorageException("Cannot partially read Swift object"); } @@ -406,7 +410,7 @@ uint8_t* SwiftContext::read_full(int& size, std::string name) { if (! connected) { BOOST_LOG_TRIVIAL(error) << "Try to read using the unconnected swift context " << container_name; - return NULL; + throw ForbiddenStorageException("Cannot read in the unconnected Swift context for container " + container_name); } int attempt = 1; @@ -424,13 +428,13 @@ uint8_t* SwiftContext::read_full(int& size, std::string name) { // On constitue le header et le moyen de récupération des informations (avec les structures de LibcurlStruct) - std::string fullUrl; - fullUrl = public_url + "/" + container_name + "/" + name; + std::string full_url; + full_url = public_url + "/" + container_name + "/" + name; list = curl_slist_append(list, token.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); - curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); if(ssl_no_verify){ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); } @@ -447,12 +451,13 @@ uint8_t* SwiftContext::read_full(int& size, std::string name) { curl_slist_free_all(list); if( CURLE_OK != res) { - BOOST_LOG_TRIVIAL(error) << "Cannot read full object from Swift : " << name; + BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; BOOST_LOG_TRIVIAL(error) << curl_easy_strerror(res); attempt++; if (attempt > write_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to full read Swift object " << container_name << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot fully read Swift object " + full_url + ": " + std::to_string(res)); } else { sleep(waiting_time); continue; @@ -471,20 +476,23 @@ uint8_t* SwiftContext::read_full(int& size, std::string name) { token = ""; use_token_from_file = false; if (! connection()) { - BOOST_LOG_TRIVIAL(error) << "Reconnection attempt failed."; - return NULL; + BOOST_LOG_TRIVIAL(error) << "Unable to full read Swift object " << container_name << " / " << name << " because of disconnection" ; + throw ForbiddenStorageException("Cannot reconnect Swift context for container " + container_name); } BOOST_LOG_TRIVIAL(debug) << "Successfully reconnected."; continue; } - if (http_code < 200 || http_code > 299) { + if (http_code == 404) { + throw NotFoundStorageException("Cannot found Swift object " + full_url); + } else if (http_code < 200 || http_code > 299) { BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; BOOST_LOG_TRIVIAL(error) << "Response HTTP code : " << http_code; attempt++; if (attempt > read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to full read Swift object " << container_name << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot fully read Swift object " + full_url + ": " + std::to_string(res)); } else { sleep(waiting_time); continue; @@ -497,9 +505,8 @@ uint8_t* SwiftContext::read_full(int& size, std::string name) { return data; } - BOOST_LOG_TRIVIAL(error) << "Unable to full read Swift object " << container_name << " / " << name << " after " << read_attempts << " tries" ; - - return NULL; + BOOST_LOG_TRIVIAL(error) << "On ne devrait jamais passer par là (SwiftContext::read_full)" ; + throw UnreachableStorageException("Cannot fully read Swift object"); } bool SwiftContext::write(uint8_t* data, int offset, int size, std::string name) { @@ -590,13 +597,13 @@ bool SwiftContext::close_to_write(std::string name) { // On constitue le header - std::string fullUrl; - fullUrl = public_url + "/" + container_name + "/" + name; + std::string full_url; + full_url = public_url + "/" + container_name + "/" + name; list = curl_slist_append(list, token.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); - curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); if(ssl_no_verify){ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); } @@ -691,13 +698,13 @@ bool SwiftContext::exists(std::string name) { struct curl_slist *list = NULL; CURL* curl = CurlPool::get_curl_env(); - std::string fullUrl; - fullUrl = public_url + "/" + container_name + "/" + name; + std::string full_url; + full_url = public_url + "/" + container_name + "/" + name; list = curl_slist_append(list, token.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); - curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str()); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD"); if(ssl_no_verify){ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); diff --git a/src/storage/ceph/CephPoolContext.cpp b/src/storage/ceph/CephPoolContext.cpp index db51304b..f3164d7b 100644 --- a/src/storage/ceph/CephPoolContext.cpp +++ b/src/storage/ceph/CephPoolContext.cpp @@ -128,45 +128,39 @@ int CephPoolContext::read(uint8_t* data, int offset, int size, std::string name) if (! connected) { BOOST_LOG_TRIVIAL(error) << "Try to read using the unconnected ceph pool context " << pool_name; - return -1; + throw ForbiddenStorageException("Cannot read in the unconnected Ceph context for pool " + pool_name); } - int readSize; + int read_size; int attempt = 1; bool error = false; while(attempt) { - readSize = rados_read(io_ctx, name.c_str(), (char*) data, size, offset); - - if (readSize < 0) { - error = true; - // Seul le timeout donne lieu à une nouvelle tentative - if (readSize == -ETIMEDOUT) { - BOOST_LOG_TRIVIAL(warning) << "Try " << attempt << " timed out" ; - } else { - BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; - BOOST_LOG_TRIVIAL(error) << "Error code: " << readSize ; - BOOST_LOG_TRIVIAL(error) << strerror(-readSize); - break; - } + read_size = rados_read(io_ctx, name.c_str(), (char*) data, size, offset); + + if (read_size == -ENOENT) { + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) in the Ceph object " << pool_name << " / " << name; + throw NotFoundStorageException("Cannot found Ceph object " + pool_name + " / " + name); + } else if (read_size == -ETIMEDOUT) { + BOOST_LOG_TRIVIAL(warning) << "Try " << attempt << " timed out" ; + } else if (read_size < 0) { + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) in the Ceph object " << pool_name << " / " << name; + throw UnreachableStorageException("Cannot partially read Ceph object " + pool_name + " / " + name + ": " + std::to_string(-read_size)); } else { - error = false; - break; + return read_size; } attempt++; if (attempt > read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) in the Ceph object " << pool_name << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot partially read Ceph object " + pool_name + " / " + name + ": " + std::to_string(-read_size)); } else { sleep(waiting_time); } } - if (error) { - BOOST_LOG_TRIVIAL(error) << "Unable to read " << size << " bytes (from the " << offset << " one) in the Ceph object " << pool_name << " / " << name << " after " << read_attempts << " tries" ; - } - - return readSize; + BOOST_LOG_TRIVIAL(error) << "On ne devrait jamais passer par là (CephContext::read)" ; + throw UnreachableStorageException("Cannot partially read Ceph object"); } @@ -178,56 +172,52 @@ uint8_t* CephPoolContext::read_full(int& size, std::string name) { if (! connected) { BOOST_LOG_TRIVIAL(error) << "Try to read using the unconnected ceph pool context " << pool_name; - return NULL; + throw ForbiddenStorageException("Cannot read in the unconnected Ceph context for pool " + pool_name); } // Récupération de la taille - uint64_t fullSize; + uint64_t full_size; time_t time; - int ret = rados_stat(io_ctx, name.c_str(), &fullSize, &time); - if (ret < 0) { - BOOST_LOG_TRIVIAL(error) << "Error reading size of ceph object " << name; - BOOST_LOG_TRIVIAL(error) << strerror(-ret); - return NULL; + int ret = rados_stat(io_ctx, name.c_str(), &full_size, &time); + + if (ret == -ENOENT) { + throw NotFoundStorageException("Cannot found Ceph object " + pool_name + " / " + name); + } else if (ret < 0) { + BOOST_LOG_TRIVIAL(error) << "Error reading size of Ceph object " << pool_name << " / " << name; + throw UnreachableStorageException("Cannot read size of Ceph object " + pool_name + " / " + name + ": " + std::to_string(-ret)); } - uint8_t* data = new uint8_t(fullSize); + uint8_t* data = new uint8_t(full_size); int attempt = 1; bool error = false; while(attempt) { - size = rados_read(io_ctx, name.c_str(), (char*) data, fullSize, 0); - - if (size < 0) { - error = true; - // Seul le timeout donne lieu à une nouvelle tentative - if (size == -ETIMEDOUT) { - BOOST_LOG_TRIVIAL(warning) << "Try " << attempt << " timed out" ; - } else { - BOOST_LOG_TRIVIAL(error) << "Try " << attempt << " failed" ; - BOOST_LOG_TRIVIAL(error) << "Error code: " << size ; - BOOST_LOG_TRIVIAL(error) << strerror(-size); - break; - } + size = rados_read(io_ctx, name.c_str(), (char*) data, full_size, 0); + + if (size == -ENOENT) { + BOOST_LOG_TRIVIAL(error) << "Unable to read full Ceph object " << pool_name << " / " << name; + throw NotFoundStorageException("Cannot found Ceph object " + pool_name + " / " + name); + } else if (size == -ETIMEDOUT) { + BOOST_LOG_TRIVIAL(warning) << "Try " << attempt << " timed out" ; + } else if (size < 0) { + BOOST_LOG_TRIVIAL(error) << "Unable to read full Ceph object " << pool_name << " / " << name; + throw UnreachableStorageException("Cannot partially read Ceph object " + pool_name + " / " + name + ": " + std::to_string(-size)); } else { - error = false; - break; + return data; } attempt++; if (attempt > read_attempts) { - break; + BOOST_LOG_TRIVIAL(error) << "Unable to read full Ceph object " << pool_name << " / " << name << " after " << read_attempts << " tries" ; + throw UnreachableStorageException("Cannot partially read Ceph object " + pool_name + " / " + name + ": " + std::to_string(-size)); } else { sleep(waiting_time); } } - if (error) { - BOOST_LOG_TRIVIAL(error) << "Unable to read full Ceph object " << pool_name << " / " << name << " after " << read_attempts << " tries" ; - } - - return data; + BOOST_LOG_TRIVIAL(error) << "On ne devrait jamais passer par là (CephContext::read_full)" ; + throw UnreachableStorageException("Cannot fully read Ceph object"); } diff --git a/src/style/Style.cpp b/src/style/Style.cpp index 3c0aee42..e0e7a463 100644 --- a/src/style/Style.cpp +++ b/src/style/Style.cpp @@ -203,7 +203,7 @@ Style::Style ( std::string path ) : Configuration(path) { } int size = -1; - uint8_t* data; + uint8_t* data = NULL; // On supprime l'extension JSON si elle est dans le chemin, on testera avec dans un deuxième temps size_t pos = fo_name.rfind ( ".json" ); @@ -211,14 +211,20 @@ Style::Style ( std::string path ) : Configuration(path) { fo_name = fo_name.erase (pos, 5); } - if (context->exists(fo_name)) { - data = context->read_full(size, fo_name); - } else if (context->exists(fo_name + ".json")) { - data = context->read_full(size, fo_name + ".json"); - } else { + try { + if (context->exists(fo_name)) { + data = context->read_full(size, fo_name); + } else if (context->exists(fo_name + ".json")) { + data = context->read_full(size, fo_name + ".json"); + } else { + error_message = "Cannot read style " + path + ", with or without extension .json"; + return; + } + } catch (StorageException err) { error_message = "Cannot read style " + path + ", with or without extension .json"; + if (data != NULL) delete[] data; return; - } + } std::string err; json11::Json doc = json11::Json::parse ( std::string((char*) data, size), err ); diff --git a/src/utils/Level.cpp b/src/utils/Level.cpp index dbed4561..712afc37 100644 --- a/src/utils/Level.cpp +++ b/src/utils/Level.cpp @@ -573,9 +573,11 @@ DataSource* Level::get_decoded_tile ( int x, int y ) { if (encoded_data == NULL) return 0; size_t size; - if (encoded_data->get_data ( size ) == NULL) { + try { + encoded_data->get_data ( size ); + } catch (StorageException& err) { delete encoded_data; - return 0; + throw; } if ( format==Rok4Format::TIFF_RAW_UINT8 || format==Rok4Format::TIFF_RAW_FLOAT32 ) @@ -601,9 +603,12 @@ DataSource* Level::get_tile (int x, int y) { if (source == NULL) return NULL; size_t size; - if (source->get_data ( size ) == NULL) { + + try { + source->get_data ( size ); + } catch (StorageException& err) { delete source; - return NULL; + throw; } if ( format == Rok4Format::TIFF_RAW_UINT8 || format == Rok4Format::TIFF_LZW_UINT8 || diff --git a/src/utils/Pyramid.cpp b/src/utils/Pyramid.cpp index b032449e..f1d88708 100644 --- a/src/utils/Pyramid.cpp +++ b/src/utils/Pyramid.cpp @@ -215,10 +215,13 @@ Pyramid::Pyramid(std::string path) : Configuration(path) { return; } - int size = -1; - uint8_t* data = context->read_full(size, fo_name); - if (size < 0) { + + int size = -1; + uint8_t* data = NULL; + try { + data = context->read_full(size, fo_name); + } catch (StorageException err) { error_message = "Cannot read descriptor " + path ; if (data != NULL) delete[] data; return; diff --git a/src/utils/TileMatrixSet.cpp b/src/utils/TileMatrixSet.cpp index 78ef2c93..24265801 100644 --- a/src/utils/TileMatrixSet.cpp +++ b/src/utils/TileMatrixSet.cpp @@ -143,7 +143,7 @@ TileMatrixSet::TileMatrixSet(std::string path) : Configuration(path) { } int size = -1; - uint8_t* data; + uint8_t* data = NULL; // On supprime l'extension JSON si elle est dans le chemin, on testera avec dans un deuxième temps size_t pos = fo_name.rfind ( ".json" ); @@ -151,14 +151,20 @@ TileMatrixSet::TileMatrixSet(std::string path) : Configuration(path) { fo_name = fo_name.erase (pos, 5); } - if (context->exists(fo_name)) { - data = context->read_full(size, fo_name); - } else if (context->exists(fo_name + ".json")) { - data = context->read_full(size, fo_name + ".json"); - } else { + try { + if (context->exists(fo_name)) { + data = context->read_full(size, fo_name); + } else if (context->exists(fo_name + ".json")) { + data = context->read_full(size, fo_name + ".json"); + } else { + error_message = "Cannot read TMS " + path + ", with or without extension .json"; + return; + } + } catch (StorageException err) { error_message = "Cannot read TMS " + path + ", with or without extension .json"; + if (data != NULL) delete[] data; return; - } + } std::string err; json11::Json doc = json11::Json::parse ( std::string((char*) data, size), err ); From 92bd169263fbc305f3b2a23905681bcc0185b062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Satabin?= Date: Tue, 13 Oct 2026 09:49:09 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Les=20erreurs=20d'acc=C3=A8s=20au=20stockag?= =?UTF-8?q?e=20sont=20remont=C3=A9es=20sous=20forme=20d'exceptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 +++++ src/utils/Level.cpp | 66 +++++++++++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a30947cb..bb8dfb7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ Le format est basé sur [Keep a Changelog](https://keepachangelog.com/) et ce pr ## [Unreleased] +### Changed +- `Storage` : les erreurs de lecture (`read` et `read_full`) sont remontées sous forme d'exception : + - `NotFoundStorageException` + - `UnreachableStorageException` + - `ForbiddenStorageException` + ### Fixed - TiffHeader : définition des en-têtes pour des images deux canaux entiers 8 bits diff --git a/src/utils/Level.cpp b/src/utils/Level.cpp index 712afc37..c9ddff59 100644 --- a/src/utils/Level.cpp +++ b/src/utils/Level.cpp @@ -516,7 +516,25 @@ Image* Level::getwindow ( unsigned int max_tile_x, unsigned int max_tile_y, Boun std::vector > T ( nby, std::vector ( nbx ) ); for ( int y = 0; y < nby; y++ ) { for ( int x = 0; x < nbx; x++ ) { - T[y][x] = get_tile ( tile_xmin + x, tile_ymin + y, left[x], top[y], right[x], bottom[y] ); + + try { + T[y][x] = get_tile ( tile_xmin + x, tile_ymin + y, left[x], top[y], right[x], bottom[y] ); + } catch (StorageException& err) { + // Nettoyage des tuiles déjà lues + + // Les lignes complètes + for ( int clean_y = 0; clean_y < y; clean_y++ ) { + for ( int clean_x = 0; clean_x < nbx; clean_x++ ) { + delete T[clean_y][clean_x]; + } + } + // La ligne en cours + for ( int clean_x = 0; clean_x < x; clean_x++ ) { + delete T[y][clean_x]; + } + throw; + } + } } @@ -630,8 +648,6 @@ Image* Level::get_tile ( int x, int y, int left, int top, int right, int bottom, if ( format==Rok4Format::TIFF_RAW_FLOAT32 || format == Rok4Format::TIFF_LZW_FLOAT32 || format == Rok4Format::TIFF_ZIP_FLOAT32 || format == Rok4Format::TIFF_PKB_FLOAT32 ) pixel_size=4; - DataSource* ds = get_decoded_tile ( x,y ); - BoundingBox bb ( tm->get_x0() + x * tm->get_tile_width() * tm->get_res() + left * tm->get_res(), tm->get_y0() - ( y+1 ) * tm->get_tile_height() * tm->get_res() + bottom * tm->get_res(), @@ -639,24 +655,34 @@ Image* Level::get_tile ( int x, int y, int left, int top, int right, int bottom, tm->get_y0() - y * tm->get_tile_height() * tm->get_res() - top * tm->get_res() ); - if (ds == 0 && null_for_nodata) { - return NULL; - } else if (ds == 0) { - // On crée une image monochrome (valeur fournie dans la pyramide) de la taille qu'aurait du avoir la tuile demandée - EmptyImage* ei = new EmptyImage( - tm->get_tile_width() - left - right, // width - tm->get_tile_height() - top - bottom, // height - channels, - nodata_value - ); - ei->set_bbox(bb); - return ei; - } else { - return new ImageDecoder ( - ds, tm->get_tile_width(), tm->get_tile_height(), channels, bb, - left, top, right, bottom, pixel_size - ); + try { + DataSource* ds = get_decoded_tile ( x,y ); + + if (ds == 0) { + throw NotFoundStorageException(""); + } else { + return new ImageDecoder ( + ds, tm->get_tile_width(), tm->get_tile_height(), channels, bb, + left, top, right, bottom, pixel_size + ); + } + + } catch (NotFoundStorageException& err) { + if (null_for_nodata) { + return NULL; + } else { + // On crée une image monochrome (valeur fournie dans la pyramide) de la taille qu'aurait du avoir la tuile demandée + EmptyImage* ei = new EmptyImage( + tm->get_tile_width() - left - right, // width + tm->get_tile_height() - top - bottom, // height + channels, + nodata_value + ); + ei->set_bbox(bb); + return ei; + } } + } TileMatrix* Level::get_tm () { return tm; }