Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Couchbase/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
use Couchbase\Exception\DocumentExistsException;
use Couchbase\Exception\DocumentIrretrievableException;
use Couchbase\Exception\DocumentNotFoundException;
use Couchbase\Exception\DocumentNotFoundOnReplicaException;
use Couchbase\Exception\CouchbaseException;
use Couchbase\Exception\InvalidArgumentException;
use Couchbase\Exception\ReplicaIndexCurrentlyUnavailableException;
use Couchbase\Exception\ReplicaIndexOutOfBoundsException;
use Couchbase\Exception\TimeoutException;
use Couchbase\Exception\UnsupportedOperationException;
use Couchbase\Management\CollectionQueryIndexManager;
Expand Down Expand Up @@ -290,6 +293,44 @@ function (ObservabilityHandler $obsHandler) use ($id, $options) {
);
}

/**
* Reads from the replica the strategy selects.
*
* @param string $id the key of the document
* @param GetReplicaStrategy $strategy selects the replica to read from
* @param GetReplicaOptions|null $options the options to use for the operation
*
* @return GetReplicaResult
*
* @throws DocumentNotFoundOnReplicaException
* @throws ReplicaIndexOutOfBoundsException
* @throws ReplicaIndexCurrentlyUnavailableException
* @throws TimeoutException
* @throws CouchbaseException
* @since 4.5.0
*/
public function getReplica(string $id, GetReplicaStrategy $strategy, ?GetReplicaOptions $options = null): GetReplicaResult
{
return $this->observability->recordOperation(
ObservabilityConstants::OP_GET_REPLICA,
GetReplicaOptions::getParentSpan($options),
Comment thread
Matt-Woz marked this conversation as resolved.
function (ObservabilityHandler $obsHandler) use ($id, $strategy, $options) {
$function = COUCHBASE_EXTENSION_NAMESPACE . '\\documentGetReplica';
$response = $function(
$this->core,
$this->bucketName,
$this->scopeName,
$this->name,
$id,
GetReplicaStrategy::export($strategy),
GetReplicaOptions::export($options),
$obsHandler->getCoreSpansArray()
);
return new GetReplicaResult($response, GetReplicaOptions::getTranscoder($options));
}
);
}

/**
* Gets a document from the active server and all replica servers in the cluster.
* Returns an array of documents, one per server.
Expand Down
2 changes: 2 additions & 0 deletions Couchbase/CollectionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public function getAndTouch(string $id, $expiry, ?GetAndTouchOptions $options =

public function getAnyReplica(string $id, ?GetAnyReplicaOptions $options = null): GetReplicaResult;

public function getReplica(string $id, GetReplicaStrategy $strategy, ?GetReplicaOptions $options = null): GetReplicaResult;
Comment thread
avsej marked this conversation as resolved.

public function getAllReplicas(string $id, ?GetAllReplicasOptions $options = null): array;

public function upsert(string $id, $value, ?UpsertOptions $options = null): MutationResult;
Expand Down
28 changes: 28 additions & 0 deletions Couchbase/Exception/DocumentNotFoundOnReplicaException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/**
* Copyright 2014-Present Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

declare(strict_types=1);

namespace Couchbase\Exception;

/**
* Indicates that Collection::getReplica() reached the requested replica, but it does not hold the document.
*/
class DocumentNotFoundOnReplicaException extends DocumentNotFoundException
{
}
30 changes: 30 additions & 0 deletions Couchbase/Exception/ReplicaIndexCurrentlyUnavailableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/**
* Copyright 2014-Present Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

declare(strict_types=1);

namespace Couchbase\Exception;

/**
* Indicates that Collection::getReplica() was asked for a replica index the bucket has, but that
* replica cannot be read right now. A rebalance resolves this; @see GetReplicaStrategy::wrap() to
* read a different replica instead.
*/
class ReplicaIndexCurrentlyUnavailableException extends CouchbaseException
{
}
29 changes: 29 additions & 0 deletions Couchbase/Exception/ReplicaIndexOutOfBoundsException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/**
* Copyright 2014-Present Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

declare(strict_types=1);

namespace Couchbase\Exception;

/**
* Indicates that Collection::getReplica() was asked for a replica index the bucket does not have:
* the index is at or beyond the bucket's configured replica count, or that count is zero.
*/
class ReplicaIndexOutOfBoundsException extends CouchbaseException
{
}
121 changes: 121 additions & 0 deletions Couchbase/GetReplicaOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

/**
* Copyright 2014-Present Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

declare(strict_types=1);

namespace Couchbase;

class GetReplicaOptions
{
private Transcoder $transcoder;
private ?int $timeoutMilliseconds = null;
private ?RequestSpan $parentSpan = null;

public function __construct()
{
$this->transcoder = JsonTranscoder::getInstance();
}

/**
* Static helper to keep code more readable
*
* @return GetReplicaOptions
*/
public static function build(): GetReplicaOptions
{
return new GetReplicaOptions();
}

