PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::storage::s3_storage Class Reference

#include <s3_storage.h>

Inheritance diagram for kcenon::pacs::storage::s3_storage:
Inheritance graph
Collaboration diagram for kcenon::pacs::storage::s3_storage:
Collaboration graph

Classes

class  s3_client_interface
 Abstract interface for S3 client operations. More...
 

Public Member Functions

 s3_storage (const cloud_storage_config &config)
 Construct S3 storage with configuration.
 
 ~s3_storage () override
 Destructor.
 
 s3_storage (const s3_storage &)=delete
 Non-copyable (contains mutex)
 
s3_storageoperator= (const s3_storage &)=delete
 
 s3_storage (s3_storage &&)=delete
 Non-movable (contains mutex)
 
s3_storageoperator= (s3_storage &&)=delete
 
auto store (const core::dicom_dataset &dataset) -> VoidResult override
 Store a DICOM dataset to S3.
 
auto retrieve (std::string_view sop_instance_uid) -> Result< core::dicom_dataset > override
 Retrieve a DICOM dataset by SOP Instance UID.
 
auto remove (std::string_view sop_instance_uid) -> VoidResult override
 Remove a DICOM object from S3.
 
auto exists (std::string_view sop_instance_uid) const -> bool override
 Check if a DICOM instance exists in S3.
 
auto find (const core::dicom_dataset &query) -> Result< std::vector< core::dicom_dataset > > override
 Find DICOM datasets matching query criteria.
 
auto get_statistics () const -> storage_statistics override
 Get storage statistics.
 
auto verify_integrity () -> VoidResult override
 Verify storage integrity.
 
auto store_with_progress (const core::dicom_dataset &dataset, progress_callback callback) -> VoidResult
 Store with progress tracking.
 
auto retrieve_with_progress (std::string_view sop_instance_uid, progress_callback callback) -> Result< core::dicom_dataset >
 Retrieve with progress tracking.
 
auto get_object_key (std::string_view sop_instance_uid) const -> std::string
 Get the S3 object key for a SOP Instance UID.
 
auto bucket_name () const -> const std::string &
 Get the bucket name.
 
auto rebuild_index () -> VoidResult
 Rebuild the local index from S3.
 
auto is_connected () const -> bool
 Check S3 connectivity.
 
- Public Member Functions inherited from kcenon::pacs::storage::storage_interface
virtual ~storage_interface ()=default
 Virtual destructor for proper polymorphic destruction.
 
virtual auto store_batch (const std::vector< core::dicom_dataset > &datasets) -> VoidResult
 Store multiple DICOM datasets in a single operation.
 
virtual auto retrieve_batch (const std::vector< std::string > &sop_instance_uids) -> Result< std::vector< core::dicom_dataset > >
 Retrieve multiple DICOM datasets by their SOP Instance UIDs.
 

Private Member Functions

auto build_object_key (std::string_view study_uid, std::string_view series_uid, std::string_view sop_uid) const -> std::string
 Build S3 object key for a dataset.
 
auto upload_multipart (const std::string &key, const std::vector< std::uint8_t > &data, progress_callback callback) -> VoidResult
 Execute multipart upload for large files.
 

Static Private Member Functions

static auto sanitize_uid (std::string_view uid) -> std::string
 Sanitize UID for use in S3 object key.
 
static auto matches_query (const core::dicom_dataset &dataset, const core::dicom_dataset &query) -> bool
 Check if dataset matches query criteria.
 

Private Attributes

cloud_storage_config config_
 Storage configuration.
 
std::unique_ptr< s3_client_interfaceclient_
 S3 client (mock for testing, AWS SDK for production)
 
std::unordered_map< std::string, s3_object_infoindex_
 Mapping from SOP Instance UID to S3 object info.
 
std::shared_mutex mutex_
 Mutex for thread-safe access.
 

Additional Inherited Members

- Protected Member Functions inherited from kcenon::pacs::storage::storage_interface
 storage_interface ()=default
 Protected default constructor for derived classes.
 
 storage_interface (const storage_interface &)=delete
 Non-copyable.
 
storage_interfaceoperator= (const storage_interface &)=delete
 
 storage_interface (storage_interface &&)=default
 Movable.
 
storage_interfaceoperator= (storage_interface &&)=default
 

Detailed Description

Definition at line 163 of file s3_storage.h.

Constructor & Destructor Documentation

◆ s3_storage() [1/3]

kcenon::pacs::storage::s3_storage::s3_storage ( const cloud_storage_config & config)
explicit

