diff --git a/libs/image/tiles3/kis_tile_hash_table.h b/libs/image/tiles3/kis_tile_hash_table.h index 8224fc4..7249a52 100644 --- a/libs/image/tiles3/kis_tile_hash_table.h +++ b/libs/image/tiles3/kis_tile_hash_table.h @@ -21,7 +21,10 @@ #define KIS_TILEHASHTABLE_H_ #include "kis_tile.h" +#include +#include +#include /** @@ -95,26 +98,66 @@ public: void debugPrintInfo(); void debugMaxListLength(qint32 &min, qint32 &max); + + void lock() { + for (int i = 0; i < LOCKS_SIZE; i++) { + m_tableLocks[i].lockForWrite(); + } + } + + void lock_shared() { + for (int i = 0; i < LOCKS_SIZE; i++) { + m_tableLocks[i].lockForRead(); + } + } + + void unlock() { + for (int i = LOCKS_SIZE - 1; i >= 0; i--) { + m_tableLocks[i].unlock(); + } + } + + void unlock_shared() { + for (int i = LOCKS_SIZE - 1; i >= 0; i--) { + m_tableLocks[i].unlock(); + } + } + + static inline quint32 calculateHash(qint32 col, qint32 row); + + private: - TileTypeSP getTile(qint32 col, qint32 row); - void linkTile(TileTypeSP tile); - TileTypeSP unlinkTile(qint32 col, qint32 row); + TileTypeSP getTile(qint32 col, qint32 row, qint32 idx); + void linkTile(TileTypeSP tile, qint32 idx); + TileTypeSP unlinkTile(qint32 col, qint32 row, qint32 idx); inline void setDefaultTileDataImp(KisTileData *defaultTileData); inline KisTileData* defaultTileDataImp() const; - static inline quint32 calculateHash(qint32 col, qint32 row); - inline qint32 debugChainLen(qint32 idx); void debugListLengthDistibution(); void sanityChecksumCheck(); private: template friend class KisTileHashTableIteratorTraits; + typedef boost::shared_lock_guard> ReadLockerImpl; + typedef boost::lock_guard> WriteLockerImpl; + + struct ReadLocker : public ReadLockerImpl { + ReadLocker(KisTileHashTableTraits *obj) : ReadLockerImpl(*obj) {} + }; + + struct WriteLocker : public WriteLockerImpl { + WriteLocker(KisTileHashTableTraits *obj) : WriteLockerImpl(*obj) {} + }; + static const qint32 TABLE_SIZE = 1024; + static constexpr qint32 LOCKS_SIZE = 16; + static constexpr qint32 LOCKS_SHIFT = 6; TileTypeSP *m_hashTable; qint32 m_numTiles; + std::array m_tableLocks; KisTileData *m_defaultTileData; KisMementoManager *m_mementoManager; @@ -145,12 +188,15 @@ public: if (m_index < KisTileHashTableTraits::TABLE_SIZE) m_tile = m_hashTable->m_hashTable[m_index]; - m_hashTable->m_lock.lockForWrite(); + //m_hashTable->m_lock.lockForWrite(); + m_hashTable->lock(); } ~KisTileHashTableIteratorTraits() { - if (m_index != -1) - m_hashTable->m_lock.unlock(); + if (m_index != -1) { + //m_hashTable->m_lock.unlock(); + m_hashTable->unlock(); + } } KisTileHashTableIteratorTraits& operator++() { @@ -184,20 +230,25 @@ public: void deleteCurrent() { TileTypeSP tile = m_tile; next(); - m_hashTable->unlinkTile(tile->col(), tile->row()); + + const qint32 idx = m_hashTable->calculateHash(tile->col(), tile->row()); + m_hashTable->unlinkTile(tile->col(), tile->row(), idx); } void moveCurrentToHashTable(KisTileHashTableTraits *newHashTable) { TileTypeSP tile = m_tile; next(); - m_hashTable->unlinkTile(tile->col(), tile->row()); + + const qint32 idx = m_hashTable->calculateHash(tile->col(), tile->row()); + m_hashTable->unlinkTile(tile->col(), tile->row(), idx); newHashTable->addTile(tile); } void destroy() { m_index = -1; - m_hashTable->m_lock.unlock(); + m_hashTable->unlock(); + //m_hashTable->m_lock.unlock(); } protected: TileTypeSP m_tile; diff --git a/libs/image/tiles3/kis_tile_hash_table_p.h b/libs/image/tiles3/kis_tile_hash_table_p.h index abcad46..1968466 100644 --- a/libs/image/tiles3/kis_tile_hash_table_p.h +++ b/libs/image/tiles3/kis_tile_hash_table_p.h @@ -23,6 +23,8 @@ //#define SHARED_TILES_SANITY_CHECK +#include + template KisTileHashTableTraits::KisTileHashTableTraits(KisMementoManager *mm) @@ -41,7 +43,7 @@ KisTileHashTableTraits::KisTileHashTableTraits(const KisTileHashTableTraits*>(&ht)); m_mementoManager = mm; m_defaultTileData = 0; @@ -87,9 +89,8 @@ quint32 KisTileHashTableTraits::calculateHash(qint32 col, qint32 row) template typename KisTileHashTableTraits::TileTypeSP -KisTileHashTableTraits::getTile(qint32 col, qint32 row) +KisTileHashTableTraits::getTile(qint32 col, qint32 row, qint32 idx) { - qint32 idx = calculateHash(col, row); TileTypeSP tile = m_hashTable[idx]; for (; tile; tile = tile->next()) { @@ -104,9 +105,8 @@ KisTileHashTableTraits::getTile(qint32 col, qint32 row) } template -void KisTileHashTableTraits::linkTile(TileTypeSP tile) +void KisTileHashTableTraits::linkTile(TileTypeSP tile, qint32 idx) { - qint32 idx = calculateHash(tile->col(), tile->row()); TileTypeSP firstTile = m_hashTable[idx]; #ifdef SHARED_TILES_SANITY_CHECK @@ -121,9 +121,8 @@ void KisTileHashTableTraits::linkTile(TileTypeSP tile) template typename KisTileHashTableTraits::TileTypeSP -KisTileHashTableTraits::unlinkTile(qint32 col, qint32 row) +KisTileHashTableTraits::unlinkTile(qint32 col, qint32 row, qint32 idx) { - qint32 idx = calculateHash(col, row); TileTypeSP tile = m_hashTable[idx]; TileTypeSP prevTile; @@ -179,16 +178,22 @@ inline KisTileData* KisTileHashTableTraits::defaultTileDataImp() const template bool KisTileHashTableTraits::tileExists(qint32 col, qint32 row) { - QReadLocker locker(&m_lock); - return getTile(col, row); + const qint32 idx = calculateHash(col, row); + + //ReadLocker locker(this); + QReadLocker locker(&m_tableLocks[idx >> LOCKS_SHIFT]); + return getTile(col, row, idx); } template typename KisTileHashTableTraits::TileTypeSP KisTileHashTableTraits::getExistingTile(qint32 col, qint32 row) { - QReadLocker locker(&m_lock); - return getTile(col, row); + const qint32 idx = calculateHash(col, row); + + //ReadLocker locker(this); + QReadLocker locker(&m_tableLocks[idx >> LOCKS_SHIFT]); + return getTile(col, row, idx); } template @@ -196,16 +201,25 @@ typename KisTileHashTableTraits::TileTypeSP KisTileHashTableTraits::getTileLazy(qint32 col, qint32 row, bool& newTile) { + const qint32 idx = calculateHash(col, row); + newTile = false; - TileTypeSP tile = getExistingTile(col, row); + TileTypeSP tile; + + { + //ReadLocker locker(this); + QReadLocker locker(&m_tableLocks[idx >> LOCKS_SHIFT]); + tile = getTile(col, row, idx); + } if (!tile) { - QWriteLocker locker(&m_lock); - tile = getTile(col, row); + //WriteLocker locker(this); + QWriteLocker locker(&m_tableLocks[idx >> LOCKS_SHIFT]); + tile = getTile(col, row, idx); if (!tile) { tile = new TileType(col, row, m_defaultTileData, m_mementoManager); - linkTile(tile); + linkTile(tile, idx); newTile = true; } } @@ -217,9 +231,11 @@ template typename KisTileHashTableTraits::TileTypeSP KisTileHashTableTraits::getReadOnlyTileLazy(qint32 col, qint32 row) { - QReadLocker locker(&m_lock); + const qint32 idx = calculateHash(col, row); + //ReadLocker locker(this); + QReadLocker locker(&m_tableLocks[idx >> LOCKS_SHIFT]); - TileTypeSP tile = getTile(col, row); + TileTypeSP tile = getTile(col, row, idx); if (!tile) tile = new TileType(col, row, m_defaultTileData, 0); @@ -229,16 +245,22 @@ KisTileHashTableTraits::getReadOnlyTileLazy(qint32 col, qint32 row) template void KisTileHashTableTraits::addTile(TileTypeSP tile) { - QWriteLocker locker(&m_lock); - linkTile(tile); + const qint32 idx = calculateHash(tile->col(), tile->row()); + + //WriteLocker locker(this); + QWriteLocker locker(&m_tableLocks[idx >> LOCKS_SHIFT]); + linkTile(tile, idx); } template void KisTileHashTableTraits::deleteTile(qint32 col, qint32 row) { - QWriteLocker locker(&m_lock); + const qint32 idx = calculateHash(col, row); + + //WriteLocker locker(this); + QWriteLocker locker(&m_tableLocks[idx >> LOCKS_SHIFT]); - TileTypeSP tile = unlinkTile(col, row); + TileTypeSP tile = unlinkTile(col, row, idx); /* Done by KisSharedPtr */ //if(tile) @@ -255,7 +277,7 @@ void KisTileHashTableTraits::deleteTile(TileTypeSP tile) template void KisTileHashTableTraits::clear() { - QWriteLocker locker(&m_lock); + WriteLocker locker(this); TileTypeSP tile = TileTypeSP(); qint32 i; @@ -286,14 +308,14 @@ void KisTileHashTableTraits::clear() template void KisTileHashTableTraits::setDefaultTileData(KisTileData *defaultTileData) { - QWriteLocker locker(&m_lock); + WriteLocker locker(this); setDefaultTileDataImp(defaultTileData); } template KisTileData* KisTileHashTableTraits::defaultTileData() const { - QWriteLocker locker(&m_lock); + WriteLocker locker(const_cast*>(this)); return defaultTileDataImp(); }