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
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);
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 ¶ms)
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())
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
00427
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
00477
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 {
00500
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
00542
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
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
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
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 }