Construct S3 storage with configuration.

Parameters
configCloud storage configuration
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 505 of file s3_storage.cpp.

506 : config_(config),
507#if defined(PACS_WITH_AWS_SDK) && !defined(PACS_USE_MOCK_S3)
508 client_(std::make_unique<aws_s3_client>(config))
509#else
510 client_(std::make_unique<mock_s3_client>(config))
511#endif
512{
513}
cloud_storage_config config_
Storage configuration.
Definition s3_storage.h:389
std::unique_ptr< s3_client_interface > client_
S3 client (mock for testing, AWS SDK for production)
Definition s3_storage.h:392

◆ ~s3_storage()

kcenon::pacs::storage::s3_storage::~s3_storage ( )
overridedefault

◆ s3_storage() [2/3]

kcenon::pacs::storage::s3_storage::s3_storage ( const s3_storage & )
delete

Non-copyable (contains mutex)

◆ s3_storage() [3/3]

kcenon::pacs::storage::s3_storage::s3_storage ( s3_storage && )
delete

Non-movable (contains mutex)

Member Function Documentation

◆ bucket_name()

auto kcenon::pacs::storage::s3_storage::bucket_name ( ) const -> const std::string &
nodiscard

Get the bucket name.

Returns
The configured bucket name
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 768 of file s3_storage.cpp.

768 {
769 return config_.bucket_name;
770}
std::string bucket_name
S3 bucket name for storing DICOM files.
Definition s3_storage.h:43

References kcenon::pacs::storage::cloud_storage_config::bucket_name, and config_.

◆ build_object_key()

auto kcenon::pacs::storage::s3_storage::build_object_key ( std::string_view study_uid,
std::string_view series_uid,
std::string_view sop_uid ) const -> std::string
nodiscardprivate

Build S3 object key for a dataset.

Parameters
study_uidStudy Instance UID
series_uidSeries Instance UID
sop_uidSOP Instance UID
Returns
The constructed object key
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 818 of file s3_storage.cpp.

821 {
822 std::ostringstream oss;
823 oss << sanitize_uid(study_uid) << "/" << sanitize_uid(series_uid) << "/"
824 << sanitize_uid(sop_uid) << ".dcm";
825 return oss.str();
826}
static auto sanitize_uid(std::string_view uid) -> std::string
Sanitize UID for use in S3 object key.

◆ exists()

auto kcenon::pacs::storage::s3_storage::exists ( std::string_view sop_instance_uid) const -> bool
nodiscardoverridevirtual

Check if a DICOM instance exists in S3.

Uses S3 HeadObject to check existence without downloading.

Parameters
sop_instance_uidThe unique identifier to check
Returns
true if the object exists, false otherwise

Implements kcenon::pacs::storage::storage_interface.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 659 of file s3_storage.cpp.

659 {
660 std::shared_lock lock(mutex_);
661 return index_.contains(std::string{sop_instance_uid});
662}
std::shared_mutex mutex_
Mutex for thread-safe access.
Definition s3_storage.h:398
std::unordered_map< std::string, s3_object_info > index_
Mapping from SOP Instance UID to S3 object info.
Definition s3_storage.h:395
constexpr dicom_tag sop_instance_uid
SOP Instance UID.

◆ find()

auto kcenon::pacs::storage::s3_storage::find ( const core::dicom_dataset & query) -> Result<std::vector<core::dicom_dataset>>
nodiscardoverridevirtual

Find DICOM datasets matching query criteria.

This operation requires scanning the local index. For large buckets, consider using the index_database instead.

Parameters
queryThe query dataset containing search criteria
Returns
Result containing matching datasets or error information
Note
This operation can be slow for large storage

Implements kcenon::pacs::storage::storage_interface.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 664 of file s3_storage.cpp.

665 {
666 std::vector<core::dicom_dataset> results;
667
668 std::vector<std::string> keys_to_retrieve;
669 {
670 std::shared_lock lock(mutex_);
671 keys_to_retrieve.reserve(index_.size());
672 for (const auto &[uid, info] : index_) {
673 keys_to_retrieve.push_back(info.key);
674 }
675 }
676
677 for (const auto &key : keys_to_retrieve) {
678 auto download_result = client_->get_object(key);
679 if (download_result.is_err()) {
680 continue; // Skip objects that can't be downloaded
681 }
682
683 auto parse_result = core::dicom_file::from_bytes(download_result.value());
684 if (parse_result.is_err()) {
685 continue; // Skip invalid DICOM files
686 }
687
688 const auto &dataset = parse_result.value().dataset();
689 if (matches_query(dataset, query)) {
690 results.push_back(dataset);
691 }
692 }
693
694 return results;
695}
static auto from_bytes(std::span< const uint8_t > data) -> kcenon::pacs::Result< dicom_file >
Parse a DICOM file from raw bytes.
static auto matches_query(const core::dicom_dataset &dataset, const core::dicom_dataset &query) -> bool
Check if dataset matches query criteria.
std::string_view uid

