Issue #1976172 by chx, andypost: Comment entity acquired and releases the different locks.

8.0.x
Nathaniel Catchpole 2013-12-19 17:54:14 +00:00
parent ba6591cdd2
commit 44ed771a1c
3 changed files with 105 additions and 9 deletions

View File

@ -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}
*/

View File

@ -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 = '';
}
}

View File

@ -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() {}
}
}