areadlink
base64
bind
+bitrotate
byteswap
c-ctype
c-strcase
util/xml.c util/xml.h \
util/virterror.c util/virterror_internal.h \
util/virhash.c util/virhash.h \
+ util/virhashcode.c util/virhashcode.h \
util/virkeycode.c util/virkeycode.h \
util/virkeymaps.h \
util/virnetdev.h util/virnetdev.c \
#include "logging.h"
#include "virfile.h"
#include "virhash.h"
+#include "virhashcode.h"
#define CGROUP_MAX_VAL 512
}
-static uint32_t virCgroupPidCode(const void *name)
+static uint32_t virCgroupPidCode(const void *name, uint32_t seed)
{
- return (uint32_t)(intptr_t)name;
+ unsigned long pid = (unsigned long)(intptr_t)name;
+ return virHashCodeGen(&pid, sizeof(pid), seed);
}
static bool virCgroupPidEqual(const void *namea, const void *nameb)
{
#include "virhash.h"
#include "memory.h"
#include "logging.h"
+#include "virhashcode.h"
+#include "virrandom.h"
#define VIR_FROM_THIS VIR_FROM_NONE
*/
struct _virHashTable {
virHashEntryPtr *table;
+ uint32_t seed;
size_t size;
size_t nbElems;
/* True iff we are iterating over hash entries. */
virHashKeyFree keyFree;
};
-static uint32_t virHashStrCode(const void *name)
+static uint32_t virHashStrCode(const void *name, uint32_t seed)
{
- const char *str = name;
- uint32_t value = 0L;
- char ch;
-
- if (str != NULL) {
- value += 30 * (*str);
- while ((ch = *str++) != 0) {
- value =
- value ^ ((value << 5) + (value >> 3) + (uint32_t) ch);
- }
- }
- return value;
+ return virHashCodeGen(name, strlen(name), seed);
}
static bool virHashStrEqual(const void *namea, const void *nameb)
static size_t
virHashComputeKey(virHashTablePtr table, const void *name)
{
- uint32_t value = table->keyCode(name);
+ uint32_t value = table->keyCode(name, table->seed);
return (value % table->size);
}
return NULL;
}
+ table->seed = virRandomBits(32);
table->size = size;
table->nbElems = 0;
table->dataFree = dataFree;
/**
* virHashKeyCode:
* @name: the hash key
+ * @seed: random seed
*
- * Compute the hash code corresponding to the key @name
+ * Compute the hash code corresponding to the key @name, using
+ * @seed to perturb the hashing algorithm
*
* Returns the hash code
*/
-typedef uint32_t (*virHashKeyCode)(const void *name);
+typedef uint32_t (*virHashKeyCode)(const void *name,
+ uint32_t seed);
/**
* virHashKeyEqual:
* @namea: the first hash key
--- /dev/null
+/*
+ * virhashcode.c: hash code generation
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The hash code generation is based on the public domain MurmurHash3 from Austin Appleby:
+ * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
+ *
+ * We use only the 32 bit variant because the 2 produce different results while
+ * we need to produce the same result regardless of the architecture as
+ * clients can be both 64 or 32 bit at the same time.
+ */
+
+#include <config.h>
+
+#include "virhashcode.h"
+#include "bitrotate.h"
+
+/* slower than original but handles platforms that do only aligned reads */
+__attribute__((always_inline))
+static uint32_t getblock(const uint8_t *p, int i)
+{
+ uint32_t r;
+ size_t size = sizeof(r);
+
+ memcpy(&r, &p[i * size], size);
+
+ return r;
+}
+
+/*
+ * Finalization mix - force all bits of a hash block to avalanche
+ */
+__attribute__((always_inline))
+static uint32_t fmix(uint32_t h)
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+
+uint32_t virHashCodeGen(const void *key, size_t len, uint32_t seed)
+{
+ const uint8_t *blocks;
+ const uint8_t *tail;
+ size_t nblocks;
+ uint32_t h1;
+ uint32_t k1;
+ uint32_t c1;
+ uint32_t c2;
+ size_t i;
+
+ blocks = (const uint8_t *)key;
+ nblocks = len / 4;
+ h1 = seed;
+ c1 = 0xcc9e2d51;
+ c2 = 0x1b873593;
+
+ /* body */
+
+ for (i = 0; i < nblocks; i++) {
+
+ k1 = getblock(blocks, i);
+
+ k1 *= c1;
+ k1 = rotl32(k1, 15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = rotl32(h1, 13);
+ h1 = h1 * 5 + 0xe6546b64;
+ }
+
+ /* tail */
+
+ tail = (const uint8_t *)key + nblocks * 4;
+
+ k1 = 0;
+
+ switch (len & 3) {
+ case 3:
+ k1 ^= tail[2] << 16;
+ /* fallthrough */
+ case 2:
+ k1 ^= tail[1] << 8;
+ /* fallthrough */
+ case 1:
+ k1 ^= tail[0];
+ k1 *= c1;
+ k1 = rotl32(k1, 15);
+ k1 *= c2;
+ h1 ^= k1;
+ /* fallthrough */
+ default:
+ break;
+ }
+
+ /* finalization */
+
+ h1 ^= len;
+ h1 = fmix(h1);
+
+ return h1;
+}
--- /dev/null
+/*
+ * virhashcode.h: hash code generation
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The hash code generation is based on the public domain MurmurHash3 from Austin Appleby:
+ * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
+ *
+ * We use only the 32 bit variant because the 2 produce different result while
+ * we need to produce the same result regardless of the architecture as
+ * clients can be both 64 or 32 bit at the same time.
+ */
+
+#ifndef __VIR_HASH_CODE_H__
+# define __VIR_HASH_CODE_H__
+
+# include "internal.h"
+
+extern uint32_t virHashCodeGen(const void *key, size_t len, uint32_t seed);
+
+#endif /* __VIR_HASH_CODE_H__ */