References kcenon::pacs::core::dicom_file::from_bytes(), and uid.

Here is the call graph for this function:

◆ get_object_key()

auto kcenon::pacs::storage::s3_storage::get_object_key ( std::string_view sop_instance_uid) const -> std::string
nodiscard

Get the S3 object key for a SOP Instance UID.

Parameters
sop_instance_uidThe SOP Instance UID
Returns
The S3 object key (may be empty if not found)
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 758 of file s3_storage.cpp.

759 {
760 std::shared_lock lock(mutex_);
761 auto it = index_.find(std::string{sop_instance_uid});
762 if (it != index_.end()) {
763 return it->second.key;
764 }
765 return {};
766}

◆ get_statistics()

auto kcenon::pacs::storage::s3_storage::get_statistics ( ) const -> storage_statistics
nodiscardoverridevirtual

Get storage statistics.

Returns
Storage statistics structure

Implements kcenon::pacs::storage::storage_interface.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 697 of file s3_storage.cpp.

697 {
698 storage_statistics stats;
699
700 std::set<std::string> studies;
701 std::set<std::string> series;
702 std::set<std::string> patients;
703
704 {
705 std::shared_lock lock(mutex_);
706 stats.total_instances = index_.size();
707
708 for (const auto &[uid, info] : index_) {
709 stats.total_bytes += info.size_bytes;
710
711 if (!info.study_instance_uid.empty()) {
712 studies.insert(info.study_instance_uid);
713 }
714 if (!info.series_instance_uid.empty()) {
715 series.insert(info.series_instance_uid);
716 }
717 }
718 }
719
720 stats.studies_count = studies.size();
721 stats.series_count = series.size();
722 // Note: patient_count requires downloading datasets to extract PatientID
723
724 return stats;
725}

References index_, mutex_, and uid.

◆ is_connected()

auto kcenon::pacs::storage::s3_storage::is_connected ( ) const -> bool
nodiscard

Check S3 connectivity.

Returns
true if S3 is reachable, false otherwise
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 810 of file s3_storage.cpp.

810 {
811 return client_ && client_->is_connected();
812}

References client_.

◆ matches_query()

auto kcenon::pacs::storage::s3_storage::matches_query ( const core::dicom_dataset & dataset,
const core::dicom_dataset & query ) -> bool
staticnodiscardprivate

Check if dataset matches query criteria.

Parameters
datasetThe dataset to check
queryThe query criteria
Returns
true if dataset matches query
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 851 of file s3_storage.cpp.

852 {
853 // If query is empty, match all
854 if (query.empty()) {
855 return true;
856 }
857
858 // Check each query element
859 for (const auto &[tag, element] : query) {
860 auto query_value = element.as_string().unwrap_or("");
861 if (query_value.empty()) {
862 continue; // Empty value acts as wildcard
863 }
864
865 auto dataset_value = dataset.get_string(tag);
866
867 // Support basic wildcard matching (* and ?)
868 if (query_value.find('*') != std::string::npos ||
869 query_value.find('?') != std::string::npos) {
870 // Simple pattern matching
871 if (query_value.front() == '*' && query_value.back() == '*') {
872 // Contains
873 auto inner = query_value.substr(1, query_value.length() - 2);
874 if (dataset_value.find(inner) == std::string::npos) {
875 return false;
876 }
877 } else if (query_value.front() == '*') {
878 // Ends with
879 auto suffix = query_value.substr(1);
880 if (dataset_value.length() < suffix.length() ||
881 dataset_value.substr(dataset_value.length() - suffix.length()) !=
882 suffix) {
883 return false;
884 }
885 } else if (query_value.back() == '*') {
886 // Starts with
887 auto prefix = query_value.substr(0, query_value.length() - 1);
888 if (dataset_value.substr(0, prefix.length()) != prefix) {
889 return false;
890 }
891 }
892 } else {
893 // Exact match
894 if (dataset_value != query_value) {
895 return false;
896 }
897 }
898 }
899
900 return true;
901}
const atna_coded_value query
Query (110112)

