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 {
|
||||
|
||||
/**
|
||||
* The thread for which a lock was acquired.
|
||||
*/
|
||||
protected $threadLock = '';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -56,6 +56,11 @@ use Drupal\Core\TypedData\DataDefinition;
|
|||
*/
|
||||
class Comment extends ContentEntityBase implements CommentInterface {
|
||||
|
||||
/**
|
||||
* The thread for which a lock was acquired.
|
||||
*/
|
||||
protected $threadLock = '';
|
||||
|
||||
/**
|
||||
* The comment ID.
|
||||
*
|
||||
|
@ -273,12 +278,13 @@ class Comment extends ContentEntityBase implements CommentInterface {
|
|||
}
|
||||
}
|
||||
// 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.
|
||||
do {
|
||||
$thread = $prefix . comment_int_to_alphadecimal(++$n) . '/';
|
||||
} while (!lock()->acquire("comment:{$this->entity_id->value}:$thread"));
|
||||
$this->threadLock = $thread;
|
||||
$lock_name = "comment:{$this->entity_id->value}:$thread";
|
||||
} while (!\Drupal::lock()->acquire($lock_name));
|
||||
$this->threadLock = $lock_name;
|
||||
}
|
||||
if (empty($this->created->value)) {
|
||||
$this->created->value = REQUEST_TIME;
|
||||
|
@ -316,7 +322,7 @@ class Comment extends ContentEntityBase implements CommentInterface {
|
|||
*/
|
||||
protected function releaseThreadLock() {
|
||||
if ($this->threadLock) {
|
||||
lock()->release($this->threadLock);
|
||||
\Drupal::lock()->release($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