2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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>
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"
30 //////////////////////////////////////////////////////////////////////
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
,
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
);
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
) {
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());
80 * Just an empty table.
82 std::unique_ptr
<Store
> new_store() {
83 return std::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
= std::make_unique
<Store
>();
93 ret
->prime(primable_ints(*ret
));
94 ret
->prime(primable_objs(*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 //////////////////////////////////////////////////////////////////////
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);
115 EXPECT_EQ(store
->get(s_key
, got
), true);
116 EXPECT_TRUE(cellSame(*got
.toCell(),
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);
127 EXPECT_EQ(store
->get(s_key
, got
), true);
128 EXPECT_TRUE(cellSame(*got
.toCell(),
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
.toCell(),
133 make_tv
<KindOfPersistentString
>(s_value2
.get())));
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);
144 EXPECT_EQ(store
->exists(s_key
), false);
145 EXPECT_EQ(store
->exists(s_key2
), false);
149 auto store
= new_store();
152 store
->set(s_key
, Variant(1), 1500);
153 EXPECT_EQ(store
->inc(s_key
, 1, found
), 2);
155 EXPECT_EQ(store
->inc(s_key
, 1, found
), 3);
157 EXPECT_EQ(store
->inc(s_key
, 1, found
), 4);
159 EXPECT_EQ(store
->inc(s_key
, 1, found
), 5);
162 store
->set(s_key
, Variant(1.0), 1500);
163 EXPECT_EQ(store
->inc(s_key
, 1, found
), 2);
165 EXPECT_EQ(store
->inc(s_key
, 1, found
), 3);
167 EXPECT_EQ(store
->inc(s_key
, 1, found
), 4);
169 EXPECT_EQ(store
->inc(s_key
, 1, found
), 5);
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);
191 EXPECT_FALSE(store
->cas(s_key
, 1, 2));
192 store
->eraseKey(s_key
);
193 EXPECT_EQ(store
->inc(s_key
, 1, found
), 0);
195 EXPECT_FALSE(store
->cas(s_key
, 1, 2));
198 TEST(APC
, BasicPrimeStuff
) {
199 auto store
= new_primed_store();
202 EXPECT_TRUE(store
->get("int_2", val
));
203 EXPECT_TRUE(cellSame(*val
.toCell(), make_tv
<KindOfInt64
>(2)));
206 EXPECT_EQ(store
->inc("int_3", 1, found
), 4);
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");
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 //////////////////////////////////////////////////////////////////////