18
18
19
19
namespace Cassandra ;
20
20
21
- class PagingIntegrationTest extends BasicIntegrationTest
22
- {
21
+ class PagingIntegrationTest extends BasicIntegrationTest {
23
22
public function setUp () {
24
23
parent ::setUp ();
25
24
@@ -40,6 +39,66 @@ public function setUp() {
40
39
}
41
40
}
42
41
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
+
43
102
/**
44
103
* Use paging state token
45
104
*
@@ -119,4 +178,72 @@ public function testNullToken() {
119
178
120
179
$ result = $ this ->session ->execute ($ statement , $ options );
121
180
}
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
+ }
122
249
}
0 commit comments