Skip to content

Commit 0b04c8f

Browse files
dariorussi-zzsgolemon
authored andcommitted
Introducing APCHandle as a replacement of APCVariant (aka SharedVariant)
Every APC object (aka shared object) now has an APCHandle field used by the concurrent storage. No indirection any longer from APCVariant to the object data (string, object, array) Reviewed By: @jdelong Differential Revision: D1023419
1 parent c6d99f1 commit 0b04c8f

30 files changed

+1393
-1041
lines changed

hphp/runtime/base/apc-array.cpp

Lines changed: 132 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,89 +15,183 @@
1515
*/
1616

1717
#include "hphp/runtime/base/apc-array.h"
18-
#include "hphp/runtime/base/apc-variant.h"
18+
#include "hphp/runtime/base/apc-handle.h"
19+
#include "hphp/runtime/base/apc-typed-value.h"
20+
#include "hphp/runtime/base/apc-string.h"
21+
#include "hphp/runtime/base/apc-local-array.h"
1922
#include "hphp/runtime/base/array-iterator.h"
23+
#include "hphp/runtime/ext/ext_apc.h"
2024

2125
namespace HPHP {
2226

2327
///////////////////////////////////////////////////////////////////////////////
2428

25-
APCArray* APCArray::Create(ArrayData* arr,
26-
bool unserializeObj,
27-
bool &shouldCache) {
28-
int num = arr->size();
29-
int cap = num > 2 ? Util::roundUpToPowerOfTwo(num) : 2;
29+
APCHandle* APCArray::MakeShared(ArrayData* arr,
30+
bool inner,
31+
bool unserializeObj) {
32+
if (!inner) {
33+
// only need to call hasInternalReference() on the toplevel array
34+
PointerSet seen;
35+
if (arr->hasInternalReference(seen)) {
36+
String s = apc_serialize(arr);
37+
APCHandle* handle = APCString::MakeShared(KindOfArray, s.get());
38+
handle->setSerializedArray();
39+
handle->mustCache();
40+
return handle;
41+
}
42+
}
43+
44+
if (arr->isVectorData()) {
45+
return APCArray::MakePackedShared(arr, unserializeObj);
46+
}
47+
48+
return APCArray::MakeShared(arr, unserializeObj);
49+
}
50+
51+
APCHandle* APCArray::MakeShared() {
52+
void* p = malloc(sizeof(APCArray));
53+
APCArray* arr = new (p) APCArray(static_cast<size_t>(0));
54+
return arr->getHandle();
55+
}
56+
57+
APCHandle* APCArray::MakeShared(ArrayData* arr,
58+
bool unserializeObj) {
59+
auto num = arr->size();
60+
auto cap = num > 2 ? Util::roundUpToPowerOfTwo(num) : 2;
3061

31-
APCArray* ret = (APCArray*)malloc(sizeof(APCArray) +
32-
sizeof(int) * cap +
33-
sizeof(Bucket) * num);
62+
void* p = malloc(sizeof(APCArray) +
63+
sizeof(int) * cap +
64+
sizeof(Bucket) * num);
65+
APCArray* ret = new (p) APCArray(static_cast<unsigned int>(cap));
3466

35-
ret->m.m_capacity_mask = cap - 1;
36-
ret->m.m_num = 0;
3767
for (int i = 0; i < cap; i++) ret->hash()[i] = -1;
3868

3969
try {
4070
for (ArrayIter it(arr); !it.end(); it.next()) {
41-
APCVariant* key = APCVariant::Create(it.first(), false, true,
42-
unserializeObj);
43-
APCVariant* val = APCVariant::Create(it.secondRef(), false, true,
44-
unserializeObj);
45-
if (val->shouldCache()) shouldCache = true;
46-
ret->add(ret->m.m_num, key, val);
47-
++ret->m.m_num;
71+
auto key = APCHandle::Create(it.first(), false, true,
72+
unserializeObj);
73+
auto val = APCHandle::Create(it.secondRef(), false, true,
74+
unserializeObj);
75+
if (val->shouldCache()) {
76+
ret->mustCache();
77+
}
78+
ret->add(key, val);
4879
}
4980
} catch (...) {
50-
Destroy(ret);
81+
delete ret;
5182
throw;
5283
}
5384

54-
return ret;
85+
return ret->getHandle();
5586
}
5687

57-
void APCArray::Destroy(APCArray* map) {
58-
Bucket* buckets = map->buckets();
59-
for (int i = 0; i < map->m.m_num; i++) {
60-
buckets[i].key->decRef();
61-
buckets[i].val->decRef();
88+
APCHandle* APCArray::MakePackedShared(ArrayData* arr,
89+
bool unserializeObj) {
90+
size_t num_elems = arr->size();
91+
void* p = malloc(sizeof(APCArray) + sizeof(APCHandle*) * num_elems);
92+
auto ret = new (p) APCArray(static_cast<size_t>(num_elems));
93+
94+
try {
95+
size_t i = 0;
96+
for (ArrayIter it(arr); !it.end(); it.next()) {
97+
APCHandle* val = APCHandle::Create(it.secondRef(),
98+
false, true,
99+
unserializeObj);
100+
if (val->shouldCache()) {
101+
ret->mustCache();
102+
}
103+
ret->vals()[i++] = val;
104+
}
105+
assert(i == num_elems);
106+
} catch (...) {
107+
delete ret;
108+
throw;
62109
}
63-
free(map);
110+
111+
return ret->getHandle();
112+
}
113+
114+
Variant APCArray::MakeArray(APCHandle* handle) {
115+
if (handle->getSerializedArray()) {
116+
StringData* serArr = APCString::fromHandle(handle)->getStringData();
117+
return apc_unserialize(serArr->data(), serArr->size());
118+
}
119+
return APCLocalArray::Make(APCArray::fromHandle(handle));
120+
}
121+
122+
void APCArray::Delete(APCHandle* handle) {
123+
handle->getSerializedArray() ? delete APCString::fromHandle(handle)
124+
: delete APCArray::fromHandle(handle);
64125
}
65126

66-
void APCArray::add(int pos, APCVariant *key, APCVariant *val) {
127+
APCArray::~APCArray() {
128+
if (isPacked()) {
129+
APCHandle** v = vals();
130+
for (size_t i = 0, n = m_size; i < n; i++) {
131+
v[i]->decRef();
132+
}
133+
} else {
134+
Bucket* bks = buckets();
135+
for (int i = 0; i < m.m_num; i++) {
136+
bks[i].key->decRef();
137+
bks[i].val->decRef();
138+
}
139+
}
140+
}
141+
142+
void APCArray::add(APCHandle *key, APCHandle *val) {
143+
int pos = m.m_num;
67144
// NOTE: no check on duplication because we assume the original array has no
68145
// duplication
69146
Bucket* bucket = buckets() + pos;
70147
bucket->key = key;
71148
bucket->val = val;
72-
int hash_pos =
73-
(key->is(KindOfInt64) ?
74-
key->intData() : key->getStringData()->hash()) & m.m_capacity_mask;
149+
m.m_num++;
150+
int hash_pos;
151+
if (!IS_REFCOUNTED_TYPE(key->getType())) {
152+
APCTypedValue *k = APCTypedValue::fromHandle(key);
153+
hash_pos = (key->is(KindOfInt64) ?
154+
k->getInt64() : k->getStringData()->hash()) & m.m_capacity_mask;
155+
} else {
156+
assert(key->is(KindOfString));
157+
APCString *k = APCString::fromHandle(key);
158+
hash_pos = k->getStringData()->hash() & m.m_capacity_mask;
159+
}
75160

76161
int& hp = hash()[hash_pos];
77162
bucket->next = hp;
78163
hp = pos;
79164
}
80165

81-
int APCArray::indexOf(const StringData* key) {
166+
ssize_t APCArray::indexOf(const StringData* key) const {
82167
strhash_t h = key->hash();
83-
int bucket = hash()[h & m.m_capacity_mask];
168+
ssize_t bucket = hash()[h & m.m_capacity_mask];
84169
Bucket* b = buckets();
85170
while (bucket != -1) {
86-
if (!b[bucket].key->is(KindOfInt64) &&
87-
key->same(b[bucket].key->getStringData())) {
88-
return bucket;
171+
if (!IS_REFCOUNTED_TYPE(b[bucket].key->getType())) {
172+
APCTypedValue *k = APCTypedValue::fromHandle(b[bucket].key);
173+
if (!b[bucket].key->is(KindOfInt64) &&
174+
key->same(k->getStringData())) {
175+
return bucket;
176+
}
177+
} else {
178+
assert(b[bucket].key->is(KindOfString));
179+
APCString *k = APCString::fromHandle(b[bucket].key);
180+
if (key->same(k->getStringData())) {
181+
return bucket;
182+
}
89183
}
90184
bucket = b[bucket].next;
91185
}
92186
return -1;
93187
}
94188

95-
int APCArray::indexOf(int64_t key) {
96-
int bucket = hash()[key & m.m_capacity_mask];
189+
ssize_t APCArray::indexOf(int64_t key) const {
190+
ssize_t bucket = hash()[key & m.m_capacity_mask];
97191
Bucket* b = buckets();
98192
while (bucket != -1) {
99193
if (b[bucket].key->is(KindOfInt64) &&
100-
key == b[bucket].key->intData()) {
194+
key == APCTypedValue::fromHandle(b[bucket].key)->getInt64()) {
101195
return bucket;
102196
}
103197
bucket = b[bucket].next;

0 commit comments

Comments
 (0)