◆ operator=() [1/2]

s3_storage & kcenon::pacs::storage::s3_storage::operator= ( const s3_storage & )
delete

◆ operator=() [2/2]

s3_storage & kcenon::pacs::storage::s3_storage::operator= ( s3_storage && )
delete

◆ rebuild_index()

auto kcenon::pacs::storage::s3_storage::rebuild_index ( ) -> VoidResult
nodiscard

Rebuild the local index from S3.

Lists all objects in the bucket and rebuilds the SOP UID mapping.

Returns
VoidResult Success or error information
Note
This operation can be slow for buckets with many objects
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 772 of file s3_storage.cpp.

772 {
773 std::unique_lock lock(mutex_);
774 index_.clear();
775
776 // List all objects from S3
777 auto keys = client_->list_objects();
778
779 for (const auto &key : keys) {
780 // Download and parse each object to rebuild index
781 auto download_result = client_->get_object(key);
782 if (download_result.is_err()) {
783 continue;
784 }
785
786 auto parse_result = core::dicom_file::from_bytes(download_result.value());
787 if (parse_result.is_err()) {
788 continue;
789 }
790
791 const auto &dataset = parse_result.value().dataset();
792 auto sop_uid = dataset.get_string(core::tags::sop_instance_uid);
793 auto study_uid = dataset.get_string(core::tags::study_instance_uid);
794 auto series_uid = dataset.get_string(core::tags::series_instance_uid);
795
796 if (!sop_uid.empty()) {
797 s3_object_info info;
798 info.key = key;
799 info.sop_instance_uid = sop_uid;
800 info.study_instance_uid = study_uid;
801 info.series_instance_uid = series_uid;
802 info.size_bytes = client_->get_object_size(key);
803 index_[sop_uid] = std::move(info);
804 }
805 }
806
807 return ok();
808}
constexpr dicom_tag study_instance_uid
Study Instance UID.
constexpr dicom_tag series_instance_uid
Series Instance UID.

References kcenon::pacs::core::dicom_file::from_bytes(), kcenon::pacs::core::tags::series_instance_uid, kcenon::pacs::core::tags::sop_instance_uid, and kcenon::pacs::core::tags::study_instance_uid.

Here is the call graph for this function:

◆ remove()

auto kcenon::pacs::storage::s3_storage::remove ( std::string_view sop_instance_uid) -> VoidResult
nodiscardoverridevirtual

Remove a DICOM object from S3.

Parameters
sop_instance_uidThe unique identifier for the instance to remove
Returns
VoidResult Success or error information

Implements kcenon::pacs::storage::storage_interface.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 638 of file s3_storage.cpp.

638 {
639 std::string object_key;
640
641 {
642 std::unique_lock lock(mutex_);
643 auto it = index_.find(std::string{sop_instance_uid});
644 if (it == index_.end()) {
645 // Not found is not an error for remove
646 return ok();
647 }
648 object_key = it->second.key;
649 index_.erase(it);
650 }
651
652 // Delete from S3
653 auto delete_result = client_->delete_object(object_key);
654 // Ignore delete errors - object might have been deleted externally
655
656 return ok();
657}

◆ retrieve()

auto kcenon::pacs::storage::s3_storage::retrieve ( std::string_view sop_instance_uid) -> Result<core::dicom_dataset>
nodiscardoverridevirtual

Retrieve a DICOM dataset by SOP Instance UID.

Downloads the object from S3 and deserializes to dicom_dataset.

Parameters
sop_instance_uidThe unique identifier for the instance
Returns
Result containing the dataset or error information

Implements kcenon::pacs::storage::storage_interface.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 591 of file s3_storage.cpp.

592 {
593 return retrieve_with_progress(sop_instance_uid, nullptr);
594}
auto retrieve_with_progress(std::string_view sop_instance_uid, progress_callback callback) -> Result< core::dicom_dataset >
Retrieve with progress tracking.

◆ retrieve_with_progress()

auto kcenon::pacs::storage::s3_storage::retrieve_with_progress ( std::string_view sop_instance_uid,
progress_callback callback ) -> Result<core::dicom_dataset>
nodiscard

Retrieve with progress tracking.

Parameters
sop_instance_uidThe SOP Instance UID
callbackProgress callback function
Returns
Result containing the dataset or error information
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 596 of file s3_storage.cpp.