/**
* Sets the operation timeout in milliseconds.
*
* @param int $milliseconds the operation timeout to apply
*
* @return GetReplicaOptions
*/
public function timeout(int $milliseconds): GetReplicaOptions
{
$this->timeoutMilliseconds = $milliseconds;
return $this;
}

/**
* Associate custom transcoder with the request.
*
* @param Transcoder $transcoder
*
* @return GetReplicaOptions
*/
public function transcoder(Transcoder $transcoder): GetReplicaOptions
{
$this->transcoder = $transcoder;
return $this;
}

/**
* Sets the parent span.
*
* @param RequestSpan $parentSpan the parent span
*
* @return GetReplicaOptions
*/
public function parentSpan(RequestSpan $parentSpan): GetReplicaOptions
{
$this->parentSpan = $parentSpan;
return $this;
}

/**
* @internal
*/
public static function getParentSpan(?GetReplicaOptions $options): ?RequestSpan
{
return $options?->parentSpan;
}

/**
* Returns associated transcoder.
*
* @param GetReplicaOptions|null $options
*
* @return Transcoder
*/
public static function getTranscoder(?GetReplicaOptions $options): Transcoder
{
if ($options == null) {
return JsonTranscoder::getInstance();
}
return $options->transcoder;
}

/**
* @param GetReplicaOptions|null $options
*
* @return array
* @internal
*/
public static function export(?GetReplicaOptions $options): array
{
if ($options == null) {
return [];
}
return [
'timeoutMilliseconds' => $options->timeoutMilliseconds,
];
}
}
84 changes: 84 additions & 0 deletions Couchbase/GetReplicaStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

/**
* Copyright 2014-Present Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

declare(strict_types=1);

namespace Couchbase;

/**
* Selects the replica that Collection::getReplica() reads from.
*
* @see Collection::getReplica()
*/
class GetReplicaStrategy
{
private int $replicaIndex;
private bool $wrap = false;

private function __construct(int $replicaIndex)
{
$this->replicaIndex = $replicaIndex;
}

/**
* Read from the replica at the given index.
*
* @param int $replicaIndex the replica to read from
*
* @see ReplicaIndex
*
* @return GetReplicaStrategy
*/
public static function fromIndex(int $replicaIndex): GetReplicaStrategy
{
return new GetReplicaStrategy($replicaIndex);
}

/**
* Resolve an index that cannot be read as requested to the next one that can, instead of
* failing with ReplicaIndexOutOfBoundsException or ReplicaIndexCurrentlyUnavailableException.
*
* The search walks the bucket's configured replica count, starting at the requested index
* modulo that count. Two failures remain: a bucket configured for no replicas still throws
* ReplicaIndexOutOfBoundsException, and a full lap that finds nothing readable throws
* ReplicaIndexCurrentlyUnavailableException.
*
* @param bool $wrap whether to wrap around the available replicas
*
* @return GetReplicaStrategy
*/
public function wrap(bool $wrap): GetReplicaStrategy
{
$this->wrap = $wrap;
return $this;
Comment thread
Matt-Woz marked this conversation as resolved.
}

/**
* @param GetReplicaStrategy $strategy
*
* @return array
* @internal
*/
public static function export(GetReplicaStrategy $strategy): array
{
return [
'replicaIndex' => $strategy->replicaIndex,
'wrap' => $strategy->wrap,
];
}
}
11 changes: 11 additions & 0 deletions Couchbase/Protostellar/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@
use Couchbase\Exception\DocumentIrretrievableException;
use Couchbase\Exception\DocumentNotFoundException;
use Couchbase\Exception\InvalidArgumentException;
use Couchbase\Exception\UnsupportedOperationException;
use Couchbase\ExistsOptions;
use Couchbase\ExistsResult;
use Couchbase\GetAllReplicasOptions;
use Couchbase\GetAndLockOptions;
use Couchbase\GetAndTouchOptions;
use Couchbase\GetAnyReplicaOptions;
use Couchbase\GetOptions;
use Couchbase\GetReplicaOptions;
use Couchbase\GetReplicaResult;
use Couchbase\GetReplicaStrategy;
use Couchbase\GetResult;
use Couchbase\InsertOptions;
use Couchbase\LookupInOptions;
Expand Down Expand Up @@ -301,6 +304,14 @@ public function getAnyReplica(string $key, ?GetAnyReplicaOptions $options = null
return KVResponseConverter::convertGetAnyReplicaResult($key, $response, $options)[0];
}

/**
* @throws UnsupportedOperationException
*/
public function getReplica(string $key, GetReplicaStrategy $strategy, ?GetReplicaOptions $options = null): GetReplicaResult
{
throw new UnsupportedOperationException("getReplica is not supported with the couchbase2 scheme yet");
}

/**
* @throws DocumentNotFoundException
*/
Expand Down
Loading
Loading