diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-02-22 12:46:59 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-02-24 11:35:25 +0000 |
commit | d5078161aadac7bb36862d8eb0d6d8c27eb58c60 (patch) | |
tree | b33fd1d0f0bd2515c3db6a1c0c94d34be7622c51 /src/corelib/io | |
parent | f971a0d65cc4bc64dc61bdd2a4b659b382eb996f (diff) |
Speed up QFile::copy on Linux file systems that support cloning
Originally inherited from Btrfs, recent Linux kernels have a system call
that allows cloning the contents of a file from another one if the
underlying file system supports it.
Change-Id: I9df66b65faef99f3bbed8a88fb6b6009baeef32e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/qabstractfileengine.cpp | 13 | ||||
-rw-r--r-- | src/corelib/io/qabstractfileengine_p.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qfile.cpp | 37 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_p.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_unix.cpp | 17 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_win.cpp | 9 | ||||
-rw-r--r-- | src/corelib/io/qtemporaryfile_p.h | 2 |
7 files changed, 62 insertions, 18 deletions
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 9606ec68e9..5f1f7e381e 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -832,6 +832,19 @@ bool QAbstractFileEngine::unmap(uchar *address) } /*! + \since 5.10 + + Copies the contents from the file specified by \a sourceHandle to this file + by cloning it. + Returns \c true on success; otherwise, \c false is returned. + */ +bool QAbstractFileEngine::clone(int sourceHandle) +{ + Q_UNUSED(sourceHandle); + return false; +} + +/*! \since 4.3 \class QAbstractFileEngineIterator \inmodule QtCore diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index 48b3dec324..dbf0d77b15 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -147,6 +147,7 @@ public: virtual QDateTime fileTime(FileTime time) const; virtual void setFileName(const QString &file); virtual int handle() const; + virtual bool clone(int sourceHandle); bool atEnd() const; uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags); bool unmap(uchar *ptr); diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 41fae69bb2..6249d54f7d 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -42,6 +42,7 @@ #include "qfile.h" #include "qfsfileengine_p.h" #include "qtemporaryfile.h" +#include "qtemporaryfile_p.h" #include "qlist.h" #include "qfileinfo.h" #include "private/qiodevice_p.h" @@ -790,25 +791,27 @@ QFile::copy(const QString &newName) close(); d->setError(QFile::CopyError, tr("Cannot open for output")); } else { - char block[4096]; - qint64 totalRead = 0; - while(!atEnd()) { - qint64 in = read(block, sizeof(block)); - if (in <= 0) - break; - totalRead += in; - if(in != out.write(block, in)) { - close(); - d->setError(QFile::CopyError, tr("Failure to write block")); - error = true; - break; + if (!out.d_func()->engine()->clone(d->engine()->handle())) { + char block[4096]; + qint64 totalRead = 0; + while (!atEnd()) { + qint64 in = read(block, sizeof(block)); + if (in <= 0) + break; + totalRead += in; + if (in != out.write(block, in)) { + close(); + d->setError(QFile::CopyError, tr("Failure to write block")); + error = true; + break; + } } - } - if (totalRead != size()) { - // Unable to read from the source. The error string is - // already set from read(). - error = true; + if (totalRead != size()) { + // Unable to read from the source. The error string is + // already set from read(). + error = true; + } } if (!error && !out.rename(newName)) { error = true; diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 593ecc2687..742cebad87 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -108,6 +108,7 @@ public: qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 readLine(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; + bool clone(int sourceHandle) override; bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) Q_DECL_OVERRIDE; bool supportsExtension(Extension extension) const Q_DECL_OVERRIDE; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index ca5af924e9..ff77278dc1 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -780,6 +780,23 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) #endif } +/*! + \reimp +*/ +bool QFSFileEngine::clone(int sourceHandle) +{ +#if defined(Q_OS_LINUX) + Q_D(QFSFileEngine); +# if !defined FICLONE +# define FICLONE _IOW (0x94, 9, int) +# endif + return ::ioctl(d->fd, FICLONE, sourceHandle) == 0; +#else + Q_UNUSED(sourceHandle); + return false; +#endif +} + QT_END_NAMESPACE #endif // QT_NO_FSFILEENGINE diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index a7fd50df83..2ebc98e0de 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -984,4 +984,13 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) return true; } +/*! + \reimp +*/ +bool QFSFileEngine::clone(int sourceHandle) +{ + Q_UNUSED(sourceHandle); + return false; +} + QT_END_NAMESPACE diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h index 7f365f0e8a..bf40e1627a 100644 --- a/src/corelib/io/qtemporaryfile_p.h +++ b/src/corelib/io/qtemporaryfile_p.h @@ -65,7 +65,7 @@ class QTemporaryFilePrivate : public QFilePrivate { Q_DECLARE_PUBLIC(QTemporaryFile) -protected: +public: QTemporaryFilePrivate(); explicit QTemporaryFilePrivate(const QString &templateNameIn); ~QTemporaryFilePrivate(); |