Browse Source

Add a method to lock a table

tags/v9.1.0beta1
Joas Schilling 8 years ago
parent
commit
7e3ce83526
No account linked to committer's email address

+ 16
- 1
lib/private/AppFramework/Db/Db.php View File

@@ -29,6 +29,7 @@ namespace OC\AppFramework\Db;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDb;
use OCP\IDBConnection;
use OCP\PreConditionNotMetException;

/**
* @deprecated use IDBConnection directly, will be removed in ownCloud 10
@@ -157,12 +158,26 @@ class Db implements IDb {
* @param array $updatePreconditionValues ensure values match preconditions (column name => value)
* @return int number of new rows
* @throws \Doctrine\DBAL\DBALException
* @throws PreconditionNotMetException
* @throws PreConditionNotMetException
*/
public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
return $this->connection->setValues($table, $keys, $values, $updatePreconditionValues);
}

/**
* @inheritdoc
*/
public function lockTable($tableName) {
$this->connection->lockTable($tableName);
}

/**
* @inheritdoc
*/
public function unlockTable() {
$this->connection->unlockTable();
}

/**
* Start a transaction
*/

+ 20
- 0
lib/private/DB/Adapter.php View File

@@ -57,6 +57,26 @@ class Adapter {
return $statement;
}

/**
* Create an exclusive read+write lock on a table
*
* @param string $tableName
* @since 9.1.0
*/
public function lockTable($tableName) {
$this->conn->beginTransaction();
$this->conn->executeUpdate('LOCK TABLE `' .$tableName . '` IN EXCLUSIVE MODE');
}

/**
* Release a previous acquired lock again
*
* @since 9.1.0
*/
public function unlockTable() {
$this->conn->commit();
}

/**
* Insert a row if the matching row does not exists.
*

+ 12
- 0
lib/private/DB/AdapterMySQL.php View File

@@ -24,6 +24,18 @@
namespace OC\DB;

class AdapterMySQL extends Adapter {

/**
* @param string $tableName
*/
public function lockTable($tableName) {
$this->conn->executeUpdate('LOCK TABLES `' .$tableName . '` WRITE');
}

public function unlockTable() {
$this->conn->executeUpdate('UNLOCK TABLES');
}

public function fixupStatement($statement) {
$statement = str_replace(' ILIKE ', ' COLLATE utf8_general_ci LIKE ', $statement);
return $statement;

+ 12
- 0
lib/private/DB/AdapterSqlite.php View File

@@ -27,6 +27,18 @@
namespace OC\DB;

class AdapterSqlite extends Adapter {

/**
* @param string $tableName
*/
public function lockTable($tableName) {
$this->conn->executeUpdate('BEGIN EXCLUSIVE TRANSACTION');
}

public function unlockTable() {
$this->conn->executeUpdate('COMMIT TRANSACTION');
}

public function fixupStatement($statement) {
$statement = preg_replace('( I?LIKE \?)', '$0 ESCAPE \'\\\'', $statement);
$statement = preg_replace('/`(\w+)` ILIKE \?/', 'LOWER($1) LIKE LOWER(?)', $statement);

+ 31
- 1
lib/private/DB/Connection.php View File

@@ -25,6 +25,7 @@
*/

namespace OC\DB;

use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Configuration;
@@ -46,6 +47,8 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
*/
protected $adapter;

protected $lockedTable = null;

public function connect() {
try {
return parent::connect();
@@ -281,7 +284,7 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
foreach ($values as $name => $value) {
$updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
}
$where = $updateQb->expr()->andx();
$where = $updateQb->expr()->andX();
$whereValues = array_merge($keys, $updatePreconditionValues);
foreach ($whereValues as $name => $value) {
$where->add($updateQb->expr()->eq(
@@ -301,6 +304,33 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
}
}

/**
* Create an exclusive read+write lock on a table
*
* @param string $tableName
* @throws \BadMethodCallException When trying to acquire a second lock
* @since 9.1.0
*/
public function lockTable($tableName) {
if ($this->lockedTable !== null) {
throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
}

$tableName = $this->tablePrefix . $tableName;
$this->lockedTable = $tableName;
$this->adapter->lockTable($tableName);
}

/**
* Release a previous acquired lock again
*
* @since 9.1.0
*/
public function unlockTable() {
$this->adapter->unlockTable();
$this->lockedTable = null;
}

/**
* returns the error code and message as a string for logging
* works with DoctrineException

+ 19
- 0
lib/public/IDBConnection.php View File

@@ -124,6 +124,25 @@ interface IDBConnection {
*/
public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []);

/**
* Create an exclusive read+write lock on a table
*
* Important Note: Due to the nature how locks work on different DBs, it is
* only possible to lock one table at a time. You should also NOT start a
* transaction while holding a lock.
*
* @param string $tableName
* @since 9.1.0
*/
public function lockTable($tableName);

/**
* Release a previous acquired lock again
*
* @since 9.1.0
*/
public function unlockTable();

/**
* Start a transaction
* @since 6.0.0

Loading…
Cancel
Save