APC snapshot priming
[hiphop-php.git] / hphp / runtime / test / apc.cpp
blob289af9b566a15da5b5400389f8a113c15272aa59
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include <gtest/gtest.h>
18 #include <memory>
19 #include <cstring>
21 #include <folly/Memory.h>
22 #include <folly/Format.h>
24 #include "hphp/runtime/base/tv-comparisons.h"
25 #include "hphp/runtime/base/concurrent-shared-store.h"
26 #include "hphp/runtime/base/apc-file-storage.h"
28 namespace HPHP {
30 //////////////////////////////////////////////////////////////////////
32 namespace {
34 using Store = ConcurrentTableSharedStore;
35 using PrimePair = Store::KeyValuePair;
37 char* alloc_leaked_string(const char* source) {
38 return strdup(source);
41 template<class Create>
42 std::vector<PrimePair> primable_n(Store& store,
43 const char* prefix,
44 Create create) {
45 std::vector<PrimePair> pairs(10);
46 auto counter = int64_t{0};
47 for (auto& pair : pairs) {
48 auto key = folly::sformat("{}_{}", prefix, counter);
49 pair.key = alloc_leaked_string(key.c_str());
51 Variant v(create(counter));
52 store.constructPrime(v, pair);
54 ++counter;
56 return pairs;
60 * Sets int_n -> KindOfInt64 n
62 * Note that ints are never file-backed in apc right now.
64 std::vector<PrimePair> primable_ints(Store& store) {
65 return primable_n(store, "int", [&] (int64_t n) {
66 return n;
67 });
71 * Sets obj_n -> a stdClass
73 std::vector<PrimePair> primable_objs(Store& store) {
74 return primable_n(store, "obj", [&] (int64_t n) {
75 return Variant::attach(SystemLib::AllocStdClassObject().detach());
76 });
80 * Just an empty table.
82 std::unique_ptr<Store> new_store() {
83 return folly::make_unique<Store>();
87 * Make an APC table with some things primed for tests to use.
89 std::unique_ptr<Store> new_primed_store() {
90 s_apc_file_storage.enable("/tmp/apc_unit_test", 1ul << 20);
92 auto ret = folly::make_unique<Store>();
93 ret->prime(primable_ints(*ret));
94 ret->prime(primable_objs(*ret));
95 ret->primeDone();
96 return ret;
99 const StaticString s_key("key");
100 const StaticString s_key2("key2");
101 const StaticString s_foo("foo");
102 const StaticString s_value1("value1");
103 const StaticString s_value2("value2");
107 //////////////////////////////////////////////////////////////////////
109 TEST(APC, Basic) {
110 auto store = new_store();
112 EXPECT_EQ(store->add(s_key, Variant(s_value1), 1500), true);
113 EXPECT_EQ(store->exists(s_key), true);
114 Variant got;
115 EXPECT_EQ(store->get(s_key, got), true);
116 EXPECT_TRUE(cellSame(*got.asCell(),
117 make_tv<KindOfPersistentString>(s_value1.get())));
118 EXPECT_EQ(store->eraseKey(s_key), true);
119 EXPECT_EQ(store->get(s_key, got), false);
122 TEST(APC, SetOverwrite) {
123 auto store = new_store();
125 store->set(s_key, Variant(s_value1), 1500);
126 Variant got;
127 EXPECT_EQ(store->get(s_key, got), true);
128 EXPECT_TRUE(cellSame(*got.asCell(),
129 make_tv<KindOfPersistentString>(s_value1.get())));
130 store->set(s_key, Variant(s_value2), 1500);
131 EXPECT_EQ(store->get(s_key, got), true);
132 EXPECT_TRUE(cellSame(*got.asCell(),
133 make_tv<KindOfPersistentString>(s_value2.get())));
136 TEST(APC, Clear) {
137 auto store = new_store();
139 EXPECT_EQ(store->add(s_key, Variant(s_value1), 1500), true);
140 EXPECT_EQ(store->add(s_key2, Variant(s_value2), 1500), true);
141 EXPECT_EQ(store->exists(s_key), true);
142 EXPECT_EQ(store->exists(s_key2), true);
143 store->clear();
144 EXPECT_EQ(store->exists(s_key), false);
145 EXPECT_EQ(store->exists(s_key2), false);
148 TEST(APC, IncCas) {
149 auto store = new_store();
150 bool found = false;
152 store->set(s_key, Variant(1), 1500);
153 EXPECT_EQ(store->inc(s_key, 1, found), 2);
154 EXPECT_TRUE(found);
155 EXPECT_EQ(store->inc(s_key, 1, found), 3);
156 EXPECT_TRUE(found);
157 EXPECT_EQ(store->inc(s_key, 1, found), 4);
158 EXPECT_TRUE(found);
159 EXPECT_EQ(store->inc(s_key, 1, found), 5);
160 EXPECT_TRUE(found);
162 store->set(s_key, Variant(1.0), 1500);
163 EXPECT_EQ(store->inc(s_key, 1, found), 2);
164 EXPECT_TRUE(found);
165 EXPECT_EQ(store->inc(s_key, 1, found), 3);
166 EXPECT_TRUE(found);
167 EXPECT_EQ(store->inc(s_key, 1, found), 4);
168 EXPECT_TRUE(found);
169 EXPECT_EQ(store->inc(s_key, 1, found), 5);
170 EXPECT_TRUE(found);
172 store->set(s_key, Variant(1), 1500);
173 EXPECT_TRUE(store->cas(s_key, 1, 2));
174 EXPECT_TRUE(store->cas(s_key, 2, 3));
175 EXPECT_TRUE(store->cas(s_key, 3, 4));
176 EXPECT_TRUE(store->cas(s_key, 4, 5));
177 EXPECT_FALSE(store->cas(s_key, 4, 5));
179 store->set(s_key, Variant(1.0), 1500);
180 EXPECT_TRUE(store->cas(s_key, 1, 2));
181 EXPECT_TRUE(store->cas(s_key, 2, 3));
182 EXPECT_TRUE(store->cas(s_key, 3, 4));
183 EXPECT_TRUE(store->cas(s_key, 4, 5));
184 EXPECT_FALSE(store->cas(s_key, 4, 5));
186 // make sure it doesn't work on some non-doubles/ints
188 store->set(s_key, Variant(s_value2), 1500);
189 EXPECT_EQ(store->inc(s_key, 1, found), 0);
190 EXPECT_FALSE(found);
191 EXPECT_FALSE(store->cas(s_key, 1, 2));
192 store->eraseKey(s_key);
193 EXPECT_EQ(store->inc(s_key, 1, found), 0);
194 EXPECT_FALSE(found);
195 EXPECT_FALSE(store->cas(s_key, 1, 2));
198 TEST(APC, BasicPrimeStuff) {
199 auto store = new_primed_store();
200 Variant val;
202 EXPECT_TRUE(store->get("int_2", val));
203 EXPECT_TRUE(cellSame(*val.asCell(), make_tv<KindOfInt64>(2)));
205 bool found = false;
206 EXPECT_EQ(store->inc("int_3", 1, found), 4);
207 EXPECT_TRUE(found);
208 EXPECT_FALSE(store->get("int_200", val));
210 EXPECT_EQ(store->cas("obj_1", 1, 2), true); // stdclass converts to 1
211 EXPECT_EQ(store->cas("obj_2", 4, 5), false);
212 EXPECT_EQ(store->cas("int_4", 4, 5), true);
213 EXPECT_EQ(store->cas("int_5", 4, 5), false);
216 TEST(APC, SampleEntries) {
217 auto store = new_store();
218 // Empty store gives an empty sample.
219 auto entries = store->sampleEntriesInfo(10);
220 EXPECT_EQ(entries.size(), 0);
221 // Single-element store results in repetition.
222 store->set(s_foo, s_value1, 1500);
223 for (uint32_t count = 0; count <= 10; ++count) {
224 entries = store->sampleEntriesInfo(count);
225 EXPECT_EQ(entries.size(), count);
226 for (const auto& entry : entries) {
227 EXPECT_STREQ(entry.key.c_str(), "foo");
230 // More entries.
231 store->set(s_key, s_value1, 1500);
232 store->set(s_key2, s_value2, 1500);
233 for (uint32_t count = 0; count <= 10; ++count) {
234 entries = store->sampleEntriesInfo(count);
235 EXPECT_EQ(entries.size(), count);
236 for (const auto& entry : entries) {
237 EXPECT_TRUE(entry.key == std::string("foo") ||
238 entry.key == std::string("key") ||
239 entry.key == std::string("key2"));
244 //////////////////////////////////////////////////////////////////////