LockingSessionConnection.php 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. <?php
  2. namespace Aws\DynamoDb;
  3. use Aws\DynamoDb\Exception\DynamoDbException;
  4. /**
  5. * The locking connection adds locking logic to the read operation.
  6. */
  7. class LockingSessionConnection extends StandardSessionConnection
  8. {
  9. public function __construct(DynamoDbClient $client, array $config = [])
  10. {
  11. parent::__construct($client, $config + [
  12. 'max_lock_wait_time' => 10,
  13. 'min_lock_retry_microtime' => 10000,
  14. 'max_lock_retry_microtime' => 50000,
  15. ]);
  16. }
  17. /**
  18. * {@inheritdoc}
  19. * Retries the request until the lock can be acquired
  20. */
  21. public function read($id)
  22. {
  23. // Create the params for the UpdateItem operation so that a lock can be
  24. // set and item returned (via ReturnValues) in a one, atomic operation.
  25. $params = [
  26. 'TableName' => $this->config['table_name'],
  27. 'Key' => $this->formatKey($id),
  28. 'Expected' => ['lock' => ['Exists' => false]],
  29. 'AttributeUpdates' => ['lock' => ['Value' => ['N' => '1']]],
  30. 'ReturnValues' => 'ALL_NEW',
  31. ];
  32. // Acquire the lock and fetch the item data.
  33. $timeout = time() + $this->config['max_lock_wait_time'];
  34. while (true) {
  35. try {
  36. $item = [];
  37. $result = $this->client->updateItem($params);
  38. if (isset($result['Attributes'])) {
  39. foreach ($result['Attributes'] as $key => $value) {
  40. $item[$key] = current($value);
  41. }
  42. }
  43. return $item;
  44. } catch (DynamoDbException $e) {
  45. if ($e->getAwsErrorCode() === 'ConditionalCheckFailedException'
  46. && time() < $timeout
  47. ) {
  48. usleep(rand(
  49. $this->config['min_lock_retry_microtime'],
  50. $this->config['max_lock_retry_microtime']
  51. ));
  52. } else {
  53. break;
  54. }
  55. }
  56. }
  57. }
  58. }