598 {
599 std::string object_key;
600
601 {
602 std::shared_lock lock(mutex_);
603 auto it = index_.find(std::string{sop_instance_uid});
604 if (it == index_.end()) {
605 return make_error<core::dicom_dataset>(
606 kObjectNotFound,
607 "Instance not found: " + std::string{sop_instance_uid}, "s3_storage");
608 }
609 object_key = it->second.key;
610 }
611
612 // Download from S3
613 auto download_result = client_->get_object(object_key);
614 if (download_result.is_err()) {
615 return make_error<core::dicom_dataset>(
616 kDownloadError, "Failed to download from S3", "s3_storage");
617 }
618
619 const auto &data = download_result.value();
620
621 // Report progress (download complete)
622 if (callback) {
623 callback(data.size(), data.size());
624 }
625
626 // Deserialize DICOM data
627 auto parse_result = core::dicom_file::from_bytes(data);
628 if (parse_result.is_err()) {
629 return make_error<core::dicom_dataset>(
630 kSerializationError,
631 "Failed to parse DICOM data: " + parse_result.error().message,
632 "s3_storage");
633 }
634
635 return parse_result.value().dataset();
636}

References kcenon::pacs::core::dicom_file::from_bytes().

Here is the call graph for this function:

◆ sanitize_uid()

auto kcenon::pacs::storage::s3_storage::sanitize_uid ( std::string_view uid) -> std::string
staticnodiscardprivate

Sanitize UID for use in S3 object key.

Parameters
uidThe UID to sanitize
Returns
Sanitized string safe for S3 key use
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 828 of file s3_storage.cpp.

828 {
829 std::string result;
830 result.reserve(uid.length());
831
832 for (char c : uid) {
833 // UIDs contain digits and dots, which are safe for S3 keys
834 // Replace any other characters with underscore
835 if (std::isalnum(static_cast<unsigned char>(c)) || c == '.') {
836 result += c;
837 } else {
838 result += '_';
839 }
840 }
841
842 return result;
843}

References uid.

◆ store()

auto kcenon::pacs::storage::s3_storage::store ( const core::dicom_dataset & dataset) -> VoidResult
nodiscardoverridevirtual

Store a DICOM dataset to S3.

Serializes the dataset to DICOM Part 10 format and uploads to S3. Uses multipart upload for files exceeding multipart_threshold.

Parameters
datasetThe DICOM dataset to store
Returns
VoidResult Success or error information
Note
Requires Study, Series, and SOP Instance UIDs in the dataset

Implements kcenon::pacs::storage::storage_interface.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 521 of file s3_storage.cpp.

521 {
522 return store_with_progress(dataset, nullptr);
523}
auto store_with_progress(const core::dicom_dataset &dataset, progress_callback callback) -> VoidResult
Store with progress tracking.

◆ store_with_progress()

auto kcenon::pacs::storage::s3_storage::store_with_progress ( const core::dicom_dataset & dataset,
progress_callback callback ) -> VoidResult
nodiscard

Store with progress tracking.

Parameters
datasetThe DICOM dataset to store
callbackProgress callback function
Returns
VoidResult Success or error information
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 525 of file s3_storage.cpp.

