Skip to content

Commit

Permalink
fixup! fix(db): also chunk MariaDB deletes
Browse files Browse the repository at this point in the history
  • Loading branch information
miaulalala committed Sep 11, 2023
1 parent cbda147 commit 83f56ae
Showing 1 changed file with 65 additions and 21 deletions.
86 changes: 65 additions & 21 deletions lib/Data.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
Expand Down Expand Up @@ -49,14 +51,16 @@ class Data {

/** @var ?IQueryBuilder */
protected $insertMail;
private LoggerInterface $logger;

/**
* @param IManager $activityManager
* @param IDBConnection $connection
*/
public function __construct(IManager $activityManager, IDBConnection $connection) {
public function __construct(IManager $activityManager, IDBConnection $connection, LoggerInterface $logger) {
$this->activityManager = $activityManager;
$this->connection = $connection;
$this->logger = $logger;
}

/**
Expand Down Expand Up @@ -369,9 +373,16 @@ public function expire($expireDays = 365) {
* 'field' => 'value' => `field` = 'value'
* 'field' => array('value', 'operator') => `field` operator 'value'
*/
public function deleteActivities($conditions) {
$delete = $this->connection->getQueryBuilder();
$delete->delete('activity');
public function deleteActivities($conditions): void {
$platform = $this->connection->getDatabasePlatform();
if($platform instanceof MySQLPlatform) {
$this->logger->debug('Choosing chunked activity delete for MySQL/MariaDB', ['app' => 'activity']);
$this->deleteActivitiesForMySQL($conditions);
return;
}
$this->logger->debug('Choosing regular activity delete', ['app' => 'activity']);
$deleteQuery = $this->connection->getQueryBuilder();
$deleteQuery->delete('activity');

foreach ($conditions as $column => $comparison) {
if (is_array($comparison)) {
Expand All @@ -382,25 +393,14 @@ public function deleteActivities($conditions) {
$value = $comparison;
}

$delete->andWhere($delete->expr()->comparison($column, $operation, $delete->createNamedParameter($value)));
$deleteQuery->andWhere($deleteQuery->expr()->comparison($column, $operation, $deleteQuery->createNamedParameter($value)));
}

// Add galera safe delete chunking if using mysql
// Stops us hitting wsrep_max_ws_rows when large row counts are deleted
$platform = $this->connection->getDatabasePlatform();
if ($platform instanceof MySQLPlatform) {
$logger = \OC::$server->get(LoggerInterface::class);
$logger->log('Chunking deletes for MySQLPlatform');
// Then use chunked delete
$max = 10000;
$delete->setMaxResults($max);
do {
$deleted = $delete->executeStatement();
} while ($deleted === $max);
} else {
// Dont use chunked delete - let the DB handle the large row count natively
$delete->executeStatement();
}



// Dont use chunked delete - let the DB handle the large row count natively
$deleteQuery->executeStatement();
}

public function getById(int $activityId): ?IEvent {
Expand Down Expand Up @@ -471,4 +471,48 @@ public function getActivitySince(string $user, int $since, bool $byOthers) {

return $query->execute()->fetch();
}

/**
* Add galera safe delete chunking if using mysql
* Stops us hitting wsrep_max_ws_rows when large row counts are deleted
*
* @param array $conditions
* @return void
*/
private function deleteActivitiesForMySQL(array $conditions): void {
$query = $this->connection->getQueryBuilder();
$query->select('activity_id')
->from('activity');

foreach ($conditions as $column => $comparison) {
if (is_array($comparison)) {
$operation = $comparison[1] ?? '=';
$value = $comparison[0];
} else {
$operation = '=';
$value = $comparison;
}
$query->where($query->expr()->comparison($column, $operation, $query->createNamedParameter($value)));
}

$query->setMaxResults(10000);
$result = $query->executeQuery();
$count = $result->rowCount();
if($count === 0) {
return;
}
$ids = array_map(static function (array $id) {
return (int)$id[0];
}, $result->fetchAll(\PDO::FETCH_NUM));
$result->closeCursor();

$deleteQuery = $this->connection->getQueryBuilder();
$deleteQuery->delete('activity');
$deleteQuery->where($deleteQuery->expr()->in('activity_id', $deleteQuery->createParameter('ids'), IQueryBuilder::PARAM_STR_ARRAY));
$deleteQuery->setParameter('ids', $ids, IQueryBuilder::PARAM_STR_ARRAY);
$queryResult = $deleteQuery->executeStatement();
if($queryResult === 10000) {
$this->deleteActivitiesForMySQL($conditions);
}
}
}

0 comments on commit 83f56ae

Please sign in to comment.