mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-22 16:26:52 +00:00
Ignore database actions after IO error.
This commit is contained in:
parent
4769a1a49f
commit
adcc11c474
@ -106,37 +106,39 @@ Error DatabaseObject::ioError(const QString &path) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseObject::open(EncryptionKey key, FnMut<void(Error)> done) {
|
void DatabaseObject::open(EncryptionKey key, FnMut<void(Error)> done) {
|
||||||
|
close(nullptr);
|
||||||
|
|
||||||
|
const auto error = openSomeBinlog(key);
|
||||||
|
if (error.type != Error::Type::None) {
|
||||||
|
close(nullptr);
|
||||||
|
}
|
||||||
|
invokeCallback(done, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error DatabaseObject::openSomeBinlog(EncryptionKey &key) {
|
||||||
const auto version = readVersion();
|
const auto version = readVersion();
|
||||||
const auto result = openBinlog(version, File::Mode::ReadAppend, key);
|
const auto result = openBinlog(version, File::Mode::ReadAppend, key);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case File::Result::Success:
|
case File::Result::Success: return Error::NoError();
|
||||||
invokeCallback(done, Error::NoError());
|
case File::Result::Failed: return openNewBinlog(key);
|
||||||
break;
|
|
||||||
case File::Result::LockFailed:
|
case File::Result::LockFailed:
|
||||||
invokeCallback(
|
return Error{ Error::Type::LockFailed, binlogPath(version) };
|
||||||
done,
|
|
||||||
Error{ Error::Type::LockFailed, binlogPath(version) });
|
|
||||||
break;
|
|
||||||
case File::Result::WrongKey:
|
case File::Result::WrongKey:
|
||||||
invokeCallback(
|
return Error{ Error::Type::WrongKey, binlogPath(version) };
|
||||||
done,
|
|
||||||
Error{ Error::Type::WrongKey, binlogPath(version) });
|
|
||||||
break;
|
|
||||||
case File::Result::Failed: {
|
|
||||||
const auto available = findAvailableVersion();
|
|
||||||
if (writeVersion(available)) {
|
|
||||||
const auto open = openBinlog(available, File::Mode::Write, key);
|
|
||||||
if (open == File::Result::Success) {
|
|
||||||
invokeCallback(done, Error::NoError());
|
|
||||||
} else {
|
|
||||||
invokeCallback(done, ioError(binlogPath(available)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
invokeCallback(done, ioError(versionPath()));
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default: Unexpected("Result from DatabaseObject::openBinlog.");
|
|
||||||
}
|
}
|
||||||
|
Unexpected("Result from DatabaseObject::openBinlog.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Error DatabaseObject::openNewBinlog(EncryptionKey &key) {
|
||||||
|
const auto available = findAvailableVersion();
|
||||||
|
if (!writeVersion(available)) {
|
||||||
|
return ioError(versionPath());
|
||||||
|
}
|
||||||
|
const auto open = openBinlog(available, File::Mode::Write, key);
|
||||||
|
if (open != File::Result::Success) {
|
||||||
|
return ioError(binlogPath(available));
|
||||||
|
}
|
||||||
|
return Error::NoError();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DatabaseObject::computePath(Version version) const {
|
QString DatabaseObject::computePath(Version version) const {
|
||||||
@ -177,19 +179,20 @@ File::Result DatabaseObject::openBinlog(
|
|||||||
return File::Result::Failed;
|
return File::Result::Failed;
|
||||||
}
|
}
|
||||||
const auto result = _binlog.open(path, mode, key);
|
const auto result = _binlog.open(path, mode, key);
|
||||||
if (result == File::Result::Success) {
|
if (result != File::Result::Success) {
|
||||||
const auto headerRequired = (mode == File::Mode::Read)
|
return result;
|
||||||
|| (mode == File::Mode::ReadAppend && _binlog.size() > 0);
|
|
||||||
if (headerRequired ? readHeader() : writeHeader()) {
|
|
||||||
_path = computePath(version);
|
|
||||||
_key = std::move(key);
|
|
||||||
createCleaner();
|
|
||||||
readBinlog();
|
|
||||||
} else {
|
|
||||||
return File::Result::Failed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
const auto headerRequired = (mode == File::Mode::Read)
|
||||||
|
|| (mode == File::Mode::ReadAppend && _binlog.size() > 0);
|
||||||
|
const auto headerResult = headerRequired ? readHeader() : writeHeader();
|
||||||
|
if (!headerResult) {
|
||||||
|
return File::Result::Failed;
|
||||||
|
}
|
||||||
|
_path = computePath(version);
|
||||||
|
_key = std::move(key);
|
||||||
|
createCleaner();
|
||||||
|
readBinlog();
|
||||||
|
return File::Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseObject::readHeader() {
|
bool DatabaseObject::readHeader() {
|
||||||
@ -575,13 +578,15 @@ void DatabaseObject::compactorDone(
|
|||||||
});
|
});
|
||||||
_binlog.close();
|
_binlog.close();
|
||||||
if (!File::Move(ready, binlog)) {
|
if (!File::Move(ready, binlog)) {
|
||||||
// megafail
|
|
||||||
compactorFail();
|
compactorFail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto result = _binlog.open(binlog, File::Mode::ReadAppend, _key);
|
const auto result = _binlog.open(binlog, File::Mode::ReadAppend, _key);
|
||||||
if (result != File::Result::Success || !_binlog.seek(_binlog.size())) {
|
if (result != File::Result::Success) {
|
||||||
// megafail
|
compactorFail();
|
||||||
|
return;
|
||||||
|
} else if (!_binlog.seek(_binlog.size())) {
|
||||||
|
_binlog.close();
|
||||||
compactorFail();
|
compactorFail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -600,7 +605,9 @@ void DatabaseObject::compactorFail() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseObject::close(FnMut<void()> done) {
|
void DatabaseObject::close(FnMut<void()> done) {
|
||||||
writeBundles();
|
if (_binlog.isOpen()) {
|
||||||
|
writeBundles();
|
||||||
|
}
|
||||||
_cleaner = CleanerWrap();
|
_cleaner = CleanerWrap();
|
||||||
_compactor = CompactorWrap();
|
_compactor = CompactorWrap();
|
||||||
_binlog.close();
|
_binlog.close();
|
||||||
@ -692,6 +699,7 @@ base::optional<QString> DatabaseObject::writeKeyPlaceGeneric(
|
|||||||
auto writeable = record;
|
auto writeable = record;
|
||||||
const auto success = _binlog.write(bytes::object_as_span(&writeable));
|
const auto success = _binlog.write(bytes::object_as_span(&writeable));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
_binlog.close();
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
_binlog.flush();
|
_binlog.flush();
|
||||||
@ -905,7 +913,7 @@ void DatabaseObject::checkCompactor() {
|
|||||||
&& (_binlogExcessLength * _settings.compactAfterFullSize
|
&& (_binlogExcessLength * _settings.compactAfterFullSize
|
||||||
< _settings.compactAfterExcess * _binlog.size())) {
|
< _settings.compactAfterExcess * _binlog.size())) {
|
||||||
return;
|
return;
|
||||||
} else if (crl::time() < _compactor.nextAttempt) {
|
} else if (crl::time() < _compactor.nextAttempt || !_binlog.isOpen()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto info = Compactor::Info();
|
auto info = Compactor::Info();
|
||||||
|
@ -88,6 +88,8 @@ private:
|
|||||||
QString binlogPath() const;
|
QString binlogPath() const;
|
||||||
QString compactReadyPath(Version version) const;
|
QString compactReadyPath(Version version) const;
|
||||||
QString compactReadyPath() const;
|
QString compactReadyPath() const;
|
||||||
|
Error openSomeBinlog(EncryptionKey &key);
|
||||||
|
Error openNewBinlog(EncryptionKey &key);
|
||||||
File::Result openBinlog(
|
File::Result openBinlog(
|
||||||
Version version,
|
Version version,
|
||||||
File::Mode mode,
|
File::Mode mode,
|
||||||
|
@ -18,9 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
using namespace Storage::Cache;
|
using namespace Storage::Cache;
|
||||||
|
|
||||||
const auto DisableLimitsTests = true;
|
const auto DisableLimitsTests = false;
|
||||||
const auto DisableCompactTests = true;
|
const auto DisableCompactTests = false;
|
||||||
const auto DisableLargeTest = false;
|
const auto DisableLargeTest = true;
|
||||||
|
|
||||||
const auto key = Storage::EncryptionKey(bytes::make_vector(
|
const auto key = Storage::EncryptionKey(bytes::make_vector(
|
||||||
bytes::make_span("\
|
bytes::make_span("\
|
||||||
|
@ -206,6 +206,9 @@ size_type File::read(bytes::span bytes) {
|
|||||||
bool File::write(bytes::span bytes) {
|
bool File::write(bytes::span bytes) {
|
||||||
Expects(bytes.size() % kBlockSize == 0);
|
Expects(bytes.size() % kBlockSize == 0);
|
||||||
|
|
||||||
|
if (!isOpen()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
encrypt(bytes);
|
encrypt(bytes);
|
||||||
const auto count = writePlain(bytes);
|
const auto count = writePlain(bytes);
|
||||||
if (count == bytes.size()) {
|
if (count == bytes.size()) {
|
||||||
@ -288,6 +291,10 @@ void File::close() {
|
|||||||
_state = base::none;
|
_state = base::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool File::isOpen() const {
|
||||||
|
return _data.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
int64 File::size() const {
|
int64 File::size() const {
|
||||||
return _dataSize;
|
return _dataSize;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ public:
|
|||||||
|
|
||||||
bool flush();
|
bool flush();
|
||||||
|
|
||||||
|
bool isOpen() const;
|
||||||
int64 size() const;
|
int64 size() const;
|
||||||
int64 offset() const;
|
int64 offset() const;
|
||||||
bool seek(int64 offset);
|
bool seek(int64 offset);
|
||||||
|
Loading…
Reference in New Issue
Block a user