Skip to content

Commit 4a8aaa7

Browse files
committed
[6.0] feat: implement data boost (#131)
1 parent 9efa8ba commit 4a8aaa7

File tree

9 files changed

+122
-6
lines changed

9 files changed

+122
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# v6.0.0 [Not released Yet]
22

33
Added
4+
- Add [Data Boost](https://cloud.google.com/spanner/docs/databoost/databoost-overview) support (#131)
45
- Deprecation warnings to `Connection`'s methods `cursorWithTimestampBound` `selectWithTimestampBound` `selectOneWithTimestampBound`. Use `cursorWithOptions` `selectWithOptions` instead. (#122)
56
- `Connection` has new methods `selectWithOptions` `cursorWithOptions` which allows spanner specific options to be set for each query. (#122)
67

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,28 @@ $queryBuilder
162162

163163
Stale reads always runs as read-only transaction with `singleUse` option. So you can not run as read-write transaction.
164164

165+
### Data Boost
166+
167+
Data boost creates snapshot and runs the query in parallel without affecting existing workloads.
168+
169+
You can read more about it [here](https://cloud.google.com/spanner/docs/databoost/databoost-overview).
170+
171+
Below are some examples of how to use it.
172+
173+
```php
174+
// Using Connection
175+
$connection->selectWithOptions('SELECT ...', $bindings, ['dataBoostEnabled' => true]);
176+
177+
// Using Query Builder
178+
$queryBuilder
179+
->useDataBoost()
180+
->get();
181+
```
182+
183+
> [!NOTE]
184+
> This creates a new session in the background which is not shared with the current session pool.
185+
> This means, queries running with data boost will not be associated with transactions that may be taking place.
186+
165187
### Data Types
166188
Some data types of Google Cloud Spanner does not have corresponding built-in type of PHP.
167189
You can use following classes by [Google Cloud PHP Client](https://github.com/googleapis/google-cloud-php)

phpstan.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ parameters:
2121
path: src/Connection.php
2222
- message: '#^Method Colopl\\Spanner\\Connection::selectWithOptions\(\) should return array<int, array> but returns mixed\.$#'
2323
path: src/Connection.php
24+
- message: '#^Generator expects value type array, mixed given.$#'
25+
path: src/Connection.php
26+
count: 1
2427
- message: '#^Cannot cast mixed to int\.$#'
2528
path: src/Eloquent/Model.php
2629
- message: '#^Property Illuminate\\Database\\Schema\\Builder::\$resolver \(Closure\) in isset\(\) is not nullable\.$#'

src/Concerns/ManagesSessionPool.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ public function maintainSessionPool(): bool
6161
return false;
6262
}
6363

64-
65-
6664
/**
6765
* @return int Number of warmed up sessions
6866
*/

src/Concerns/ManagesStaleReads.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
trait ManagesStaleReads
2727
{
2828
/**
29-
* @deprecated use selectWithOptions() instead. This method will be removed in v7.
29+
* @deprecated use cursorWithOptions() instead. This method will be removed in v7.
3030
* @param string $query
3131
* @param array<array-key, mixed> $bindings
3232
* @param TimestampBoundInterface|null $timestampBound

src/Connection.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,11 +588,33 @@ protected function executeQuery(string $query, array $bindings, array $options):
588588
{
589589
$options += ['parameters' => $this->prepareBindings($bindings)];
590590

591+
if (isset($options['dataBoostEnabled'])) {
592+
return $this->executePartitionedQuery($query, $options);
593+
}
594+
591595
return $this->getDatabaseContext()
592596
->execute($query, $options)
593597
->rows();
594598
}
595599

600+
/**
601+
* @param string $query
602+
* @param array<string, mixed> $options
603+
* @return Generator<int, array<array-key, mixed>>
604+
*/
605+
protected function executePartitionedQuery(string $query, array $options): Generator
606+
{
607+
$snapshot = $this->getSpannerClient()
608+
->batch($this->instanceId, $this->database, $options)
609+
->snapshot();
610+
611+
foreach ($snapshot->partitionQuery($query, $options) as $partition) {
612+
foreach ($snapshot->executePartition($partition) as $row) {
613+
yield $row;
614+
}
615+
}
616+
}
617+
596618
/**
597619
* Check if this is "session not found" error
598620
*

src/Query/Builder.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424

2525
class Builder extends BaseBuilder
2626
{
27-
use Concerns\UsesMutations,
28-
Concerns\UsesPartitionedDml,
29-
Concerns\UsesStaleReads;
27+
use Concerns\UsesDataBoost;
28+
use Concerns\UsesMutations;
29+
use Concerns\UsesPartitionedDml;
30+
use Concerns\UsesStaleReads;
3031

3132
/**
3233
* @var Connection
@@ -136,6 +137,10 @@ protected function runSelect()
136137
$bindings = $this->getBindings();
137138
$options = [];
138139

140+
if ($this->dataBoostEnabled()) {
141+
$options += ['dataBoostEnabled' => true];
142+
}
143+
139144
if ($this->timestampBound !== null) {
140145
$options += $this->timestampBound->transactionOptions();
141146
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/**
3+
* Copyright 2019 Colopl Inc. All Rights Reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace Colopl\Spanner\Query\Concerns;
19+
20+
trait UsesDataBoost
21+
{
22+
/**
23+
* @var bool
24+
*/
25+
protected bool $useDataBoost = false;
26+
27+
/**
28+
* @param bool $toggle
29+
* @return $this
30+
*/
31+
public function useDataBoost(bool $toggle = true): static
32+
{
33+
$this->useDataBoost = $toggle;
34+
return $this;
35+
}
36+
37+
/**
38+
* @return bool
39+
*/
40+
public function dataBoostEnabled(): bool
41+
{
42+
return $this->useDataBoost;
43+
}
44+
}

tests/Query/BuilderTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,4 +836,25 @@ public function test_toRawSql(): void
836836
$sql = $conn->table($table)->where('s', "t\"e\"s\nt")->toRawSql();
837837
$this->assertSame("select * from `RawSqlTest` where `s` = r\"\"\"t\\\"e\\\"s\nt\"\"\"", $sql, 'newline with escaped quote');
838838
}
839+
840+
public function test_dataBoost_enabled(): void
841+
{
842+
$conn = $this->getDefaultConnection();
843+
$tableName = self::TABLE_NAME_USER;
844+
845+
$conn->table($tableName)->insert(['userId' => $this->generateUuid(), 'name' => __FUNCTION__]);
846+
847+
$query = $conn->table($tableName)->useDataBoost();
848+
$result = $query->get();
849+
850+
$this->assertTrue($query->dataBoostEnabled());
851+
$this->assertSame(1, $result->count());
852+
$this->assertSame(__FUNCTION__, $result->first()['name']);
853+
}
854+
855+
public function test_dataBoost_disabled(): void
856+
{
857+
$query = $this->getDefaultConnection()->table('t')->useDataBoost(false);
858+
$this->assertFalse($query->dataBoostEnabled());
859+
}
839860
}

0 commit comments

Comments
 (0)