Issue #1976172 by chx, andypost: Comment entity acquired and releases the different locks.
parent
ba6591cdd2
commit
44ed771a1c
|
@ -19,11 +19,6 @@ use Drupal\Core\Entity\EntityChangedInterface;
|
||||||
*/
|
*/
|
||||||
class CommentStorageController extends FieldableDatabaseStorageController implements CommentStorageControllerInterface {
|
class CommentStorageController extends FieldableDatabaseStorageController implements CommentStorageControllerInterface {
|
||||||
|
|
||||||
/**
|
|
||||||
* The thread for which a lock was acquired.
|
|
||||||
*/
|
|
||||||
protected $threadLock = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -56,6 +56,11 @@ use Drupal\Core\TypedData\DataDefinition;
|
||||||
*/
|
*/
|
||||||
class Comment extends ContentEntityBase implements CommentInterface {
|
class Comment extends ContentEntityBase implements CommentInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The thread for which a lock was acquired.
|
||||||
|
*/
|
||||||
|
protected $threadLock = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The comment ID.
|
* The comment ID.
|
||||||
*
|
*
|
||||||
|
@ -273,12 +278,13 @@ class Comment extends ContentEntityBase implements CommentInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Finally, build the thread field for this new comment. To avoid
|
// Finally, build the thread field for this new comment. To avoid
|
||||||
// race conditions, get a lock on the thread. If aother process already
|
// race conditions, get a lock on the thread. If another process already
|
||||||
// has the lock, just move to the next integer.
|
// has the lock, just move to the next integer.
|
||||||
do {
|
do {
|
||||||
$thread = $prefix . comment_int_to_alphadecimal(++$n) . '/';
|
$thread = $prefix . comment_int_to_alphadecimal(++$n) . '/';
|
||||||
} while (!lock()->acquire("comment:{$this->entity_id->value}:$thread"));
|
$lock_name = "comment:{$this->entity_id->value}:$thread";
|
||||||
$this->threadLock = $thread;
|
} while (!\Drupal::lock()->acquire($lock_name));
|
||||||
|
$this->threadLock = $lock_name;
|
||||||
}
|
}
|
||||||
if (empty($this->created->value)) {
|
if (empty($this->created->value)) {
|
||||||
$this->created->value = REQUEST_TIME;
|
$this->created->value = REQUEST_TIME;
|
||||||
|
@ -316,7 +322,7 @@ class Comment extends ContentEntityBase implements CommentInterface {
|
||||||
*/
|
*/
|
||||||
protected function releaseThreadLock() {
|
protected function releaseThreadLock() {
|
||||||
if ($this->threadLock) {
|
if ($this->threadLock) {
|
||||||
lock()->release($this->threadLock);
|
\Drupal::lock()->release($this->threadLock);
|
||||||
$this->threadLock = '';
|
$this->threadLock = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\comment\Tests\Entity\CommentTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\comment\Tests\Entity {
|
||||||
|
|
||||||
|
use Drupal\comment\Entity\Comment;
|
||||||
|
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||||
|
use Drupal\Tests\UnitTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the comment entity lock behavior.
|
||||||
|
*
|
||||||
|
* @group Drupal
|
||||||
|
*/
|
||||||
|
class CommentLockTest extends UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return array(
|
||||||
|
'name' => 'Comment locks',
|
||||||
|
'description' => 'Test comment acquires and releases the right lock.',
|
||||||
|
'group' => 'Comment',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the lock behavior.
|
||||||
|
*/
|
||||||
|
public function testLocks() {
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
$container->set('current_user', $this->getMock('Drupal\Core\Session\AccountInterface'));
|
||||||
|
$container->register('request', 'Symfony\Component\HttpFoundation\Request');
|
||||||
|
$lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface');
|
||||||
|
$cid = 2;
|
||||||
|
$lock_name = "comment:$cid:./";
|
||||||
|
$lock->expects($this->at(0))
|
||||||
|
->method('acquire')
|
||||||
|
->with($lock_name, 30)
|
||||||
|
->will($this->returnValue(TRUE));
|
||||||
|
$lock->expects($this->at(1))
|
||||||
|
->method('release')
|
||||||
|
->with($lock_name);
|
||||||
|
$lock->expects($this->exactly(2))
|
||||||
|
->method($this->anything());
|
||||||
|
$container->set('lock', $lock);
|
||||||
|
\Drupal::setContainer($container);
|
||||||
|
$methods = get_class_methods('Drupal\comment\Entity\Comment');
|
||||||
|
unset($methods[array_search('preSave', $methods)]);
|
||||||
|
unset($methods[array_search('postSave', $methods)]);
|
||||||
|
$comment = $this->getMockBuilder('Drupal\comment\Entity\Comment')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods($methods)
|
||||||
|
->getMock();
|
||||||
|
$comment->expects($this->once())
|
||||||
|
->method('isNew')
|
||||||
|
->will($this->returnValue(TRUE));
|
||||||
|
foreach (array('status', 'pid', 'created', 'changed', 'entity_id', 'uid', 'thread', 'hostname') as $property) {
|
||||||
|
$comment->$property = new \stdClass();
|
||||||
|
}
|
||||||
|
$comment->status->value = 1;
|
||||||
|
$comment->entity_id->value = $cid;
|
||||||
|
$comment->uid->target_id = 3;
|
||||||
|
$comment->pid->target_id = 42;
|
||||||
|
$comment->pid->entity = new \stdClass();
|
||||||
|
$comment->pid->entity->thread = (object) array('value' => '');
|
||||||
|
$storage_controller = $this->getMock('Drupal\comment\CommentStorageControllerInterface');
|
||||||
|
$comment->preSave($storage_controller);
|
||||||
|
$comment->postSave($storage_controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function tearDown() {
|
||||||
|
parent::tearDown();
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
\Drupal::setContainer($container);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace {
|
||||||
|
if (!function_exists('comment_int_to_alphadecimal')) {
|
||||||
|
function comment_int_to_alphadecimal() {}
|
||||||
|
}
|
||||||
|
if (!function_exists('module_invoke_all')) {
|
||||||
|
function module_invoke_all() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue