Backup: release the held index cache writes also when the dump transaction fails to start
holdIndexCache() ran before beginTransaction(), outside the try, and the release came after rollBack(); an exception from either left later cache writes queued for the rest of the run.
This commit is contained in:
+39
-36
@@ -75,50 +75,53 @@ final class DbDumper {
|
|||||||
// A pack that fills up during the dump is uploaded right away; its index cache row must
|
// A pack that fills up during the dump is uploaded right away; its index cache row must
|
||||||
// wait until the read-only transaction is over.
|
// wait until the read-only transaction is over.
|
||||||
$repo->holdIndexCache();
|
$repo->holdIndexCache();
|
||||||
$this->db->setTransactionIsolation(TransactionIsolationLevel::REPEATABLE_READ);
|
|
||||||
$this->db->beginTransaction();
|
|
||||||
try {
|
try {
|
||||||
if ($this->db->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\PostgreSQLPlatform) {
|
$this->db->setTransactionIsolation(TransactionIsolationLevel::REPEATABLE_READ);
|
||||||
$this->db->executeStatement('SET TRANSACTION READ ONLY');
|
$this->db->beginTransaction();
|
||||||
}
|
try {
|
||||||
while ($state['i'] < count($state['tables'])) {
|
if ($this->db->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\PostgreSQLPlatform) {
|
||||||
$table = $state['tables'][$state['i']];
|
$this->db->executeStatement('SET TRANSACTION READ ONLY');
|
||||||
$schema = $sm->introspectTable($table);
|
|
||||||
$writer = $repo->blobWriter($stats);
|
|
||||||
$hash = $state['hash'] !== null ? unserialize(base64_decode($state['hash']), ['allowed_classes' => [\HashContext::class]]) : hash_init('sha256');
|
|
||||||
if ($state['after'] === null && $state['segments'] === []) {
|
|
||||||
$writer->write($this->header($schema) . "\n");
|
|
||||||
}
|
}
|
||||||
$complete = true;
|
while ($state['i'] < count($state['tables'])) {
|
||||||
foreach ($this->rowLines($schema, $state['after']) as [$key, $line]) {
|
$table = $state['tables'][$state['i']];
|
||||||
$writer->write($line . "\n");
|
$schema = $sm->introspectTable($table);
|
||||||
hash_update($hash, $line . "\n");
|
$writer = $repo->blobWriter($stats);
|
||||||
$state['rows']++;
|
$hash = $state['hash'] !== null ? unserialize(base64_decode($state['hash']), ['allowed_classes' => [\HashContext::class]]) : hash_init('sha256');
|
||||||
$state['after'] = $key;
|
if ($state['after'] === null && $state['segments'] === []) {
|
||||||
if (microtime(true) >= $deadline) {
|
$writer->write($this->header($schema) . "\n");
|
||||||
$complete = false;
|
}
|
||||||
|
$complete = true;
|
||||||
|
foreach ($this->rowLines($schema, $state['after']) as [$key, $line]) {
|
||||||
|
$writer->write($line . "\n");
|
||||||
|
hash_update($hash, $line . "\n");
|
||||||
|
$state['rows']++;
|
||||||
|
$state['after'] = $key;
|
||||||
|
if (microtime(true) >= $deadline) {
|
||||||
|
$complete = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$state['segments'][] = $writer->finish();
|
||||||
|
$state['bytes'] += $writer->bytes();
|
||||||
|
if (!$complete) {
|
||||||
|
$state['hash'] = base64_encode(serialize($hash));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$state['result'][$table] = ['blobs' => array_merge(...$state['segments']), 'rows' => $state['rows'],
|
||||||
|
'bytes' => $state['bytes'], 'sha256' => hash_final($hash)];
|
||||||
|
$state = array_merge($state, ['i' => $state['i'] + 1, 'after' => null, 'segments' => [], 'rows' => 0, 'bytes' => 0, 'hash' => null]);
|
||||||
|
if (microtime(true) >= $deadline && $state['i'] < count($state['tables'])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$state['segments'][] = $writer->finish();
|
if ($state['i'] >= count($state['tables'])) {
|
||||||
$state['bytes'] += $writer->bytes();
|
$state['sequences'] = $this->sequenceStates($state['tables']);
|
||||||
if (!$complete) {
|
$state['done'] = true;
|
||||||
$state['hash'] = base64_encode(serialize($hash));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
$state['result'][$table] = ['blobs' => array_merge(...$state['segments']), 'rows' => $state['rows'],
|
} finally {
|
||||||
'bytes' => $state['bytes'], 'sha256' => hash_final($hash)];
|
$this->db->rollBack();
|
||||||
$state = array_merge($state, ['i' => $state['i'] + 1, 'after' => null, 'segments' => [], 'rows' => 0, 'bytes' => 0, 'hash' => null]);
|
|
||||||
if (microtime(true) >= $deadline && $state['i'] < count($state['tables'])) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($state['i'] >= count($state['tables'])) {
|
|
||||||
$state['sequences'] = $this->sequenceStates($state['tables']);
|
|
||||||
$state['done'] = true;
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
$this->db->rollBack();
|
|
||||||
$repo->releaseIndexCache();
|
$repo->releaseIndexCache();
|
||||||
}
|
}
|
||||||
$repo->flushPacks();
|
$repo->flushPacks();
|
||||||
|
|||||||
Reference in New Issue
Block a user