diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2014-02-17 11:35:03 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-06 14:16:29 +0100 |
commit | 5b148b93d15844abea5bb6c6673064b8a701801f (patch) | |
tree | 78ee4880311be92c325caba40b77eea42fb9af7f | |
parent | 16e686342a4c0a8a875ff24f3d5d9bea8a9512e6 (diff) | |
download | qtwebkit-5b148b93d15844abea5bb6c6673064b8a701801f.tar.gz |
Implement Qt port for for leveldb
Replace the pthread/posix port classes in leveldb with a Qt port.
This should enable us to use leveldb on all Qt platforms.
Change-Id: Ie467f1c23ac28c436d26fb8fdc06c09ce70aff7d
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r-- | Source/ThirdParty/leveldb/Target.pri | 14 | ||||
-rw-r--r-- | Source/ThirdParty/leveldb/db/c.cc | 1 | ||||
-rw-r--r-- | Source/ThirdParty/leveldb/port/port.h | 2 | ||||
-rw-r--r-- | Source/ThirdParty/leveldb/port/port_qt.h | 123 | ||||
-rw-r--r-- | Source/ThirdParty/leveldb/util/env_qt.cc | 443 | ||||
-rw-r--r-- | Source/ThirdParty/leveldb/util/qt_logger.h | 59 | ||||
-rw-r--r-- | Tools/qmake/mkspecs/features/features.prf | 3 |
7 files changed, 633 insertions, 12 deletions
diff --git a/Source/ThirdParty/leveldb/Target.pri b/Source/ThirdParty/leveldb/Target.pri index 48d8550ff..ed4d8a1c8 100644 --- a/Source/ThirdParty/leveldb/Target.pri +++ b/Source/ThirdParty/leveldb/Target.pri @@ -27,10 +27,8 @@ HEADERS += \ db/version_edit.h \ db/version_set.h \ db/write_batch_internal.h \ - port/atomic_pointer.h \ - port/port_example.h \ port/port.h \ - port/port_posix.h \ + port/port_qt.h \ port/thread_annotations.h \ port/win/stdint.h \ helpers/memenv/memenv.h \ @@ -61,7 +59,7 @@ HEADERS += \ util/histogram.h \ util/logging.h \ util/mutexlock.h \ - util/posix_logger.h \ + util/qt_logger.h \ util/random.h SOURCES += \ @@ -80,7 +78,6 @@ SOURCES += \ db/version_set.cc \ db/write_batch.cc \ helpers/memenv/memenv.cc \ - port/port_posix.cc \ table/block_builder.cc \ table/block.cc \ table/filter_block.cc \ @@ -97,7 +94,7 @@ SOURCES += \ util/comparator.cc \ util/crc32c.cc \ util/env.cc \ - util/env_posix.cc \ + util/env_qt.cc \ util/filter_policy.cc \ util/hash.cc \ util/histogram.cc \ @@ -105,11 +102,10 @@ SOURCES += \ util/options.cc \ util/status.cc -posix: DEFINES += LEVELDB_PLATFORM_POSIX +DEFINES += LEVELDB_PLATFORM_QT win: DEFINES += OS_WIN mac: DEFINES += OS_MACOSX linux: DEFINES += OS_LINUX freebsd*: DEFINES += OS_FREEBSD -# We do not need anything from Qt -QT = +QT += core diff --git a/Source/ThirdParty/leveldb/db/c.cc b/Source/ThirdParty/leveldb/db/c.cc index 08ff0ad90..745817f2b 100644 --- a/Source/ThirdParty/leveldb/db/c.cc +++ b/Source/ThirdParty/leveldb/db/c.cc @@ -5,7 +5,6 @@ #include "leveldb/c.h" #include <stdlib.h> -#include <unistd.h> #include "leveldb/cache.h" #include "leveldb/comparator.h" #include "leveldb/db.h" diff --git a/Source/ThirdParty/leveldb/port/port.h b/Source/ThirdParty/leveldb/port/port.h index e667db40d..f6279fc7a 100644 --- a/Source/ThirdParty/leveldb/port/port.h +++ b/Source/ThirdParty/leveldb/port/port.h @@ -14,6 +14,8 @@ # include "port/port_posix.h" #elif defined(LEVELDB_PLATFORM_CHROMIUM) # include "port/port_chromium.h" +#elif defined(LEVELDB_PLATFORM_QT) +# include "port/port_qt.h" #endif #endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/Source/ThirdParty/leveldb/port/port_qt.h b/Source/ThirdParty/leveldb/port/port_qt.h new file mode 100644 index 000000000..cc8db5fe8 --- /dev/null +++ b/Source/ThirdParty/leveldb/port/port_qt.h @@ -0,0 +1,123 @@ +/* + Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef STORAGE_LEVELDB_PORT_PORT_QT_H_ +#define STORAGE_LEVELDB_PORT_PORT_QT_H_ + +#include <QAtomicInteger> +#include <QAtomicPointer> +#include <QMutex> +#include <QWaitCondition> + +#include <string> + +#ifdef SNAPPY +#include <snappy.h> +#endif + +#ifdef Q_CC_MSVC +#include "win/stdint.h" +#define snprintf _snprintf +#endif + +namespace leveldb { +namespace port { + +static const bool kLittleEndian = (Q_BYTE_ORDER == Q_LITTLE_ENDIAN); + +class Mutex : public QMutex { +public: + Mutex() { } + + void Lock() { lock(); } + void Unlock() { unlock(); } + void AssertHeld() { Q_ASSERT(!tryLock()); } +}; + +class CondVar : public QWaitCondition { +public: + explicit CondVar(Mutex* mu) : m_mutex(mu) { } + + void Wait() { wait(m_mutex); } + void Signal() { wakeOne(); } + void SignalAll() { wakeAll(); } +private: + Mutex* m_mutex; +}; + +typedef QAtomicInteger<int> OnceType; +#define LEVELDB_ONCE_INIT 0 +inline void InitOnce(port::OnceType* once, void (*initializer)()) +{ + if (once->testAndSetAcquire(0, 1)) + initializer(); +} + +class AtomicPointer : public QAtomicPointer<void> { +public: + AtomicPointer() { } + AtomicPointer(void *p) : QAtomicPointer<void>(p) { } + void* Acquire_Load() const { return loadAcquire(); } + void Release_Store(void* p) { storeRelease(p); } + void* NoBarrier_Load() const { return load(); } + void NoBarrier_Store(void* p) { store(p); } +}; + +// SNAPPY, non Qt specific: + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_QT_H_ diff --git a/Source/ThirdParty/leveldb/util/env_qt.cc b/Source/ThirdParty/leveldb/util/env_qt.cc new file mode 100644 index 000000000..a90a8afdf --- /dev/null +++ b/Source/ThirdParty/leveldb/util/env_qt.cc @@ -0,0 +1,443 @@ +/* + Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/qt_logger.h" + +#include <string.h> + +#include <QDateTime> +#include <QDir> +#include <QFile> +#include <QLockFile> +#include <QObject> +#include <QStandardPaths> +#include <QString> +#include <QThread> + +//#define QTENV_DEBUG + +#ifdef QTENV_DEBUG +#include <QDebug> +#endif + +typedef void (*UserFunctionPointer)(void*); + +Q_DECLARE_METATYPE(UserFunctionPointer) + +namespace leveldb { + +namespace { + + +static Status IOError(const QString& fname, const QString& errorMessage) +{ +#ifdef QTENV_DEBUG + qDebug() << Q_FUNC_INFO << fname << errorMessage; +#endif + return Status::IOError(fname.toStdString(), errorMessage.toStdString()); +} + +class QtSequentialFile: public SequentialFile { +public: + QFile m_file; + + QtSequentialFile(const std::string& fname) : m_file(QString::fromStdString(fname)) + { } + virtual ~QtSequentialFile() { m_file.close(); } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s; + size_t r = m_file.read(scratch, n); + *result = Slice(scratch, r); + if (r < n) { + if (m_file.atEnd()) { + // We leave status as ok if we hit the end of the file + } else { + // A partial read with an error: return a non-ok status + s = IOError(m_file.fileName(), m_file.errorString()); + } + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (!m_file.seek(n + m_file.pos())) { + return IOError(m_file.fileName(), m_file.errorString()); + } + return Status::OK(); + } +}; + +class QtRandomAccessFile: public RandomAccessFile { +public: + mutable QFile m_file; + + QtRandomAccessFile(const std::string& fname) : m_file(QString::fromStdString(fname)) + { } + virtual ~QtRandomAccessFile() { m_file.close(); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const + { + if (!m_file.seek(offset)) + return IOError(m_file.fileName(), m_file.errorString()); + + qint64 r = m_file.peek(scratch, n); + *result = Slice(scratch, (r < 0) ? 0 : r); + if (r < 0) { + // An error: return a non-ok status + return IOError(m_file.fileName(), m_file.errorString()); + } + return Status::OK(); + } +}; + +class QtWritableFile: public WritableFile { +public: + QFile m_file; + + QtWritableFile(const std::string& fname) : m_file(QString::fromStdString(fname)) + { } + virtual ~QtWritableFile() { m_file.close(); } + + virtual Status Append(const Slice& data) + { + m_file.unsetError(); + qint64 r = m_file.write(data.data(), data.size()); + if (r < 0) { + return IOError(m_file.fileName(), m_file.errorString()); + } + return Status::OK(); + } + virtual Status Close() + { + m_file.unsetError(); + if (!m_file.isOpen()) + return IOError(m_file.fileName(), QObject::tr("File not open")); + m_file.close(); + return Status::OK(); + } + virtual Status Flush() + { + m_file.unsetError(); + if (!m_file.flush()) + return IOError(m_file.fileName(), m_file.errorString()); + return Status::OK(); + } + + virtual Status Sync() + { + return Flush(); + } +}; + +class QtFileLock : public FileLock { +public: + QLockFile m_file; + QString m_fileName; + + QtFileLock(const std::string& fname) + : m_file(QString::fromStdString(fname)) + , m_fileName(QString::fromStdString(fname)) + { } +}; + +class BGProcessor : public QObject { + Q_OBJECT +public: + BGProcessor() + { + } + +public slots: + void slot_run(UserFunctionPointer user_function, void* arg) + { + user_function(arg); + } +}; + +class BGThread : public QThread { + Q_OBJECT +public: + BGThread() : m_processor(0), m_started(0) + { + } + + virtual void run() { + m_mutex.lock(); + m_processor = new BGProcessor(); + QObject::connect(this, SIGNAL(schedule(UserFunctionPointer,void*)), m_processor, SLOT(slot_run(UserFunctionPointer,void*)), Qt::QueuedConnection); + m_started.store(1); + m_startCond.wakeAll(); + m_mutex.unlock(); + exec(); + delete m_processor; + } + + void waitUntilStarted() { + if (m_started) + return; + m_mutex.lock(); + if (!m_started) + m_startCond.wait(&m_mutex); + m_mutex.unlock(); + } +signals: + void schedule(UserFunctionPointer user_function, void* arg); + +private: + BGProcessor* m_processor; + QMutex m_mutex; + QWaitCondition m_startCond; + QAtomicInt m_started; +}; + +class QtEnv : public Env { +public: + QtEnv() { + bgthread.start(); + } + + virtual ~QtEnv() { + qFatal("Destroying Env::Default()\n"); + } + + virtual Status NewSequentialFile(const std::string& fname, SequentialFile** result) + { + QtSequentialFile* file = new QtSequentialFile(fname); + if (!file->m_file.open(QIODevice::ReadOnly)) { + *result = 0; + Status status = IOError(file->m_file.fileName(), file->m_file.errorString()); + delete file; + return status; + } + *result = file; + return Status::OK(); + } + + virtual Status NewRandomAccessFile(const std::string& fname, RandomAccessFile** result) + { + QtRandomAccessFile* file = new QtRandomAccessFile(fname); + if (!file->m_file.open(QIODevice::ReadOnly)) { + *result = 0; + Status status = IOError(file->m_file.fileName(), file->m_file.errorString()); + delete file; + return status; + } + *result = file; + return Status::OK(); + } + + virtual Status NewWritableFile(const std::string& fname, WritableFile** result) + { + QtWritableFile* file = new QtWritableFile(fname); + if (!file->m_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + *result = 0; + Status status = IOError(file->m_file.fileName(), file->m_file.errorString()); + delete file; + return status; + } + *result = file; + return Status::OK(); + } + + virtual bool FileExists(const std::string& fname) + { + return QFile::exists(QString::fromStdString(fname)); + } + + virtual Status GetChildren(const std::string& dir, std::vector<std::string>* result) + { + result->clear(); + QDir qdir(QString::fromStdString(dir)); + foreach (const QString& filename, qdir.entryList()) { + result->push_back(filename.toStdString()); + } + return Status::OK(); + } + + virtual Status DeleteFile(const std::string& fname) + { + QFile file(QString::fromStdString(fname)); + if (!file.remove()) + return IOError(file.fileName(), file.errorString()); + return Status::OK(); + } + + virtual Status CreateDir(const std::string& name) + { + QDir dir; + if (!dir.mkdir(QString::fromStdString(name))) + return IOError(QString::fromStdString(name), QObject::tr("Could not create path")); + return Status::OK(); + } + + virtual Status DeleteDir(const std::string& name) + { + QDir dir; + if (!dir.rmdir(QString::fromStdString(name))) + return IOError(QString::fromStdString(name), QObject::tr("Could not delete path")); + return Status::OK(); + } + + virtual Status GetFileSize(const std::string& fname, uint64_t* size) + { + QFile file(QString::fromStdString(fname)); + qint64 sz = file.size(); + if (!sz) + return IOError(file.fileName(), file.errorString()); + + *size = sz; + return Status::OK(); + } + + virtual Status RenameFile(const std::string& src, const std::string& target) + { + QFile file(QString::fromStdString(src)); + // POSIX rename overwrites destination, QFile::rename does not. + if (file.exists() && QFile::exists(QString::fromStdString(target))) + QFile::remove(QString::fromStdString(target)); + if (!file.rename(QString::fromStdString(target))) + return IOError(file.fileName(), file.errorString()); + return Status::OK(); + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) + { + *lock = 0; + QtFileLock* my_lock = new QtFileLock(fname); + if (!my_lock->m_file.tryLock(500)) { + if (my_lock->m_file.staleLockTime() > 30000) { + // Handle stale lock files not locked by Qt. + my_lock->m_file.setStaleLockTime(30000); + return LockFile(fname, lock); + } + QString errorString; + switch (my_lock->m_file.error()) { + case QLockFile::NoError: + errorString = QObject::tr("No error"); + break; + case QLockFile::LockFailedError: + errorString = QObject::tr("Lock failed error"); + break; + case QLockFile::PermissionError: + errorString = QObject::tr("Permission error"); + break; + case QLockFile::UnknownError: + errorString = QObject::tr("Unknown error"); + break; + } + delete my_lock; + return IOError(QString::fromStdString(fname), errorString); + } + *lock = my_lock; + return Status::OK(); + } + + virtual Status UnlockFile(FileLock* lock) + { + QtFileLock* my_lock = reinterpret_cast<QtFileLock*>(lock); + my_lock->m_file.unlock(); + delete my_lock; + return Status::OK(); + } + + virtual void Schedule(void (*function)(void*), void* arg) + { + bgthread.waitUntilStarted(); + emit bgthread.schedule(function, arg); + } + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* result) { + QByteArray env = qgetenv("TEST_TMPDIR"); + if (!env.isEmpty() && env[0] != '\0') { + *result = QString::fromLocal8Bit(env).toStdString(); + } else { + QString path = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + *result = path.toStdString(); + } + // Directory may already exist + CreateDir(*result); + return Status::OK(); + } + + virtual Status NewLogger(const std::string& fname, Logger** result) + { + *result = new QtLogger(QString::fromStdString(fname)); + return Status::OK(); + } + + virtual uint64_t NowMicros() + { + return QDateTime::currentMSecsSinceEpoch() * 1000; + } + + virtual void SleepForMicroseconds(int micros) + { + QThread::usleep(micros); + } +private: + BGThread bgthread; +}; + +class StartThreadState : public QThread { +public: + StartThreadState(UserFunctionPointer user_function, void* arg) + : user_function(user_function) + , arg(arg) + { } + virtual void run() + { + user_function(arg); + } +private: + UserFunctionPointer user_function; + void* arg; +}; + +void QtEnv::StartThread(void (*function)(void*), void* arg) +{ + QThread* thread = new StartThreadState(function, arg); + QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + thread->start(); +} + +} // namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() +{ + qRegisterMetaType<UserFunctionPointer>(); + default_env = new QtEnv; +} + +Env* Env::Default() { + port::InitOnce (&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb + +#include "env_qt.moc" diff --git a/Source/ThirdParty/leveldb/util/qt_logger.h b/Source/ThirdParty/leveldb/util/qt_logger.h new file mode 100644 index 000000000..e673fd5de --- /dev/null +++ b/Source/ThirdParty/leveldb/util/qt_logger.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef STORAGE_LEVELDB_UTIL_QT_LOGGER_H_ +#define STORAGE_LEVELDB_UTIL_QT_LOGGER_H_ + +#include "leveldb/env.h" + +#include <QDateTime> +#include <QFile> +#include <QString> +#include <QTextStream> +#include <QThread> + +namespace leveldb { + +class QtLogger : public Logger { +private: + QFile file; + QTextStream log; + +public: + QtLogger(QString fname) : file(fname), log(&file) + { + file.open(QIODevice::WriteOnly | QIODevice::Append); + } + virtual ~QtLogger() { + log.flush(); + file.close(); + } + + virtual void Logv(const char* format, va_list ap) { + const uint64_t thread_id = (qintptr)QThread::currentThreadId(); + QString formated; + formated = formated.vsprintf(format, ap); + + log << QDateTime::currentDateTime().toString(Qt::SystemLocaleShortDate) << " " << thread_id << " " << formated << '\n'; + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_QT_LOGGER_H_ diff --git a/Tools/qmake/mkspecs/features/features.prf b/Tools/qmake/mkspecs/features/features.prf index d45ea40cd..866e1c41b 100644 --- a/Tools/qmake/mkspecs/features/features.prf +++ b/Tools/qmake/mkspecs/features/features.prf @@ -135,8 +135,7 @@ defineTest(detectFeatures) { # Slider Touch is sensible to use when compiling WebKit2 enable?(touch_events): WEBKIT_CONFIG += touch_slider - # IndexedDB requires leveldb and leveldb currently requires posix - !posix:WEBKIT_CONFIG -= indexed_database + # IndexedDB requires leveldb enable?(indexed_database): WEBKIT_CONFIG += use_leveldb export(WEBKIT_CONFIG) |