diff options
author | Alex Trotsenko <alex1973tr@gmail.com> | 2015-06-02 22:01:44 +0300 |
---|---|---|
committer | Alex Trotsenko <alex1973tr@gmail.com> | 2016-01-12 18:00:58 +0000 |
commit | 7d257aab8175f3d4fd3b838d4f47457a8d868885 (patch) | |
tree | 7ebbbc4809561ad8a95961e1914890d37f19a934 /src/corelib/io/qiodevice_p.h | |
parent | 98cea2b6c49940e806c102cd33381807d86df44e (diff) |
QIODevice: handle incomplete reads
Introduce a transaction mechanism that gives the ability to read the
data atomically. Current implementation supports transactions for both
types of devices. For sequential devices, it records the whole input
stream during transaction. For random-access devices, device position
is saved when transaction starts. If an error occurs, the application
may be able to recover the input stream by rolling back to the start
point.
Also, QIODevice::peek() was rewritten to make use of transactions
internally. The replacement of QIODevicePrivateLinearBuffer by
QRingBuffer is closely entangled with that, which makes it unfeasible
to do separately.
Bump the TypeInformationVersion field in qtHookData, to notify the
Qt Creator developers that the offset of QFilePrivate::fileName was
changed and dumpers should be adapted.
[ChangeLog][QtCore] Added QIODevice's startTransaction(),
commitTransaction(), rollbackTransaction(), isTransactionStarted()
functions to support the read transactions.
Task-number: QTBUG-44418
Change-Id: I3564b343ebeeaaf7c48a1dcdb7ef0a7ffec550f2
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'src/corelib/io/qiodevice_p.h')
-rw-r--r-- | src/corelib/io/qiodevice_p.h | 143 |
1 files changed, 10 insertions, 133 deletions
diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h index 56a89ab680..45f5219240 100644 --- a/src/corelib/io/qiodevice_p.h +++ b/src/corelib/io/qiodevice_p.h @@ -62,138 +62,6 @@ QT_BEGIN_NAMESPACE Q_CORE_EXPORT int qt_subtract_from_timeout(int timeout, int elapsed); -// This is QIODevice's read buffer, optimized for read(), isEmpty() and getChar() -class QIODevicePrivateLinearBuffer -{ -public: - QIODevicePrivateLinearBuffer(int) : len(0), first(0), buf(0), capacity(0) { - } - ~QIODevicePrivateLinearBuffer() { - delete [] buf; - } - void clear() { - len = 0; - delete [] buf; - buf = 0; - first = buf; - capacity = 0; - } - qint64 size() const { - return len; - } - bool isEmpty() const { - return len == 0; - } - void skip(qint64 n) { - if (n >= len) { - clear(); - } else { - len -= n; - first += n; - } - } - int getChar() { - if (len == 0) - return -1; - int ch = uchar(*first); - len--; - first++; - return ch; - } - qint64 read(char* target, qint64 size) { - qint64 r = qMin(size, len); - memcpy(target, first, r); - len -= r; - first += r; - return r; - } - qint64 peek(char* target, qint64 size) { - qint64 r = qMin(size, len); - memcpy(target, first, r); - return r; - } - char* reserve(qint64 size) { - makeSpace(size + len, freeSpaceAtEnd); - char* writePtr = first + len; - len += size; - return writePtr; - } - void chop(qint64 size) { - if (size >= len) { - clear(); - } else { - len -= size; - } - } - QByteArray readAll() { - QByteArray retVal(first, len); - clear(); - return retVal; - } - qint64 readLine(char* target, qint64 size) { - qint64 r = qMin(size, len); - char* eol = static_cast<char*>(memchr(first, '\n', r)); - if (eol) - r = 1+(eol-first); - memcpy(target, first, r); - len -= r; - first += r; - return r; - } - bool canReadLine() const { - return memchr(first, '\n', len); - } - void ungetChar(char c) { - if (first == buf) { - // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer - makeSpace(len+1, freeSpaceAtStart); - } - first--; - len++; - *first = c; - } - void ungetBlock(const char* block, qint64 size) { - if ((first - buf) < size) { - // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer - makeSpace(len + size, freeSpaceAtStart); - } - first -= size; - len += size; - memcpy(first, block, size); - } - -private: - enum FreeSpacePos {freeSpaceAtStart, freeSpaceAtEnd}; - void makeSpace(size_t required, FreeSpacePos where) { - size_t newCapacity = qMax(capacity, size_t(QIODEVICE_BUFFERSIZE)); - while (newCapacity < required) - newCapacity *= 2; - const size_t moveOffset = (where == freeSpaceAtEnd) ? 0 : newCapacity - size_t(len); - if (newCapacity > capacity) { - // allocate more space - char* newBuf = new char[newCapacity]; - memmove(newBuf + moveOffset, first, len); - delete [] buf; - buf = newBuf; - capacity = newCapacity; - } else { - // shift any existing data to make space - memmove(buf + moveOffset, first, len); - } - first = buf + moveOffset; - } - -private: - // length of the unread data - qint64 len; - // start of the unread data - char* first; - // the allocated buffer - char* buf; - // allocated buffer size - size_t capacity; -}; - class Q_CORE_EXPORT QIODevicePrivate #ifndef QT_NO_QOBJECT : public QObjectPrivate @@ -208,9 +76,11 @@ public: QIODevice::OpenMode openMode; QString errorString; - QIODevicePrivateLinearBuffer buffer; + QRingBuffer buffer; qint64 pos; qint64 devicePos; + qint64 transactionPos; + bool transactionStarted; bool baseReadLineDataCalled; virtual bool putCharHelper(char c); @@ -228,6 +98,13 @@ public: return accessMode == Sequential; } + inline bool isBufferEmpty() const + { + return buffer.isEmpty() || (transactionStarted && isSequential() + && transactionPos == buffer.size()); + } + void seekBuffer(qint64 newPos); + virtual qint64 peek(char *data, qint64 maxSize); virtual QByteArray peek(qint64 maxSize); |