5#ifndef QRANDOMACCESSASYNCFILE_P_P_H
6#define QRANDOMACCESSASYNCFILE_P_P_H
21#include <QtCore/private/qobject_p.h>
23#include <QtCore/qstring.h>
25#if QT_CONFIG(future) && QT_CONFIG(thread)
27#include <QtCore/private/qfsfileengine_p.h>
29#include <QtCore/qfuturewatcher.h>
30#include <QtCore/qmutex.h>
31#include <QtCore/qqueue.h>
37#include <QtCore/qlist.h>
38#include <QtCore/qmutex.h>
39#include <QtCore/qset.h>
40#include <QtCore/qwaitcondition.h>
42#include <dispatch/dispatch.h>
46#ifdef QT_RANDOMACCESSASYNCFILE_QIORING
47#include <QtCore/private/qioring_p.h>
48#include <QtCore/qlist.h>
66 [[nodiscard]]
virtual QIOOperation *
open(
const QString &path, QIODeviceBase::OpenMode mode) = 0;
74 readInto(qint64 offset, QSpan<std::byte> buffer) = 0;
76 writeFrom(qint64 offset, QSpan<
const std::byte> buffer) = 0;
79 readInto(qint64 offset, QSpan<
const QSpan<std::byte>> buffers) = 0;
81 writeFrom(qint64 offset, QSpan<
const QSpan<
const std::byte>> buffers) = 0;
99 Q_DECLARE_PUBLIC(QRandomAccessAsyncFile)
106 {
return file->d_func(); }
112 m_backend->cancelAndWait(op);
123 return m_backend->size();
129 return m_backend->open(path, mode);
134 return m_backend->flush();
140 return m_backend->read(offset, maxSize);
145 return m_backend->write(offset, data);
150 return m_backend->write(offset, std::move(data));
156 return m_backend->readInto(offset, buffer);
161 return m_backend->writeFrom(offset, buffer);
165 QSpan<
const QSpan<std::byte>> buffers)
168 return m_backend->readInto(offset, buffers);
171 QSpan<
const QSpan<
const std::byte>> buffers)
174 return m_backend->writeFrom(offset, buffers);
178 void checkValid()
const { Q_ASSERT(m_backend); }
179 std::unique_ptr<QRandomAccessAsyncFileBackend> m_backend;
184#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) || defined(Q_OS_DARWIN)
185class QRandomAccessAsyncFileNativeBackend final :
public QRandomAccessAsyncFileBackend
187 Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileNativeBackend)
189 explicit QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner);
190 ~QRandomAccessAsyncFileNativeBackend();
192 bool init() override;
193 void cancelAndWait(QIOOperation *op) override;
195 void close() override;
196 qint64 size()
const override;
198 [[nodiscard]] QIOOperation *open(
const QString &path, QIODeviceBase::OpenMode mode) override;
199 [[nodiscard]] QIOOperation *flush() override;
201 [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override;
202 [[nodiscard]] QIOWriteOperation *write(qint64 offset,
const QByteArray &data) override;
203 [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override;
205 [[nodiscard]] QIOVectoredReadOperation *
206 readInto(qint64 offset, QSpan<std::byte> buffer) override;
207 [[nodiscard]] QIOVectoredWriteOperation *
208 writeFrom(qint64 offset, QSpan<
const std::byte> buffer) override;
210 [[nodiscard]] QIOVectoredReadOperation *
211 readInto(qint64 offset, QSpan<
const QSpan<std::byte>> buffers) override;
212 [[nodiscard]] QIOVectoredWriteOperation *
213 writeFrom(qint64 offset, QSpan<
const QSpan<
const std::byte>> buffers) override;
216#if defined(QT_RANDOMACCESSASYNCFILE_QIORING)
217 void queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error);
218 void startReadIntoSingle(QIOOperation *op,
const QSpan<std::byte> &to);
219 void startWriteFromSingle(QIOOperation *op,
const QSpan<
const std::byte> &from);
220 QIORing::RequestHandle cancel(QIORing::RequestHandle handle);
221 QIORing *m_ioring =
nullptr;
223 QList<QPointer<QIOOperation>> m_operations;
224 QHash<QIOOperation *, QIORing::RequestHandle> m_opHandleMap;
227 using OperationId = quint64;
228 static constexpr OperationId kInvalidOperationId = 0;
229 static constexpr OperationId kAllOperationIds = std::numeric_limits<OperationId>::max();
231 struct OperationResult
238 enum class OpState : quint8
247 dispatch_io_t channel;
248 QPointer<QIOOperation> operation;
251 OperationInfo(OperationId _id, QIOOperation *_op)
255 state(OpState::Pending)
268 QList<OperationInfo> m_operations;
269 dispatch_io_t m_ioChannel =
nullptr;
274 OperationId m_opToCancel = kInvalidOperationId;
275 QSet<OperationId> m_runningOps;
276 qsizetype m_numChannelsToClose = 0;
277 QWaitCondition m_cancellationCondition;
279 static OperationId getNextId();
281 template <
typename Operation,
typename ...Args>
282 Operation *addOperation(QIOOperation::Type type, qint64 offset, Args &&...args);
284 void notifyIfOperationsAreCompleted();
285 dispatch_io_t createMainChannel(
int fd);
286 dispatch_io_t duplicateIoChannel(OperationId opId);
287 void closeIoChannel(dispatch_io_t channel);
288 void releaseIoChannel(dispatch_io_t channel);
289 void handleOperationComplete(
const OperationResult &opResult);
291 void queueCompletion(OperationId opId,
int error);
293 void startOperationsUntilBarrier();
294 void executeRead(OperationInfo &opInfo);
295 void executeWrite(OperationInfo &opInfo);
296 void executeFlush(OperationInfo &opInfo);
297 void executeOpen(OperationInfo &opInfo);
299 void readOneBuffer(OperationId opId, qsizetype bufferIdx, qint64 alreadyRead);
300 void readOneBufferHelper(OperationId opId, dispatch_io_t channel, qint64 offset,
301 void *bytesPtr, qint64 maxSize, qsizetype currentBufferIdx,
302 qsizetype totalBuffers, qint64 alreadyRead);
303 void writeHelper(OperationId opId, dispatch_io_t channel, qint64 offset,
304 dispatch_data_t dataToWrite, qint64 dataSize);
309#if QT_CONFIG(future) && QT_CONFIG(thread)
310class QRandomAccessAsyncFileThreadPoolBackend :
public QRandomAccessAsyncFileBackend
312 Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileThreadPoolBackend)
314 explicit QRandomAccessAsyncFileThreadPoolBackend(QRandomAccessAsyncFile *owner);
315 ~QRandomAccessAsyncFileThreadPoolBackend();
317 bool init() override;
318 void cancelAndWait(QIOOperation *op) override;
320 void close() override;
321 qint64 size()
const override;
323 [[nodiscard]] QIOOperation *open(
const QString &path, QIODeviceBase::OpenMode mode) override;
324 [[nodiscard]] QIOOperation *flush() override;
326 [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override;
327 [[nodiscard]] QIOWriteOperation *write(qint64 offset,
const QByteArray &data) override;
328 [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override;
330 [[nodiscard]] QIOVectoredReadOperation *
331 readInto(qint64 offset, QSpan<std::byte> buffer) override;
332 [[nodiscard]] QIOVectoredWriteOperation *
333 writeFrom(qint64 offset, QSpan<
const std::byte> buffer) override;
335 [[nodiscard]] QIOVectoredReadOperation *
336 readInto(qint64 offset, QSpan<
const QSpan<std::byte>> buffers) override;
337 [[nodiscard]] QIOVectoredWriteOperation *
338 writeFrom(qint64 offset, QSpan<
const QSpan<
const std::byte>> buffers) override;
340 struct OperationResult
342 qint64 bytesProcessed;
343 QIOOperation::Error error;
347 mutable QBasicMutex m_engineMutex;
348 std::unique_ptr<QFSFileEngine> m_engine;
349 QFutureWatcher<OperationResult> m_watcher;
351 QQueue<QPointer<QIOOperation>> m_operations;
352 QPointer<QIOOperation> m_currentOperation;
353 qsizetype numProcessedBuffers = 0;
355 void executeNextOperation();
356 void processBufferAt(qsizetype idx);
359 void operationComplete();
virtual QIOOperation * open(const QString &path, QIODeviceBase::OpenMode mode)=0
virtual QIOReadOperation * read(qint64 offset, qint64 maxSize)=0
virtual ~QRandomAccessAsyncFileBackend()
QIODeviceBase::OpenMode m_openMode
virtual QIOWriteOperation * write(qint64 offset, QByteArray &&data)=0
virtual QIOOperation * flush()=0
virtual qint64 size() const =0
virtual QIOVectoredReadOperation * readInto(qint64 offset, QSpan< std::byte > buffer)=0
virtual void cancelAndWait(QIOOperation *op)=0
virtual QIOVectoredWriteOperation * writeFrom(qint64 offset, QSpan< const std::byte > buffer)=0
virtual QIOWriteOperation * write(qint64 offset, const QByteArray &data)=0
QRandomAccessAsyncFile * m_owner
static QRandomAccessAsyncFilePrivate * get(QRandomAccessAsyncFile *file)
QIOOperation * open(const QString &path, QIODeviceBase::OpenMode mode)
~QRandomAccessAsyncFilePrivate() override
void cancelAndWait(QIOOperation *op)
QIOReadOperation * read(qint64 offset, qint64 maxSize)
QIOVectoredWriteOperation * writeFrom(qint64 offset, QSpan< const std::byte > buffer)
QIOWriteOperation * write(qint64 offset, QByteArray &&data)
QIOWriteOperation * write(qint64 offset, const QByteArray &data)
QIOVectoredReadOperation * readInto(qint64 offset, QSpan< std::byte > buffer)
Combined button and popup list for selecting options.