526 {
527 // Extract required UIDs
528 auto study_uid = dataset.get_string(core::tags::study_instance_uid);
529 auto series_uid = dataset.get_string(core::tags::series_instance_uid);
530 auto sop_uid = dataset.get_string(core::tags::sop_instance_uid);
531
532 if (study_uid.empty() || series_uid.empty() || sop_uid.empty()) {
533 return make_error<std::monostate>(
534 kMissingRequiredUid,
535 "Missing required UID (Study, Series, or SOP Instance UID)",
536 "s3_storage");
537 }
538
539 // Build S3 object key
540 auto object_key = build_object_key(study_uid, series_uid, sop_uid);
541
542 // Create DICOM file and serialize to bytes
543 auto dicom_file = core::dicom_file::create(
545
546 auto data = dicom_file.to_bytes();
547 if (data.empty()) {
548 return make_error<std::monostate>(
549 kSerializationError, "Failed to serialize DICOM dataset", "s3_storage");
550 }
551
552 // Report initial progress
553 if (callback && !callback(0, data.size())) {
554 return make_error<std::monostate>(kUploadError, "Upload cancelled by user",
555 "s3_storage");
556 }
557
558 // Upload to S3 (use multipart for large files)
559 VoidResult upload_result = ok();
560 if (data.size() > config_.multipart_threshold) {
561 upload_result =
562 client_->multipart_upload(object_key, data, config_.part_size, callback);
563 } else {
564 upload_result = client_->put_object(object_key, data);
565
566 // Report completion progress
567 if (callback) {
568 callback(data.size(), data.size());
569 }
570 }
571
572 if (upload_result.is_err()) {
573 return upload_result;
574 }
575
576 // Update local index
577 {
578 std::unique_lock lock(mutex_);
579 s3_object_info info;
580 info.key = object_key;
581 info.sop_instance_uid = sop_uid;
582 info.study_instance_uid = study_uid;
583 info.series_instance_uid = series_uid;
584 info.size_bytes = data.size();
585 index_[sop_uid] = std::move(info);
586 }
587
588 return ok();
589}
static auto create(dicom_dataset dataset, const encoding::transfer_syntax &ts) -> dicom_file
Create a new DICOM file from a dataset.
static const transfer_syntax explicit_vr_little_endian
Explicit VR Little Endian (1.2.840.10008.1.2.1)
auto build_object_key(std::string_view study_uid, std::string_view series_uid, std::string_view sop_uid) const -> std::string
Build S3 object key for a dataset.
std::size_t part_size
Part size for multipart upload in bytes (default: 10MB)
Definition s3_storage.h:63
std::size_t multipart_threshold
Threshold for multipart upload in bytes (default: 100MB) Files larger than this will use multipart up...
Definition s3_storage.h:60

References kcenon::pacs::core::dicom_file::create(), kcenon::pacs::encoding::transfer_syntax::explicit_vr_little_endian, kcenon::pacs::core::tags::series_instance_uid, kcenon::pacs::core::tags::sop_instance_uid, and kcenon::pacs::core::tags::study_instance_uid.

Here is the call graph for this function:

◆ upload_multipart()

auto kcenon::pacs::storage::s3_storage::upload_multipart ( const std::string & key,
const std::vector< std::uint8_t > & data,
progress_callback callback ) -> VoidResult
nodiscardprivate

Execute multipart upload for large files.

Parameters
keyS3 object key
dataData to upload
callbackOptional progress callback
Returns
VoidResult Success or error information
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 845 of file s3_storage.cpp.

847 {
848 return client_->multipart_upload(key, data, config_.part_size, callback);
849}

◆ verify_integrity()

auto kcenon::pacs::storage::s3_storage::verify_integrity ( ) -> VoidResult
nodiscardoverridevirtual

Verify storage integrity.

Checks that all indexed objects exist in S3 and have valid ETags.

Returns
VoidResult Success if integrity is verified, error otherwise

Implements kcenon::pacs::storage::storage_interface.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 727 of file s3_storage.cpp.

727 {
728 std::vector<std::pair<std::string, std::string>> entries;
729 {
730 std::shared_lock lock(mutex_);
731 entries.reserve(index_.size());
732 for (const auto &[uid, info] : index_) {
733 entries.emplace_back(uid, info.key);
734 }
735 }
736
737 std::vector<std::string> invalid_entries;
738
739 for (const auto &[uid, key] : entries) {
740 if (!client_->head_object(key)) {
741 invalid_entries.push_back(uid + " (object missing)");
742 }
743 }
744
745 if (!invalid_entries.empty()) {
746 std::string message = "Integrity check failed for " +
747 std::to_string(invalid_entries.size()) + " entries";
748 return make_error<std::monostate>(kIntegrityError, message, "s3_storage");
749 }
750
751 return ok();
752}

References uid.

Member Data Documentation

◆ client_

std::unique_ptr<s3_client_interface> kcenon::pacs::storage::s3_storage::client_
private

S3 client (mock for testing, AWS SDK for production)

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 392 of file s3_storage.h.

Referenced by is_connected().

◆ config_

cloud_storage_config kcenon::pacs::storage::s3_storage::config_
private

Storage configuration.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 389 of file s3_storage.h.

Referenced by bucket_name().

◆ index_

std::unordered_map<std::string, s3_object_info> kcenon::pacs::storage::s3_storage::index_
private

Mapping from SOP Instance UID to S3 object info.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 395 of file s3_storage.h.

Referenced by get_statistics().

◆ mutex_

std::shared_mutex kcenon::pacs::storage::s3_storage::mutex_
mutableprivate

Mutex for thread-safe access.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/s3_storage.h.

Definition at line 398 of file s3_storage.h.

Referenced by get_statistics().


The documentation for this class was generated from the following files: