Skip to content

Commit 59da2a2

Browse files
author
Michael Fero
committed
test: Adding test for PHP-101 (Memory leak when paging enabled)
1 parent 2ac03c2 commit 59da2a2

File tree

1 file changed

+129
-2
lines changed

1 file changed

+129
-2
lines changed

tests/integration/Cassandra/PagingIntegrationTest.php

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818

1919
namespace Cassandra;
2020

21-
class PagingIntegrationTest extends BasicIntegrationTest
22-
{
21+
class PagingIntegrationTest extends BasicIntegrationTest {
2322
public function setUp() {
2423
parent::setUp();
2524

@@ -40,6 +39,66 @@ public function setUp() {
4039
}
4140
}
4241

42+
/**
43+
* Generate a random string
44+
*
45+
* @param int $length Length of string to generate (DEFAULT: random length
46+
* from 1 - 1024 characters)
47+
* @return string Randomly genreated text
48+
*/
49+
private function randomString($length = -1) {
50+
// Determine if the length should be random
51+
if ($length < 0) {
52+
$length = mt_rand(1, 1024);
53+
}
54+
55+
// Generate the random string from the below character set
56+
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ';
57+
$charactersLength = strlen($characters);
58+
$randomString = '';
59+
foreach (range(1, $length) as $i) {
60+
$randomString .= $characters[rand(0, $charactersLength - 1)];
61+
}
62+
return $randomString;
63+
}
64+
65+
/**
66+
* Page through the results while validating no memory leaks exists
67+
*
68+
* @param $start Starting memory value
69+
* @return int Number of rows visited
70+
*/
71+
private function validatePageResults($rows) {
72+
// Get the starting memory usage
73+
$start = memory_get_usage() / 1024;
74+
if (Integration::isDebug() && Integration::isVerbose()) {
75+
fprintf(STDOUT, "Start Usage: %dkb" . PHP_EOL, $start);
76+
}
77+
78+
// Page over each result set and count the number of rows visited
79+
$count = $rows->count();
80+
while ($rows = $rows->nextPage()) {
81+
if ($rows->count() != 0) {
82+
$count += $rows->count();
83+
if (Integration::isDebug() && Integration::isVerbose()) {
84+
fprintf(STDOUT, "Page %d: Current memory usage is %dkb" . PHP_EOL,
85+
($count / 2), ((memory_get_usage() / 1024) - $start));
86+
}
87+
}
88+
}
89+
90+
// Get the final memory usage (and apply a tolerance to compensate for GC)
91+
$end = memory_get_usage() / 1024;
92+
if (Integration::isDebug() && Integration::isVerbose()) {
93+
fprintf(STDOUT, "End Usage: %dkb [%dkb]" . PHP_EOL, $end, ($end - $start));
94+
}
95+
$difference = ($end - $start) - 20; // 20KB tolerance
96+
$this->assertLessThanOrEqual(0, $difference);
97+
98+
// Return the number of rows visited
99+
return $count;
100+
}
101+
43102
/**
44103
* Use paging state token
45104
*
@@ -119,4 +178,72 @@ public function testNullToken() {
119178

120179
$result = $this->session->execute($statement, $options);
121180
}
181+
182+
/**
183+
* Paging advancement does not create memory leak
184+
*
185+
* This test will ensure that the driver does not create memory leaks
186+
* associated advancing to the next page of results.
187+
*
188+
* @test
189+
* @ticket PHP-101
190+
*/
191+
public function testNoPagingMemoryLeak() {
192+
// Create the user types and table for the test
193+
$this->session->execute(new SimpleStatement(
194+
"DROP TABLE {$this->tableNamePrefix}"
195+
));
196+
$this->session->execute(new SimpleStatement(
197+
"CREATE TYPE price_history (time timestamp, price float)"
198+
));
199+
$priceHistory = Type::userType(
200+
"time", Type::timestamp(),
201+
"price", Type::float());
202+
$this->session->execute(new SimpleStatement(
203+
"CREATE TYPE purchase_stats (day_of_week int, total_purchases int)"
204+
));
205+
$purchaseStats = Type::userType(
206+
"day_of_week", Type::int(),
207+
"total_purchases", Type::int());
208+
$this->session->execute(new SimpleStatement(
209+
"CREATE TABLE {$this->tableNamePrefix} (id uuid PRIMARY KEY,
210+
history frozen<price_history>, stats frozen<purchase_stats>,
211+
comments text)"
212+
));
213+
214+
// Populate the table with some random data
215+
$totalInserts = 500;
216+
$statement = $this->session->prepare("INSERT INTO {$this->tableNamePrefix}
217+
(id, history, stats, comments) VALUES (?, ?, ?, ?)");
218+
foreach (range(1, $totalInserts) as $i) {
219+
// Create the values for the insert
220+
$history = $priceHistory->create(
221+
"time", new Timestamp(mt_rand(1270094400000, 1459483200000)), // 04-01-2010 - 04-01-2016
222+
"price", new Float((mt_rand(1, 1000) / 100))
223+
);
224+
$stats = $purchaseStats->create(
225+
"day_of_week", mt_rand(0, 6),
226+
"total_purchases", mt_rand(0, 1000)
227+
);
228+
$values = array(
229+
new Uuid(),
230+
$history,
231+
$stats,
232+
$this->randomString()
233+
);
234+
235+
$options = new ExecutionOptions(array("arguments" => $values));
236+
$this->session->execute($statement, $options);
237+
}
238+
239+
// Select all the rows in the table using paging
240+
$statement = new SimpleStatement("SELECT * FROM {$this->tableNamePrefix}");
241+
$options = new ExecutionOptions(array("page_size" => 2));
242+
$rows = $this->session->execute($statement, $options);
243+
244+
245+
// Validate paging and ensure all the rows were read
246+
$count = $this->validatePageResults($rows);
247+
$this->assertEquals($totalInserts, $count);
248+
}
122249
}

0 commit comments

Comments
 (0)