MythTV  0.26-pre
mythdb.cpp
Go to the documentation of this file.
00001 #include <vector>
00002 using namespace std;
00003 
00004 #include <QReadWriteLock>
00005 #include <QTextStream>
00006 #include <QSqlError>
00007 #include <QMutex>
00008 #include <QFile>
00009 #include <QHash>
00010 #include <QDir>
00011 
00012 #include "mythdb.h"
00013 #include "mythdbcon.h"
00014 #include "mythlogging.h"
00015 #include "mythdirs.h"
00016 #include "mythcorecontext.h"
00017 
00018 static MythDB *mythdb = NULL;
00019 static QMutex dbLock;
00020 
00021 // For thread safety reasons this is not a QString
00022 const char *kSentinelValue = "<settings_sentinel_value>";
00023 const char *kClearSettingValue = "<clear_setting_value>";
00024 
00025 MythDB *MythDB::getMythDB(void)
00026 {
00027     if (mythdb)
00028         return mythdb;
00029 
00030     dbLock.lock();
00031     if (!mythdb)
00032         mythdb = new MythDB();
00033     dbLock.unlock();
00034 
00035     return mythdb;
00036 }
00037 
00038 void MythDB::destroyMythDB(void)
00039 {
00040     dbLock.lock();
00041     delete mythdb;
00042     mythdb = NULL;
00043     dbLock.unlock();
00044 }
00045 
00046 MythDB *GetMythDB(void)
00047 {
00048     return MythDB::getMythDB();
00049 }
00050 
00051 void DestroyMythDB(void)
00052 {
00053     MythDB::destroyMythDB();
00054 }
00055 
00056 struct SingleSetting
00057 {
00058     QString key;
00059     QString value;
00060     QString host;
00061 };
00062 
00063 typedef QHash<QString,QString> SettingsMap;
00064 
00065 class MythDBPrivate
00066 {
00067   public:
00068     MythDBPrivate();
00069    ~MythDBPrivate();
00070 
00071     DatabaseParams  m_DBparams;  
00072     QString m_localhostname;
00073     MDBManager m_dbmanager;
00074 
00075     bool ignoreDatabase;
00076     bool suppressDBMessages;
00077 
00078     QReadWriteLock settingsCacheLock;
00079     volatile bool useSettingsCache;
00081     SettingsMap settingsCache;
00083     SettingsMap overriddenSettings;
00086     QList<SingleSetting> delayedSettings;
00087 
00088     bool haveDBConnection;
00089     bool haveSchema;
00090 };
00091 
00092 static const int settings_reserve = 61;
00093 
00094 MythDBPrivate::MythDBPrivate() :
00095     ignoreDatabase(false), suppressDBMessages(true), useSettingsCache(false),
00096     haveDBConnection(false), haveSchema(false)
00097 {
00098     m_localhostname.clear();
00099     settingsCache.reserve(settings_reserve);
00100 }
00101 
00102 MythDBPrivate::~MythDBPrivate()
00103 {
00104     LOG(VB_DATABASE, LOG_INFO, "Destroying MythDBPrivate");
00105 }
00106 
00107 MythDB::MythDB()
00108 {
00109     d = new MythDBPrivate();
00110 }
00111 
00112 MythDB::~MythDB()
00113 {
00114     delete d;
00115 }
00116 
00117 MDBManager *MythDB::GetDBManager(void)
00118 {
00119     return &(d->m_dbmanager);
00120 }
00121 
00122 QString MythDB::toCommaList(const QMap<QString, QVariant> &bindings,
00123                             uint indent, uint maxColumn)
00124 {
00125     QMap<QString, QVariant>::const_iterator it = bindings.begin();
00126     if (it == bindings.end())
00127         return "";
00128 
00129     uint curColumn = indent;
00130     QString str = QString("%1").arg("", indent);
00131     for (; it != bindings.end(); ++it)
00132     {
00133         QString val = (*it).toString();
00134         if ((*it).isNull())
00135         {
00136             val = "NULL";
00137         }
00138         else if (it->type() == QVariant::String)
00139         {
00140             val = (it->toString().isNull()) ?
00141                 "NULL" : QString("\"%1\"").arg(val);
00142         }
00143         const QString curBinding = it.key() + '=' + val + ',';
00144         if ((curColumn > indent) &&
00145             ((curBinding.length() + curColumn) > maxColumn))
00146         {
00147             str += '\n';
00148             str += QString("%1").arg("", indent);
00149             curColumn = indent;
00150         }
00151         if (curColumn > indent)
00152         {
00153             str += ' ';
00154             curColumn++;
00155         }
00156         str += curBinding;
00157         curColumn += curBinding.length();
00158     }
00159     str = str.left(str.length() - 1); // remove trailing comma.
00160     str += '\n';
00161 
00162     return str;
00163 }
00164 
00165 QString MythDB::GetError(const QString &where, const MSqlQuery &query)
00166 {
00167     QString str = QString("DB Error (%1):\n").arg(where);
00168 
00169     str += "Query was:\n";
00170     str += query.executedQuery() + '\n';
00171     QString tmp = toCommaList(query.boundValues());
00172     if (!tmp.isEmpty())
00173     {
00174         str += "Bindings were:\n";
00175         str += tmp;
00176     }
00177     str += DBErrorMessage(query.lastError());
00178     return str;
00179 }
00180 
00181 void MythDB::DBError(const QString &where, const MSqlQuery &query)
00182 {
00183     LOG(VB_GENERAL, LOG_ERR, GetError(where, query));
00184 }
00185 
00186 QString MythDB::DBErrorMessage(const QSqlError& err)
00187 {
00188     if (!err.type())
00189         return "No error type from QSqlError?  Strange...";
00190 
00191     return QString("Driver error was [%1/%2]:\n"
00192                    "%3\n"
00193                    "Database error was:\n"
00194                    "%4\n")
00195         .arg(err.type())
00196         .arg(err.number())
00197         .arg(err.driverText())
00198         .arg(err.databaseText());
00199 }
00200 
00201 DatabaseParams MythDB::GetDatabaseParams(void) const
00202 {
00203     return d->m_DBparams;
00204 }
00205 
00206 void MythDB::SetDatabaseParams(const DatabaseParams &params)
00207 {
00208     d->m_DBparams = params;
00209 }
00210 
00211 void MythDB::SetLocalHostname(const QString &name)
00212 {
00213     if (d->m_localhostname != name.toLower())
00214     {
00215         d->m_localhostname = name.toLower();
00216         ClearSettingsCache();
00217     }
00218 }
00219 
00220 QString MythDB::GetHostName(void) const
00221 {
00222     return d->m_localhostname;
00223 }
00224 
00225 void MythDB::IgnoreDatabase(bool bIgnore)
00226 {
00227     d->ignoreDatabase = bIgnore;
00228 }
00229 
00230 bool MythDB::IsDatabaseIgnored(void) const
00231 {
00232     return d->ignoreDatabase;
00233 }
00234 
00235 void MythDB::SetSuppressDBMessages(bool bUpgraded)
00236 {
00237     d->suppressDBMessages = bUpgraded;
00238 }
00239 
00240 bool MythDB::SuppressDBMessages(void) const
00241 {
00242     return d->suppressDBMessages;
00243 }
00244 
00245 void MythDB::SaveSetting(const QString &key, int newValue)
00246 {
00247     (void) SaveSettingOnHost(key,
00248                              QString::number(newValue), d->m_localhostname);
00249 }
00250 
00251 void MythDB::SaveSetting(const QString &key, const QString &newValue)
00252 {
00253     (void) SaveSettingOnHost(key, newValue, d->m_localhostname);
00254 }
00255 
00256 bool MythDB::SaveSettingOnHost(const QString &key,
00257                                const QString &newValueRaw,
00258                                const QString &host)
00259 {
00260     QString loc  = QString("SaveSettingOnHost('%1') ").arg(key);
00261     if (key.isEmpty())
00262     {
00263         LOG(VB_GENERAL, LOG_ERR, loc + "- Illegal null key");
00264         return false;
00265     }
00266 
00267     QString newValue = (newValueRaw.isNull()) ? "" : newValueRaw;
00268 
00269     if (d->ignoreDatabase)
00270     {
00271         if (host.toLower() == d->m_localhostname)
00272         {
00273             if (newValue != kClearSettingValue)
00274                 OverrideSettingForSession(key, newValue);
00275             else
00276                 ClearOverrideSettingForSession(key);
00277         }
00278         return true;
00279     }
00280 
00281     if (!HaveValidDatabase())  // Bootstrapping without database?
00282     {
00283         if (host.toLower() == d->m_localhostname)
00284             OverrideSettingForSession(key, newValue);
00285         if (!d->suppressDBMessages)
00286             LOG(VB_GENERAL, LOG_ERR, loc + "- No database yet");
00287         SingleSetting setting;
00288         setting.host = host;
00289         setting.key = key;
00290         setting.value = newValue;
00291         d->delayedSettings.append(setting);
00292         return false;
00293     }
00294 
00295     bool success = false;
00296 
00297     MSqlQuery query(MSqlQuery::InitCon());
00298     if (query.isConnected())
00299     {
00300 
00301         if (!host.isEmpty())
00302             query.prepare("DELETE FROM settings WHERE value = :KEY "
00303                           "AND hostname = :HOSTNAME ;");
00304         else
00305             query.prepare("DELETE FROM settings WHERE value = :KEY "
00306                           "AND hostname is NULL;");
00307 
00308         query.bindValue(":KEY", key);
00309         if (!host.isEmpty())
00310             query.bindValue(":HOSTNAME", host);
00311 
00312         if (!query.exec())
00313         {
00314             if (!GetMythDB()->SuppressDBMessages())
00315                 MythDB::DBError("Clear setting", query);
00316         }
00317         else
00318         {
00319             success = true;
00320         }
00321     }
00322 
00323     if (success && (newValue != kClearSettingValue))
00324     {
00325         if (!host.isEmpty())
00326             query.prepare("INSERT INTO settings (value,data,hostname) "
00327                           "VALUES ( :VALUE, :DATA, :HOSTNAME );");
00328         else
00329             query.prepare("INSERT INTO settings (value,data ) "
00330                           "VALUES ( :VALUE, :DATA );");
00331 
00332         query.bindValue(":VALUE", key);
00333         query.bindValue(":DATA", newValue);
00334         if (!host.isEmpty())
00335             query.bindValue(":HOSTNAME", host);
00336 
00337         if (!query.exec())
00338         {
00339             success = false;
00340             if (!(GetMythDB()->SuppressDBMessages()))
00341                 MythDB::DBError(loc + "- query failure: ", query);
00342         }
00343     }
00344     else if (!success)
00345     {
00346         LOG(VB_GENERAL, LOG_ERR, loc + "- database not open");
00347     }
00348 
00349     ClearSettingsCache(host + ' ' + key);
00350 
00351     return success;
00352 }
00353 
00354 bool MythDB::ClearSetting(const QString &key)
00355 {
00356     return ClearSettingOnHost(key, d->m_localhostname);
00357 }
00358 
00359 bool MythDB::ClearSettingOnHost(const QString &key, const QString &host)
00360 {
00361     return SaveSettingOnHost(key, kClearSettingValue, host);
00362 }
00363 
00364 QString MythDB::GetSetting(const QString &_key, const QString &defaultval)
00365 {
00366     QString key = _key.toLower();
00367     QString value = defaultval;
00368 
00369     d->settingsCacheLock.lockForRead();
00370     if (d->useSettingsCache)
00371     {
00372         SettingsMap::const_iterator it = d->settingsCache.find(key);
00373         if (it != d->settingsCache.end())
00374         {
00375             value = *it;
00376             d->settingsCacheLock.unlock();
00377             return value;
00378         }
00379     }
00380     SettingsMap::const_iterator it = d->overriddenSettings.find(key);
00381     if (it != d->overriddenSettings.end())
00382     {
00383         value = *it;
00384         d->settingsCacheLock.unlock();
00385         return value;
00386     }
00387     d->settingsCacheLock.unlock();
00388 
00389     if (d->ignoreDatabase || !HaveValidDatabase())
00390         return value;
00391 
00392     MSqlQuery query(MSqlQuery::InitCon());
00393     if (!query.isConnected())
00394         return value;
00395 
00396     query.prepare(
00397         "SELECT data "
00398         "FROM settings "
00399         "WHERE value = :KEY AND hostname = :HOSTNAME");
00400     query.bindValue(":KEY", key);
00401     query.bindValue(":HOSTNAME", d->m_localhostname);
00402 
00403     if (query.exec() && query.next())
00404     {
00405         value = query.value(0).toString();
00406     }
00407     else
00408     {
00409         query.prepare(
00410             "SELECT data "
00411             "FROM settings "
00412             "WHERE value = :KEY AND hostname IS NULL");
00413         query.bindValue(":KEY", key);
00414 
00415         if (query.exec() && query.next())
00416         {
00417             value = query.value(0).toString();
00418         }
00419     }
00420 
00421     if (d->useSettingsCache && value != kSentinelValue)
00422     {
00423         key.squeeze();
00424         value.squeeze();
00425         d->settingsCacheLock.lockForWrite();
00426         // another thread may have inserted a value into the cache
00427         // while we did not have the lock, check first then save
00428         if (d->settingsCache.find(key) == d->settingsCache.end())
00429             d->settingsCache[key] = value;
00430         d->settingsCacheLock.unlock();
00431     }
00432 
00433     return value;
00434 }
00435 
00436 bool MythDB::GetSettings(QMap<QString,QString> &_key_value_pairs)
00437 {
00438     QMap<QString,bool> done;
00439     typedef QMap<QString,QString>::iterator KVIt;
00440     KVIt kvit = _key_value_pairs.begin();
00441     for (; kvit != _key_value_pairs.end(); ++kvit)
00442         done[kvit.key().toLower()] = false;
00443 
00444     QMap<QString,bool>::iterator dit = done.begin();
00445     kvit = _key_value_pairs.begin();
00446 
00447     {
00448         uint done_cnt = 0;
00449         d->settingsCacheLock.lockForRead();
00450         if (d->useSettingsCache)
00451         {
00452             for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
00453             {
00454                 SettingsMap::const_iterator it = d->settingsCache.find(dit.key());
00455                 if (it != d->settingsCache.end())
00456                 {
00457                     *kvit = *it;
00458                     *dit = true;
00459                     done_cnt++;
00460                 }
00461             }
00462         }
00463         for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
00464         {
00465             SettingsMap::const_iterator it =
00466                 d->overriddenSettings.find(dit.key());
00467             if (it != d->overriddenSettings.end())
00468             {
00469                 *kvit = *it;
00470                 *dit = true;
00471                 done_cnt++;
00472             }
00473         }
00474         d->settingsCacheLock.unlock();
00475 
00476         // Avoid extra work if everything was in the caches and
00477         // also don't try to access the DB if ignoreDatabase is set
00478         if (((uint)done.size()) == done_cnt || d->ignoreDatabase)
00479             return true;
00480     }
00481 
00482     dit = done.begin();
00483     kvit = _key_value_pairs.begin();
00484 
00485     QString keylist("");
00486     QMap<QString,KVIt> keymap;
00487     for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
00488     {
00489         if (*dit)
00490             continue;
00491 
00492         QString key = dit.key();
00493         if (!key.contains("'"))
00494         {
00495             keylist += QString("'%1',").arg(key);
00496             keymap[key] = kvit;
00497         }
00498         else
00499         {   // hopefully no one actually uses quotes for in a settings key.
00500             // but in case they do, just get that value inefficiently..
00501             *kvit = GetSetting(key, *kvit);
00502         }
00503     }
00504 
00505     if (keylist.isEmpty())
00506         return true;
00507 
00508     keylist = keylist.left(keylist.length() - 1);
00509 
00510     MSqlQuery query(MSqlQuery::InitCon());
00511     if (!query.exec(
00512             QString(
00513                 "SELECT value, data, hostname "
00514                 "FROM settings "
00515                 "WHERE (hostname = '%1' OR hostname IS NULL) AND "
00516                 "      value IN (%2) "
00517                 "ORDER BY hostname DESC")
00518             .arg(d->m_localhostname).arg(keylist)))
00519     {
00520         if (!d->suppressDBMessages)
00521             DBError("GetSettings", query);
00522         return false;
00523     }
00524 
00525     while (query.next())
00526     {
00527         QString key = query.value(0).toString().toLower();
00528         QMap<QString,KVIt>::const_iterator it = keymap.find(key);
00529         if (it != keymap.end())
00530             **it = query.value(1).toString();
00531     }
00532 
00533     if (d->useSettingsCache)
00534     {
00535         d->settingsCacheLock.lockForWrite();
00536         QMap<QString,KVIt>::const_iterator it = keymap.begin();
00537         for (; it != keymap.end(); ++it)
00538         {
00539             QString key = it.key(), value = **it;
00540 
00541             // another thread may have inserted a value into the cache
00542             // while we did not have the lock, check first then save
00543             if (d->settingsCache.find(key) == d->settingsCache.end())
00544             {
00545                 key.squeeze();
00546                 value.squeeze();
00547                 d->settingsCache[key] = value;
00548             }
00549         }
00550         d->settingsCacheLock.unlock();
00551     }
00552 
00553     return true;
00554 }
00555 
00556 
00557 int MythDB::GetNumSetting(const QString &key, int defaultval)
00558 {
00559     QString val = QString::number(defaultval);
00560     QString retval = GetSetting(key, val);
00561 
00562     return retval.toInt();
00563 }
00564 
00565 double MythDB::GetFloatSetting(const QString &key, double defaultval)
00566 {
00567     QString val = QString::number(defaultval);
00568     QString retval = GetSetting(key, val);
00569 
00570     return retval.toDouble();
00571 }
00572 
00573 QString MythDB::GetSetting(const QString &key)
00574 {
00575     QString sentinel = QString(kSentinelValue);
00576     QString retval = GetSetting(key, sentinel);
00577     return (retval == sentinel) ? "" : retval;
00578 }
00579 
00580 int MythDB::GetNumSetting(const QString &key)
00581 {
00582     QString sentinel = QString(kSentinelValue);
00583     QString retval = GetSetting(key, sentinel);
00584     return (retval == sentinel) ? 0 : retval.toInt();
00585 }
00586 
00587 double MythDB::GetFloatSetting(const QString &key)
00588 {
00589     QString sentinel = QString(kSentinelValue);
00590     QString retval = GetSetting(key, sentinel);
00591     return (retval == sentinel) ? 0.0 : retval.toDouble();
00592 }
00593 
00594 QString MythDB::GetSettingOnHost(const QString &_key, const QString &_host,
00595                                  const QString &defaultval)
00596 {
00597     QString key   = _key.toLower();
00598     QString host  = _host.toLower();
00599     QString value = defaultval;
00600     QString myKey = host + ' ' + key;
00601 
00602     d->settingsCacheLock.lockForRead();
00603     if (d->useSettingsCache)
00604     {
00605         SettingsMap::const_iterator it = d->settingsCache.find(myKey);
00606         if (it != d->settingsCache.end())
00607         {
00608             value = *it;
00609             d->settingsCacheLock.unlock();
00610             return value;
00611         }
00612     }
00613     SettingsMap::const_iterator it = d->overriddenSettings.find(myKey);
00614     if (it != d->overriddenSettings.end())
00615     {
00616         value = *it;
00617         d->settingsCacheLock.unlock();
00618         return value;
00619     }
00620     d->settingsCacheLock.unlock();
00621 
00622     if (d->ignoreDatabase)
00623         return value;
00624 
00625     MSqlQuery query(MSqlQuery::InitCon());
00626     if (!query.isConnected())
00627     {
00628         if (!d->suppressDBMessages)
00629             LOG(VB_GENERAL, LOG_ERR,
00630                 QString("Database not open while trying to "
00631                         "load setting: %1").arg(key));
00632         return value;
00633     }
00634 
00635     query.prepare(
00636         "SELECT data "
00637         "FROM settings "
00638         "WHERE value = :VALUE AND hostname = :HOSTNAME");
00639     query.bindValue(":VALUE", key);
00640     query.bindValue(":HOSTNAME", host);
00641 
00642     if (query.exec() && query.next())
00643     {
00644         value = query.value(0).toString();
00645     }
00646 
00647     if (d->useSettingsCache && value != kSentinelValue)
00648     {
00649         myKey.squeeze();
00650         value.squeeze();
00651         d->settingsCacheLock.lockForWrite();
00652         if (d->settingsCache.find(myKey) == d->settingsCache.end())
00653             d->settingsCache[myKey] = value;
00654         d->settingsCacheLock.unlock();
00655     }
00656 
00657     return value;
00658 }
00659 
00660 int MythDB::GetNumSettingOnHost(const QString &key, const QString &host,
00661                                      int defaultval)
00662 {
00663     QString val = QString::number(defaultval);
00664     QString retval = GetSettingOnHost(key, host, val);
00665 
00666     return retval.toInt();
00667 }
00668 
00669 double MythDB::GetFloatSettingOnHost(
00670     const QString &key, const QString &host, double defaultval)
00671 {
00672     QString val = QString::number(defaultval);
00673     QString retval = GetSettingOnHost(key, host, val);
00674 
00675     return retval.toDouble();
00676 }
00677 
00678 QString MythDB::GetSettingOnHost(const QString &key, const QString &host)
00679 {
00680     QString sentinel = QString(kSentinelValue);
00681     QString retval = GetSettingOnHost(key, host, sentinel);
00682     return (retval == sentinel) ? "" : retval;
00683 }
00684 
00685 int MythDB::GetNumSettingOnHost(const QString &key, const QString &host)
00686 {
00687     QString sentinel = QString(kSentinelValue);
00688     QString retval = GetSettingOnHost(key, host, sentinel);
00689     return (retval == sentinel) ? 0 : retval.toInt();
00690 }
00691 
00692 double MythDB::GetFloatSettingOnHost(const QString &key, const QString &host)
00693 {
00694     QString sentinel = QString(kSentinelValue);
00695     QString retval = GetSettingOnHost(key, host, sentinel);
00696     return (retval == sentinel) ? 0.0 : retval.toDouble();
00697 }
00698 
00699 void MythDB::GetResolutionSetting(const QString &type,
00700                                        int &width, int &height,
00701                                        double &forced_aspect,
00702                                        double &refresh_rate,
00703                                        int index)
00704 {
00705     bool ok = false, ok0 = false, ok1 = false;
00706     QString sRes =    QString("%1Resolution").arg(type);
00707     QString sRR =     QString("%1RefreshRate").arg(type);
00708     QString sAspect = QString("%1ForceAspect").arg(type);
00709     QString sWidth =  QString("%1Width").arg(type);
00710     QString sHeight = QString("%1Height").arg(type);
00711     if (index >= 0)
00712     {
00713         sRes =    QString("%1Resolution%2").arg(type).arg(index);
00714         sRR =     QString("%1RefreshRate%2").arg(type).arg(index);
00715         sAspect = QString("%1ForceAspect%2").arg(type).arg(index);
00716         sWidth =  QString("%1Width%2").arg(type).arg(index);
00717         sHeight = QString("%1Height%2").arg(type).arg(index);
00718     }
00719 
00720     QString res = GetSetting(sRes);
00721 
00722     if (!res.isEmpty())
00723     {
00724         QStringList slist = res.split(QString("x"));
00725         int w = width, h = height;
00726         if (2 == slist.size())
00727         {
00728             w = slist[0].toInt(&ok0);
00729             h = slist[1].toInt(&ok1);
00730         }
00731         bool ok = ok0 && ok1;
00732         if (ok)
00733         {
00734             width = w;
00735             height = h;
00736             refresh_rate = GetFloatSetting(sRR);
00737             forced_aspect = GetFloatSetting(sAspect);
00738         }
00739     }
00740     else
00741 
00742     if (!ok)
00743     {
00744         int tmpWidth = GetNumSetting(sWidth, width);
00745         if (tmpWidth)
00746             width = tmpWidth;
00747 
00748         int tmpHeight = GetNumSetting(sHeight, height);
00749         if (tmpHeight)
00750             height = tmpHeight;
00751 
00752         refresh_rate = 0.0;
00753         forced_aspect = 0.0;
00754         //SetSetting(sRes, QString("%1x%2").arg(width).arg(height));
00755     }
00756 }
00757 
00758 void MythDB::GetResolutionSetting(const QString &t, int &w, int &h, int i)
00759 {
00760     double forced_aspect = 0;
00761     double refresh_rate = 0.0;
00762     GetResolutionSetting(t, w, h, forced_aspect, refresh_rate, i);
00763 }
00764 
00765 
00772 void MythDB::OverrideSettingForSession(
00773     const QString &key, const QString &value)
00774 {
00775     QString mk = key.toLower(), mk2 = d->m_localhostname + ' ' + mk, mv = value;
00776     if ("dbschemaver" == mk)
00777     {
00778         LOG(VB_GENERAL, LOG_ERR, 
00779             QString("ERROR: Refusing to allow override for '%1'.").arg(key));
00780         return;
00781     }
00782     mk.squeeze();
00783     mk2.squeeze();
00784     mv.squeeze();
00785 
00786     d->settingsCacheLock.lockForWrite();
00787     d->overriddenSettings[mk] = mv;
00788     d->settingsCache[mk]      = mv;
00789     d->settingsCache[mk2]     = mv;
00790     d->settingsCacheLock.unlock();
00791 }
00792 
00794 void MythDB::ClearOverrideSettingForSession(const QString &key)
00795 {
00796     QString mk = key.toLower();
00797     QString mk2 = d->m_localhostname + ' ' + mk;
00798 
00799     d->settingsCacheLock.lockForWrite();
00800 
00801     SettingsMap::iterator oit = d->overriddenSettings.find(mk);
00802     if (oit != d->overriddenSettings.end())
00803         d->overriddenSettings.erase(oit);
00804 
00805     SettingsMap::iterator sit = d->settingsCache.find(mk);
00806     if (sit != d->settingsCache.end())
00807         d->settingsCache.erase(sit);
00808 
00809     sit = d->settingsCache.find(mk2);
00810     if (sit != d->settingsCache.end())
00811         d->settingsCache.erase(sit);
00812 
00813     d->settingsCacheLock.unlock();
00814 }
00815 
00816 static void clear(
00817     SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
00818 {
00819     // Do the actual clearing..
00820     SettingsMap::iterator it = cache.find(myKey);
00821     if (it != cache.end())
00822     {
00823         SettingsMap::const_iterator oit = overrides.find(myKey);
00824         if (oit == overrides.end())
00825         {
00826             LOG(VB_DATABASE, LOG_INFO,
00827                     QString("Clearing Settings Cache for '%1'.").arg(myKey));
00828             cache.erase(it);
00829         }
00830         else
00831         {
00832             LOG(VB_DATABASE, LOG_INFO,
00833                     QString("Clearing Cache of overridden '%1' ignored.")
00834                     .arg(myKey));
00835         }
00836     }
00837 }
00838 
00839 void MythDB::ClearSettingsCache(const QString &_key)
00840 {
00841     d->settingsCacheLock.lockForWrite();
00842 
00843     if (_key.isEmpty())
00844     {
00845         LOG(VB_DATABASE, LOG_INFO, "Clearing Settings Cache.");
00846         d->settingsCache.clear();
00847         d->settingsCache.reserve(settings_reserve);
00848 
00849         SettingsMap::const_iterator it = d->overriddenSettings.begin();
00850         for (; it != d->overriddenSettings.end(); ++it)
00851         {
00852             QString mk2 = d->m_localhostname + ' ' + it.key();
00853             mk2.squeeze();
00854 
00855             d->settingsCache[it.key()] = *it;
00856             d->settingsCache[mk2] = *it;
00857         }
00858     }
00859     else
00860     {
00861         QString myKey = _key.toLower();
00862         clear(d->settingsCache, d->overriddenSettings, myKey);
00863 
00864         // To be safe always clear any local[ized] version too
00865         QString mkl = myKey.section(QChar(' '), 1);
00866         if (!mkl.isEmpty())
00867             clear(d->settingsCache, d->overriddenSettings, mkl);
00868     }
00869 
00870     d->settingsCacheLock.unlock();
00871 }
00872 
00873 void MythDB::ActivateSettingsCache(bool activate)
00874 {
00875     if (activate)
00876         LOG(VB_DATABASE, LOG_INFO, "Enabling Settings Cache.");
00877     else
00878         LOG(VB_DATABASE, LOG_INFO, "Disabling Settings Cache.");
00879 
00880     d->useSettingsCache = activate;
00881     ClearSettingsCache();
00882 }
00883 
00884 void MythDB::WriteDelayedSettings(void)
00885 {
00886     if (!HaveValidDatabase())
00887         return;
00888 
00889     if (!gCoreContext->IsUIThread())
00890         return;
00891 
00892     while (!d->delayedSettings.isEmpty())
00893     {
00894         SingleSetting setting = d->delayedSettings.takeFirst();
00895         SaveSettingOnHost(setting.key, setting.value, setting.host);
00896     }
00897 }
00898 
00902 void MythDB::SetHaveDBConnection(bool connected)
00903 {
00904     d->haveDBConnection = connected;
00905 }
00906 
00911 void MythDB::SetHaveSchema(bool schema)
00912 {
00913     d->haveSchema = schema;
00914 }
00915 
00923 bool MythDB::HaveSchema(void) const
00924 {
00925     return d->haveSchema;
00926 }
00927 
00935 bool MythDB::HaveValidDatabase(void) const
00936 {
00937     return (d->haveDBConnection && d->haveSchema);
00938 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends