File indexing completed on 2024-05-05 04:49:18

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com>            *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #define DEBUG_PREFIX "ServiceSqlRegistry"
0018 
0019 #include "ServiceSqlRegistry.h"
0020 
0021 #include "core/support/Debug.h"
0022 
0023 
0024 #include <QMutableHashIterator>
0025 #include <QMutexLocker>
0026 
0027 using namespace Meta;
0028 
0029 ServiceSqlRegistry::ServiceSqlRegistry( ServiceMetaFactory * metaFactory )
0030     : QObject( nullptr )
0031     , m_metaFactory( metaFactory )
0032 {
0033     setObjectName( QStringLiteral("ServiceSqlRegistry") );
0034 
0035    /* m_timer = new QTimer( this );
0036     m_timer->setInterval( 60000 );  //try to clean up every 60 seconds, change if necessary
0037     m_timer->setSingleShot( false );
0038     connect( m_timer, &QTimer::timeout, this, SLOT(emptyCache()) );
0039     m_timer->start();*/
0040 }
0041 
0042 ServiceSqlRegistry::~ServiceSqlRegistry()
0043 {
0044     //don't delete m_collection
0045 }
0046 
0047 TrackPtr
0048 ServiceSqlRegistry::getTrack( const QStringList &rowData )
0049 {
0050     //test if rowData is the correct length
0051     int correctLength = m_metaFactory->getTrackSqlRowCount() + m_metaFactory->getAlbumSqlRowCount() + m_metaFactory->getArtistSqlRowCount() + m_metaFactory->getGenreSqlRowCount();
0052 
0053     if ( rowData.size() != correctLength )
0054         return Meta::TrackPtr();
0055 
0056     int id = rowData[0].toInt();
0057 
0058     QMutexLocker locker( &m_trackMutex );
0059     if( m_trackMap.contains( id ) )
0060     {
0061         return m_trackMap.value( id );
0062     }
0063     else
0064     {
0065         int index = 0;
0066         TrackPtr trackPtr = m_metaFactory->createTrack( rowData.mid(index, m_metaFactory->getTrackSqlRowCount() ) );
0067         index += m_metaFactory->getTrackSqlRowCount();
0068 
0069         ServiceTrack * track = static_cast<ServiceTrack *> ( trackPtr.data() );
0070         AlbumPtr albumPtr;
0071 
0072         if ( m_albumMap.contains( track->albumId() ) )
0073             albumPtr = m_albumMap.value( track->albumId() );
0074         else
0075             albumPtr = getAlbum( rowData.mid( index, rowData.count() -1 ) );
0076 
0077         index += m_metaFactory->getAlbumSqlRowCount();
0078 
0079         ServiceAlbum * album = static_cast<ServiceAlbum *> ( albumPtr.data() );
0080 
0081         album->addTrack( trackPtr );
0082         track->setAlbumPtr( albumPtr );
0083 
0084         m_albumMap.insert( track->albumId(), albumPtr );
0085 
0086 
0087         ArtistPtr artistPtr;
0088 
0089         if ( m_artistMap.contains( track->artistId() ) )
0090             artistPtr = m_artistMap.value( track->artistId() );
0091         else
0092         {
0093             QStringList subRows = rowData.mid(index, m_metaFactory->getArtistSqlRowCount() );
0094             artistPtr = m_metaFactory->createArtist( subRows );
0095         }
0096 
0097         index += m_metaFactory->getArtistSqlRowCount();
0098 
0099         ServiceArtist * artist = static_cast<ServiceArtist *> ( artistPtr.data() );
0100 
0101         artist->addTrack( trackPtr );
0102         track->setArtist( artistPtr );
0103 
0104         m_artistMap.insert( track->artistId(), artistPtr );
0105 
0106         GenrePtr genrePtr;
0107 
0108         int genreId = rowData[index].toInt();
0109 
0110         if( m_genreMap.contains( genreId ) )
0111             genrePtr = m_genreMap.value( genreId );
0112         else
0113             genrePtr = m_metaFactory->createGenre( rowData.mid(index, m_metaFactory->getGenreSqlRowCount() ) );
0114 
0115         ServiceGenre * genre = dynamic_cast<ServiceGenre *> ( genrePtr.data() );
0116         Q_ASSERT( genre );
0117 
0118         if( genre )
0119             genre->addTrack( trackPtr );
0120 
0121         track->setGenre( genrePtr );
0122 
0123         m_genreMap.insert( genreId, genrePtr );
0124 
0125         m_trackMap.insert( id, trackPtr );
0126         return trackPtr;
0127     }
0128 }
0129 
0130 ArtistPtr
0131 ServiceSqlRegistry::getArtist( const QStringList &rowData )
0132 {
0133     int id = rowData[0].toInt();
0134 
0135     QMutexLocker locker( &m_artistMutex );
0136     if( m_artistMap.contains( id ) )
0137         return m_artistMap.value( id );
0138     else
0139     {
0140         ArtistPtr artist = m_metaFactory->createArtist( rowData );
0141         m_artistMap.insert( id, artist );
0142         return artist;
0143     }
0144 }
0145 
0146 GenrePtr
0147 ServiceSqlRegistry::getGenre( const QStringList &rowData )
0148 {
0149     int id = rowData[0].toInt();
0150     QMutexLocker locker( &m_genreMutex );
0151     if( m_genreMap.contains( id ) )
0152         return m_genreMap.value( id );
0153     else
0154     {
0155         GenrePtr genre = m_metaFactory->createGenre( rowData );
0156         m_genreMap.insert( id, genre );
0157         return genre;
0158     }
0159 }
0160 
0161 /*ComposerPtr
0162 ServiceSqlRegistry::getComposer( const QString &name, int id )
0163 {
0164     QMutexLocker locker( &m_composerMutex );
0165     if( m_composerMap.contains( name ) )
0166         return m_composerMap.value( name );
0167     else
0168     {
0169         ComposerPtr composer( new SqlComposer( m_collection, id, name ) );
0170         m_composerMap.insert( name, composer );
0171         return composer;
0172     }
0173 }*/
0174 
0175 /*YearPtr
0176 ServiceSqlRegistry::getYear( const QString &name, int id )
0177 {
0178     QMutexLocker locker( &m_yearMutex );
0179     if( m_yearMap.contains( name ) )
0180         return m_yearMap.value( name );
0181     else
0182     {
0183         YearPtr year( new SqlYear( m_collection, id, name ) );
0184         m_yearMap.insert( name, year );
0185         return year;
0186     }
0187 }*/
0188 
0189 AlbumPtr
0190 ServiceSqlRegistry::getAlbum( const QStringList &rowData )
0191 {
0192     int id = rowData[0].toInt();
0193     QMutexLocker locker( &m_albumMutex );
0194     if( m_albumMap.contains( id ) )
0195         return m_albumMap.value( id );
0196     else
0197     {
0198         int index = 0; 
0199         
0200         QStringList testString = rowData.mid( index, m_metaFactory->getAlbumSqlRowCount() );
0201 
0202         AlbumPtr albumPtr = m_metaFactory->createAlbum( rowData.mid(index, m_metaFactory->getAlbumSqlRowCount() ) );
0203         m_albumMap.insert( id, albumPtr );
0204 
0205         index += m_metaFactory->getAlbumSqlRowCount();
0206 
0207         ServiceAlbum* album = static_cast<ServiceAlbum *> ( albumPtr.data() );
0208 
0209         ArtistPtr artistPtr;
0210 
0211         // we need to set the artist for this album
0212         if ( m_artistMap.contains( album->artistId() ) )
0213             artistPtr = m_artistMap.value( album->artistId() );
0214         else
0215         {
0216             QStringList subRows = rowData.mid(index, m_metaFactory->getArtistSqlRowCount() );
0217             artistPtr = m_metaFactory->createArtist( subRows );
0218         }
0219 
0220         index += m_metaFactory->getArtistSqlRowCount();
0221 
0222         ServiceArtist * artist = static_cast<ServiceArtist *> ( artistPtr.data() );
0223 
0224         album->setAlbumArtist( artistPtr );
0225 
0226         m_artistMap.insert( artist->id(), artistPtr );
0227 
0228         return albumPtr;
0229     }
0230 }
0231 
0232 /*
0233 void
0234 ServiceSqlRegistry::emptyCache()
0235 {
0236     DEBUG_BLOCK
0237     bool hasTrack, hasAlbum, hasArtist, hasYear, hasGenre, hasComposer;
0238     hasTrack = hasAlbum = hasArtist = hasYear = hasGenre = hasComposer = false;
0239 
0240     //try to avoid possible deadlocks by aborting when we can't get all locks
0241     if ( ( hasTrack = m_trackMutex.tryLock() )
0242          && ( hasAlbum = m_albumMutex.tryLock() )
0243          && ( hasArtist = m_artistMutex.tryLock() )
0244          && ( hasYear = m_yearMutex.tryLock() )
0245          && ( hasGenre = m_genreMutex.tryLock() )
0246          && ( hasComposer = m_composerMutex.tryLock() ) )
0247     {
0248         //this very simple garbage collector doesn't handle cyclic object graphs
0249         //so care has to be taken to make sure that we are not dealing with a cyclic graph
0250         //by invalidating the tracks cache on all objects
0251         #define foreachInvalidateCache( Type, RealType, x ) \
0252         for( QMutableHashIterator<QString,Type > iter(x); iter.hasNext(); ) \
0253             RealType::staticCast( iter.next().value() )->invalidateCache()
0254 
0255         foreachInvalidateCache( AlbumPtr, AmarokSharedPointer<SqlAlbum>, m_albumMap );
0256         foreachInvalidateCache( ArtistPtr, AmarokSharedPointer<SqlArtist>, m_artistMap );
0257         foreachInvalidateCache( GenrePtr, AmarokSharedPointer<SqlGenre>, m_genreMap );
0258         foreachInvalidateCache( ComposerPtr, AmarokSharedPointer<SqlComposer>, m_composerMap );
0259         foreachInvalidateCache( YearPtr, AmarokSharedPointer<SqlYear>, m_yearMap );
0260 
0261         //elem.count() == 2 is correct because elem is one pointer to the object
0262         //and the other is stored in the hash map
0263         #define foreachCollectGarbage( Key, Type, x ) \
0264         for( QMutableHashIterator<Key,Type > iter(x); iter.hasNext(); ) \
0265         { \
0266             Type elem = iter.next().value(); \
0267             if( elem.count() == 2 ) \
0268                 iter.remove(); \
0269         }
0270 
0271         foreachCollectGarbage( TrackId, TrackPtr, m_trackMap )
0272         //run before artist so that album artist pointers can be garbage collected
0273         foreachCollectGarbage( QString, AlbumPtr, m_albumMap )
0274         foreachCollectGarbage( QString, ArtistPtr, m_artistMap )
0275         foreachCollectGarbage( QString, GenrePtr, m_genreMap )
0276         foreachCollectGarbage( QString, ComposerPtr, m_composerMap )
0277         foreachCollectGarbage( QString, YearPtr, m_yearMap )
0278     }
0279 
0280     //make sure to unlock all necessary locks
0281     //important: calling unlock() on an unlocked mutex gives an undefined result
0282     //unlocking a mutex locked by another thread results in an error, so be careful
0283     if( hasTrack ) m_trackMutex.unlock();
0284     if( hasAlbum ) m_albumMutex.unlock();
0285     if( hasArtist ) m_artistMutex.unlock();
0286     if( hasYear ) m_yearMutex.unlock();
0287     if( hasGenre ) m_genreMutex.unlock();
0288     if( hasComposer ) m_composerMutex.unlock();
0289 }*/
0290 
0291 ServiceMetaFactory * ServiceSqlRegistry::factory()
0292 {
0293     return m_metaFactory;
0294 }
0295 
0296 
0297