clean up SharedMap

This diff cleans up some of the mess in SharedMap. The existing way of accessing values in ShareMap is SharedMap -> SharedVariant -> ImmutableMap -> SharedVariant. This diff changes it so that the path is reduced to SharedMap -> ImmutableMap (with inlined SharedVariants).
(Likewise for VectorData)

The hashing scheme in ImmutableMap is left unchanged (chaining with ->next pointers, though we could change it to something similar to HphpArray).
Esse commit está contido em:
aravind
2013-05-23 00:55:05 -07:00
commit de Sara Golemon
commit 841670cd26
8 arquivos alterados com 206 adições e 211 exclusões
@@ -252,7 +252,7 @@ SharedVariant* ConcurrentTableSharedStore::unserialize(CStrRef key,
VariableUnserializer vu(sval->sAddr, sval->getSerializedSize(), sType);
Variant v;
v.unserialize(&vu);
sval->var = SharedVariant::Create(v, sval->isSerializedObj());
sval->var = new SharedVariant(v, sval->isSerializedObj());
stats_on_add(key.get(), sval, 0, true, true); // delayed prime
return sval->var;
} catch (Exception &e) {
@@ -518,7 +518,7 @@ bool ConcurrentTableSharedStore::constructPrime(CStrRef v, KeyValuePair& item,
return false;
}
}
item.value = SharedVariant::Create(v, serialized);
item.value = new SharedVariant(v, serialized);
return true;
}
@@ -535,7 +535,7 @@ bool ConcurrentTableSharedStore::constructPrime(CVarRef v,
return false;
}
}
item.value = SharedVariant::Create(v, false);
item.value = new SharedVariant(v, false);
return true;
}
@@ -38,7 +38,7 @@ namespace HPHP {
class ConcurrentTableSharedStore : public SharedStore {
public:
ConcurrentTableSharedStore(int id)
explicit ConcurrentTableSharedStore(int id)
: SharedStore(id), m_lockingFlag(false), m_purgeCounter(0) {}
virtual int size() {
@@ -62,7 +62,7 @@ public:
protected:
virtual SharedVariant* construct(CVarRef v) {
return SharedVariant::Create(v, false);
return new SharedVariant(v, false);
}
struct charHashCompare {
+40 -19
Ver Arquivo
@@ -38,11 +38,7 @@ ImmutableMap* ImmutableMap::Create(ArrayData* arr,
try {
for (ArrayIter it(arr); !it.end(); it.next()) {
SharedVariant* key = SharedVariant::Create(it.first(), false, true,
unserializeObj);
SharedVariant* val = SharedVariant::Create(it.secondRef(), false, true,
unserializeObj);
ret->add(ret->m.m_num, key, val);
ret->add(ret->m.m_num, it.first(), it.secondRef(), unserializeObj);
++ret->m.m_num;
}
} catch (...) {
@@ -57,36 +53,62 @@ HOT_FUNC
void ImmutableMap::Destroy(ImmutableMap* map) {
Bucket* buckets = map->buckets();
for (int i = 0; i < map->m.m_num; i++) {
delete buckets[i].key;
delete buckets[i].val;
(*(SharedVariant*)&buckets[i].val).~SharedVariant();
}
free(map);
}
HOT_FUNC
void ImmutableMap::add(int pos, SharedVariant *key, SharedVariant *val) {
void ImmutableMap::addVal(int pos, int hash_pos,
CVarRef val, bool unserializeObj) {
// NOTE: no check on duplication because we assume the original array has no
// duplication
Bucket* bucket = buckets() + pos;
bucket->key = key;
bucket->val = val;
int hash_pos =
(key->is(KindOfInt64) ?
key->intData() : key->getStringData()->hash()) & m.m_capacity_mask;
new (&bucket->val) SharedVariant(val, false, true, unserializeObj);
int& hp = hash()[hash_pos];
bucket->next = hp;
hp = pos;
}
HOT_FUNC
void ImmutableMap::add(int pos, CVarRef key, CVarRef val, bool unserializeObj) {
int64_t ikey;
StringData* skey;
int32_t hash;
Bucket* b = buckets() + pos;
switch (key.getType()) {
case KindOfInt64: {
hash = ikey = key.toInt64();
b->setIntKey(ikey);
break;
}
case KindOfString: {
skey = StringData::GetStaticString(key.getStringData());
goto static_case;
}
case KindOfStaticString: {
skey = key.getStringData();
static_case:
hash = skey->hash();
b->setStrKey(skey, hash);
break;
}
default: not_reached();
}
addVal(pos, hash & m.m_capacity_mask, val, unserializeObj);
}
#define STR_HASH(x) (int32_t(x) | 0x80000000)
HOT_FUNC
int ImmutableMap::indexOf(const StringData* key) {
strhash_t h = key->hash();
strhash_t h = STR_HASH(key->hash());
int bucket = hash()[h & m.m_capacity_mask];
Bucket* b = buckets();
while (bucket != -1) {
if (!b[bucket].key->is(KindOfInt64) &&
key->same(b[bucket].key->getStringData())) {
Bucket* cand = &b[bucket];
if (cand->hash() == h && (cand->skey == key || key->same(cand->skey))) {
return bucket;
}
bucket = b[bucket].next;
@@ -99,8 +121,7 @@ int ImmutableMap::indexOf(int64_t key) {
int bucket = hash()[key & m.m_capacity_mask];
Bucket* b = buckets();
while (bucket != -1) {
if (b[bucket].key->is(KindOfInt64) &&
key == b[bucket].key->intData()) {
if (b[bucket].hasIntKey() && key == b[bucket].ikey) {
return bucket;
}
bucket = b[bucket].next;
+41 -12
Ver Arquivo
@@ -25,7 +25,6 @@
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class SharedVariant;
/**
* an immutable map is a php-style array that can take strings and
* ints as keys. the map also stores the order in which the elements
@@ -37,14 +36,19 @@ public:
int indexOf(const StringData* key);
int indexOf(int64_t key);
SharedVariant* getKeyIndex(int index) {
Variant getKey(int index) {
assert(index < size());
return buckets()[index].key;
Bucket* b = &buckets()[index];
if (b->hasIntKey()) {
return b->ikey;
} else {
return b->skey;
}
}
SharedVariant* getValIndex(int index) {
SharedVariant* getValue(int index) {
assert(index < size());
return buckets()[index].val;
return (SharedVariant*)&buckets()[index].val;
}
unsigned size() const {
@@ -65,18 +69,43 @@ public:
static ImmutableMap* Create(ArrayData* arr,
bool unserializeObj);
static void Destroy(ImmutableMap* im);
private:
ImmutableMap() {}
~ImmutableMap() {}
void add(int pos, SharedVariant *key, SharedVariant *val);
struct Bucket {
/** index of the next bucket, or -1 if the end of a chain */
int next;
/** the value of this bucket */
SharedVariant *key;
SharedVariant *val;
/* similar to HphpArray::Elm */
union {
int64_t ikey;
StringData* skey;
};
// cannot declare SharedVariant here because of cyclic header
// includes
TypedValueAux val;
bool hasStrKey() const {
return val.hash() != 0;
}
bool hasIntKey() const {
return val.hash() == 0;
}
int32_t hash() const {
return val.hash();
}
void setStrKey(StringData* k, strhash_t h) {
skey = k;
val.hash() = int32_t(h) | 0x80000000;
}
void setIntKey(int64_t k) {
ikey = k;
val.hash() = 0;
}
};
private:
ImmutableMap() {}
~ImmutableMap() {}
void addVal(int pos, int hash_pos, CVarRef val, bool unserializeObj);
void add(int pos, CVarRef key, CVarRef val, bool unserializeObj);
/** index of the beginning of each hash chain */
int *hash() const { return (int*)(this + 1); }
/** buckets, stored in index order */
+51 -23
Ver Arquivo
@@ -27,17 +27,16 @@ IMPLEMENT_SMART_ALLOCATION_HOT(SharedMap);
///////////////////////////////////////////////////////////////////////////////
HOT_FUNC
CVarRef SharedMap::getValueRef(ssize_t pos) const {
SharedVariant *sv = m_arr->getValue(pos);
SharedVariant *sv = getValueImpl(pos);
DataType t = sv->getType();
if (!IS_REFCOUNTED_TYPE(t)) return sv->asCVarRef();
if (LIKELY(m_localCache != nullptr)) {
assert(unsigned(pos) < m_arr->arrCap());
assert(unsigned(pos) < size());
TypedValue* tv = &m_localCache[pos];
if (tv->m_type != KindOfUninit) return tvAsCVarRef(tv);
} else {
static_assert(KindOfUninit == 0, "must be 0 since we use smart_calloc");
unsigned cap = m_arr->arrCap();
m_localCache = (TypedValue*) smart_calloc(cap, sizeof(TypedValue));
m_localCache = (TypedValue*) smart_calloc(size(), sizeof(TypedValue));
}
TypedValue* tv = &m_localCache[pos];
tvAsVariant(tv) = sv->toLocal();
@@ -48,7 +47,7 @@ CVarRef SharedMap::getValueRef(ssize_t pos) const {
HOT_FUNC
SharedMap::~SharedMap() {
if (m_localCache) {
for (TypedValue* tv = m_localCache, *end = tv + m_arr->arrCap();
for (TypedValue* tv = m_localCache, *end = tv + size();
tv < end; ++tv) {
tvRefcountedDecRef(tv);
}
@@ -56,24 +55,29 @@ SharedMap::~SharedMap() {
}
}
bool SharedMap::exists(const StringData* k) const {
return m_arr->getIndex(k) != -1;
}
bool SharedMap::exists(int64_t k) const {
return m_arr->getIndex(k) != -1;
ssize_t SharedMap::getIndex(const StringData* k) const {
if (isVector()) return -1;
return m_map->indexOf(k);
}
ssize_t SharedMap::getIndex(int64_t k) const {
return m_arr->getIndex(k);
if (isVector()) {
if (k < 0 || (size_t)k >= m_vec->m_size) return -1;
return k;
}
return m_map->indexOf(k);
}
ssize_t SharedMap::getIndex(const StringData* k) const {
return m_arr->getIndex(k);
bool SharedMap::exists(const StringData* k) const {
return getIndex(k) != -1;
}
bool SharedMap::exists(int64_t k) const {
return getIndex(k) != -1;
}
CVarRef SharedMap::get(const StringData* k, bool error /* = false */) const {
int index = m_arr->getIndex(k);
int index = getIndex(k);
if (index == -1) {
return error ? getNotFound(k) : null_variant;
}
@@ -81,7 +85,7 @@ CVarRef SharedMap::get(const StringData* k, bool error /* = false */) const {
}
CVarRef SharedMap::get(int64_t k, bool error /* = false */) const {
int index = m_arr->getIndex(k);
int index = getIndex(k);
if (index == -1) {
return error ? getNotFound(k) : null_variant;
}
@@ -171,25 +175,25 @@ ArrayData *SharedMap::prepend(CVarRef v, bool copy) {
}
ArrayData *SharedMap::escalate() const {
ArrayData *ret = m_arr->loadElems(*this);
ArrayData *ret = loadElems();
assert(!ret->isStatic());
return ret;
}
TypedValue* SharedMap::nvGet(int64_t k) const {
int index = m_arr->getIndex(k);
int index = getIndex(k);
if (index == -1) return nullptr;
return (TypedValue*)&getValueRef(index);
}
TypedValue* SharedMap::nvGet(const StringData* key) const {
int index = m_arr->getIndex(key);
int index = getIndex(key);
if (index == -1) return nullptr;
return (TypedValue*)&getValueRef(index);
}
void SharedMap::nvGetKey(TypedValue* out, ssize_t pos) {
Variant k = m_arr->getKey(pos);
Variant k = getKey(pos);
TypedValue* tv = k.asTypedValue();
// copy w/out clobbering out->_count.
out->m_type = tv->m_type;
@@ -202,22 +206,46 @@ TypedValue* SharedMap::nvGetValueRef(ssize_t pos) {
}
TypedValue* SharedMap::nvGetCell(int64_t k) const {
int index = m_arr->getIndex(k);
int index = getIndex(k);
return index != -1 ? getValueRef(index).getTypedAccessor() :
nvGetNotFound(k);
}
TypedValue* SharedMap::nvGetCell(const StringData* key) const {
int index = m_arr->getIndex(key);
int index = getIndex(key);
return index != -1 ? getValueRef(index).getTypedAccessor() :
nvGetNotFound(key);
}
ArrayData* SharedMap::escalateForSort() {
ArrayData *ret = m_arr->loadElems(*this, true /* mapInit */);
ArrayData *ret = loadElems(true /* mapInit */);
assert(!ret->isStatic());
return ret;
}
ArrayData* SharedMap::loadElems(bool mapInit /* = false */) const {
uint count = size();
bool isVec = isVector();
auto ai =
mapInit ? ArrayInit(count, ArrayInit::mapInit) :
isVec ? ArrayInit(count, ArrayInit::vectorInit) :
ArrayInit(count);
if (isVec) {
for (uint i = 0; i < count; i++) {
ai.set(getValueRef(i));
}
} else {
for (uint i = 0; i < count; i++) {
ai.add(m_map->getKey(i), getValueRef(i),
true);
}
}
ArrayData* elems = ai.create();
if (elems->isStatic()) elems = elems->copy();
return elems;
}
///////////////////////////////////////////////////////////////////////////////
}
+21 -5
Ver Arquivo
@@ -31,10 +31,11 @@ namespace HPHP {
*/
class SharedMap : public ArrayData {
public:
SharedMap(SharedVariant* source)
explicit SharedMap(SharedVariant* source)
: ArrayData(kSharedMap)
, m_arr(source)
, m_localCache(nullptr) {
m_map = source->getMap();
m_isVector = source->getIsVector();
}
~SharedMap();
@@ -57,11 +58,19 @@ public:
using ArrayData::remove;
ssize_t vsize() const {
return m_arr->arrSize();
return isVector() ? m_vec->m_size : m_map->size();
}
Variant getKey(ssize_t pos) const {
return m_arr->getKey(pos);
if (isVector()) {
assert(pos < (ssize_t)m_vec->m_size);
return pos;
}
return m_map->getKey(pos);
}
SharedVariant* getValueImpl(ssize_t pos) const {
return isVector() ? m_vec->getValue(pos) : m_map->getValue(pos);
}
Variant getValue(ssize_t pos) const { return getValueRef(pos); }
@@ -119,9 +128,16 @@ public:
virtual ArrayData *escalate() const;
virtual ArrayData* escalateForSort();
ArrayData* loadElems(bool mapInit = false) const;
private:
SharedVariant *m_arr;
bool m_isVector;
union {
ImmutableMap* m_map;
VectorData* m_vec;
};
mutable TypedValue* m_localCache;
bool isVector() const { return m_isVector; }
};
///////////////////////////////////////////////////////////////////////////////
+8 -92
Ver Arquivo
@@ -28,7 +28,6 @@ SharedVariant::SharedVariant(CVarRef source, bool serialized,
bool unserializeObj /* = false */)
: m_flags(0) {
assert(!serialized || source.isString());
m_count = 1;
m_type = source.getType();
switch (m_type) {
case KindOfBoolean:
@@ -91,9 +90,7 @@ StringCase:
setIsVector();
m_data.vec = new (arr->size()) VectorData();
for (ArrayIter it(arr); !it.end(); it.next()) {
SharedVariant* val = Create(it.secondRef(), false, true,
unserializeObj);
m_data.vec->vals()[m_data.vec->m_size++] = val;
m_data.vec->add(it.secondRef(), unserializeObj);
}
} else {
m_data.map = ImmutableMap::Create(arr, unserializeObj);
@@ -246,88 +243,6 @@ SharedVariant::~SharedVariant() {
///////////////////////////////////////////////////////////////////////////////
HOT_FUNC
int SharedVariant::getIndex(const StringData* key) {
assert(is(KindOfArray));
if (getIsVector()) return -1;
return m_data.map->indexOf(key);
}
int SharedVariant::getIndex(int64_t key) {
assert(is(KindOfArray));
if (getIsVector()) {
if (key < 0 || (size_t) key >= m_data.vec->m_size) return -1;
return key;
}
return m_data.map->indexOf(key);
}
Variant SharedVariant::getKey(ssize_t pos) const {
assert(is(KindOfArray));
if (getIsVector()) {
assert(pos < (ssize_t) m_data.vec->m_size);
return pos;
}
return m_data.map->getKeyIndex(pos)->toLocal();
}
HOT_FUNC
SharedVariant* SharedVariant::getValue(ssize_t pos) const {
assert(is(KindOfArray));
if (getIsVector()) {
assert(pos < (ssize_t) m_data.vec->m_size);
return m_data.vec->vals()[pos];
}
return m_data.map->getValIndex(pos);
}
ArrayData* SharedVariant::loadElems(const SharedMap &sharedMap,
bool mapInit /* = false */) {
assert(is(KindOfArray));
uint count = arrSize();
bool isVector = getIsVector();
auto ai =
mapInit ? ArrayInit(count, ArrayInit::mapInit) :
isVector ? ArrayInit(count, ArrayInit::vectorInit) :
ArrayInit(count);
if (isVector) {
for (uint i = 0; i < count; i++) {
ai.set(sharedMap.getValueRef(i));
}
} else {
for (uint i = 0; i < count; i++) {
ai.add(m_data.map->getKeyIndex(i)->toLocal(), sharedMap.getValueRef(i),
true);
}
}
ArrayData* elems = ai.create();
if (elems->isStatic()) elems = elems->copy();
return elems;
}
int SharedVariant::countReachable() const {
int count = 1;
if (getType() == KindOfArray) {
int size = arrSize();
if (!getIsVector()) {
count += size; // for keys
}
for (int i = 0; i < size; i++) {
SharedVariant* p = getValue(i);
count += p->countReachable(); // for values
}
}
return count;
}
SharedVariant *SharedVariant::Create
(CVarRef source, bool serialized, bool inner /* = false */,
bool unserializeObj /* = false*/) {
return new SharedVariant(source, serialized, inner, unserializeObj);
}
SharedVariant* SharedVariant::convertObj(CVarRef var) {
if (!var.is(KindOfObject) || getObjAttempted()) {
return nullptr;
@@ -367,14 +282,14 @@ int32_t SharedVariant::getSpaceUsage() const {
size += sizeof(VectorData) +
sizeof(SharedVariant*) * m_data.vec->m_size;
for (size_t i = 0; i < m_data.vec->m_size; i++) {
size += m_data.vec->vals()[i]->getSpaceUsage();
size += m_data.vec->getValue(i)->getSpaceUsage();
}
} else {
ImmutableMap *map = m_data.map;
size += map->getStructSize();
for (int i = 0; i < map->size(); i++) {
size += map->getKeyIndex(i)->getSpaceUsage();
size += map->getValIndex(i)->getSpaceUsage();
size += sizeof(int64_t);
size += map->getValue(i)->getSpaceUsage();
}
}
break;
@@ -421,7 +336,7 @@ void SharedVariant::getStats(SharedVariantStats *stats) const {
stats->dataTotalSize = sizeof(SharedVariant) + sizeof(VectorData);
stats->dataTotalSize += sizeof(SharedVariant*) * m_data.vec->m_size;
for (size_t i = 0; i < m_data.vec->m_size; i++) {
SharedVariant *v = m_data.vec->vals()[i];
SharedVariant *v = m_data.vec->getValue(i);
SharedVariantStats childStats;
v->getStats(&childStats);
stats->addChildStats(&childStats);
@@ -431,9 +346,10 @@ void SharedVariant::getStats(SharedVariantStats *stats) const {
stats->dataTotalSize = sizeof(SharedVariant) + map->getStructSize();
for (int i = 0; i < map->size(); i++) {
SharedVariantStats childStats;
map->getKeyIndex(i)->getStats(&childStats);
// for key
childStats.dataSize = childStats.dataTotalSize = sizeof(int64_t);
stats->addChildStats(&childStats);
map->getValIndex(i)->getStats(&childStats);
map->getValue(i)->getStats(&childStats);
stats->addChildStats(&childStats);
}
}
+40 -55
Ver Arquivo
@@ -42,6 +42,8 @@ class SharedMap;
class SharedVariantStats;
class VectorData;
///////////////////////////////////////////////////////////////////////////////
class SharedVariant {
@@ -50,11 +52,6 @@ public:
bool unserializeObj = false);
~SharedVariant();
// Create will do the wrapped check before creating a SharedVariant
static SharedVariant* Create(CVarRef source, bool serialized,
bool inner = false,
bool unserializeObj = false);
bool is(DataType d) const { return m_type == d; }
DataType getType() const { return (DataType)m_type; }
CVarRef asCVarRef() const {
@@ -86,28 +83,6 @@ public:
return m_data.str->hash();
}
size_t arrSize() const {
assert(is(KindOfArray));
if (getIsVector()) return m_data.vec->m_size;
return m_data.map->size();
}
size_t arrCap() const {
assert(is(KindOfArray));
if (getIsVector()) return m_data.vec->m_size;
return m_data.map->capacity();
}
int getIndex(int64_t key);
int getIndex(const StringData* key);
ArrayData* loadElems(const SharedMap &sharedMap,
bool mapInit = false);
Variant getKey(ssize_t pos) const;
SharedVariant* getValue(ssize_t pos) const;
// implementing LeakDetectable
void dump(std::string &out);
@@ -122,34 +97,7 @@ public:
SharedVariant *convertObj(CVarRef var);
bool isUnserializedObj() { return getIsObj(); }
int countReachable() const;
private:
class VectorData {
public:
union {
size_t m_size;
SharedVariant* m_align_dummy;
};
VectorData() : m_size(0) {}
~VectorData() {
SharedVariant** v = vals();
for (size_t i = 0; i < m_size; i++) {
delete v[i];
}
}
SharedVariant** vals() { return (SharedVariant**)(this + 1); }
void *operator new(size_t sz, int num) {
assert(sz == sizeof(VectorData));
return malloc(sizeof(VectorData) + num * sizeof(SharedVariant*));
}
void operator delete(void* ptr) { free(ptr); }
// just to keep the compiler happy; used if the constructor throws
void operator delete(void* ptr, int num) { free(ptr); }
};
/*
* Keep the object layout binary compatible with Variant for primitive types.
* We want to have compile time assertion to guard it but still want to have
@@ -211,7 +159,6 @@ private:
void setSerializedArray() { m_flags |= SerializedArray;}
void clearSerializedArray() { m_flags &= ~SerializedArray;}
bool getIsVector() const { return (bool)(m_flags & IsVector);}
void setIsVector() { m_flags |= IsVector;}
void clearIsVector() { m_flags &= ~IsVector;}
@@ -222,6 +169,44 @@ private:
bool getObjAttempted() const { return (bool)(m_flags & ObjAttempted);}
void setObjAttempted() { m_flags |= ObjAttempted;}
void clearObjAttempted() { m_flags &= ~ObjAttempted;}
public:
bool getIsVector() const { return (bool)(m_flags & IsVector);}
ImmutableMap* getMap() const { return m_data.map; }
};
/* VectorData is used when when all the keys are integers
* in the sequential range 0 to n-1. */
class VectorData {
public:
union {
size_t m_size;
SharedVariant* m_align_dummy;
};
VectorData() : m_size(0) {}
~VectorData() {
SharedVariant* v = vals();
for (size_t i = 0; i < m_size; i++) {
v[i].~SharedVariant();
}
}
SharedVariant* getValue(ssize_t pos) {
return &((SharedVariant *)(this + 1))[pos];
}
SharedVariant* vals() { return (SharedVariant*)(this + 1); }
void *operator new(size_t sz, int num) {
assert(sz == sizeof(VectorData));
return malloc(sizeof(VectorData) + num * sizeof(SharedVariant));
}
void add(CVarRef val, bool unserializeObj) {
/* placement new */
new (&vals()[m_size++]) SharedVariant(val, false, true, unserializeObj);
}
void operator delete(void* ptr) { free(ptr); }
// just to keep the compiler happy; used if the constructor throws
void operator delete(void* ptr, int num) { free(ptr); }
};
class SharedVariantStats {