Mercurial > hg > orthanc
view OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h @ 7129:662d58ce7ddf Orthanc-1.13.0
Orthanc-1.13.0
| author | Sebastien Jodogne <s.jodogne@gmail.com> |
|---|---|
| date | Sat, 15 Aug 2026 13:53:33 +0200 |
| parents | cf1f10a22505 |
| children |
line wrap: on
line source
/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium * Copyright (C) 2017-2023 Osimis S.A., Belgium * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/>. **/ #pragma once #include "../MultiThreading/IExecutorService.h" #include "DataSourceAnswer.h" #include <stdint.h> namespace Orthanc { class DataSourceReader; class OrthancException; /** * This class retrieves items from a data source in a deterministic * order while still using parallel execution through a thread pool. * * Internally, it uses a sliding-window approach. Since items may * complete out of order, the class buffers them until earlier items * become available. This additional buffering is necessary because * applying backpressure (as done in "DataSourceReader::Submit()") * could otherwise lead to deadlock. If item ordering is not * required, prefer "DataSourceReader::Submit()", which supports * backpressure and avoids the extra memory overhead. * * Note that this class is not thread safe, it should be invoked * from a single thread. **/ class ORTHANC_PUBLIC DataSourceSequentialReader : public boost::noncopyable { public: class ORTHANC_PUBLIC Item : public IDynamicObject { private: std::unique_ptr<IDynamicObject> value_; std::unique_ptr<OrthancException> error_; std::unique_ptr<IDynamicObject> userData_; size_t estimatedSize_; public: Item(IDynamicObject* value, size_t estimatedSize); explicit Item(const OrthancException& error); const IDynamicObject& GetValue() const; void SetUserData(IDynamicObject* userData); bool HasUserData() const { return userData_.get() != NULL; } const IDynamicObject& GetUserData() const; size_t GetEstimatedSize() const { return estimatedSize_; } IDynamicObject* ReleaseValue(); IDynamicObject* ReleaseUserData(); }; /** * Extracts the value from an answer item so that it can be * buffered independently and is no longer subject to * backpressure. **/ class ORTHANC_PUBLIC IValueDisconnector : public boost::noncopyable { public: virtual ~IValueDisconnector() { } // IMPORTANT: The disconnector is in charge of deleting the "source" object. // If "source" is not properly destructed, deadlock will occur. // Note that "source" will never contain user data, those are handled at the level above. virtual IDynamicObject* Apply(DataSourceAnswer::Item* source /* takes ownership */) = 0; }; private: class Callable; typedef std::list<IDataIdentifier*> PendingRequests; typedef std::list<IFuture*> RunningRequests; boost::shared_ptr<IExecutorService> executor_; boost::shared_ptr<DataSourceReader> reader_; boost::shared_ptr<IValueDisconnector> disconnector_; unsigned int windowSize_; uint64_t windowCapacity_; bool started_; PendingRequests pendingRequests_; RunningRequests runningRequests_; uint64_t runningSize_; void FillWindow(); public: // IMPORTANT: The "executor" must not be the same as that of "reader", otherwise deadlock will occur DataSourceSequentialReader(const boost::shared_ptr<IExecutorService>& executor, const boost::shared_ptr<DataSourceReader>& reader, IValueDisconnector* disconnector /* takes ownership */, unsigned int windowSize /* maximum number of elements in the sliding window */, uint64_t windowCapacity /* if 0, memory usage is only controlled by the size of the sliding window */); ~DataSourceSequentialReader(); void Submit(IDataIdentifier* request /* takes ownership */); void Start(); bool HasNext() const; Item* Next(); }; }
