X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Futil%2Fcontainer_bloomfilter.c;h=8c226f67d9581eee16d0b186133d8359ef2129c2;hb=8f654f30c3c4987c9ca1b564d6e6f2d75ae24862;hp=8b76ef8dc03d74966e773ad9627f7e990f11fa11;hpb=0a217a8df1657b4334b55b0e4a6c7837a8dbcfd9;p=oweals%2Fgnunet.git diff --git a/src/util/container_bloomfilter.c b/src/util/container_bloomfilter.c index 8b76ef8dc..8c226f67d 100644 --- a/src/util/container_bloomfilter.c +++ b/src/util/container_bloomfilter.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2006, 2008 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2003, 2004, 2006, 2008, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -44,6 +44,12 @@ #include "gnunet_container_lib.h" #include "gnunet_disk_lib.h" +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + struct GNUNET_CONTAINER_BloomFilter { @@ -60,7 +66,7 @@ struct GNUNET_CONTAINER_BloomFilter /** * The bit counter file on disk */ - int fd; + struct GNUNET_DISK_FileHandle *fh; /** * How many bits we set for each stored element @@ -70,11 +76,43 @@ struct GNUNET_CONTAINER_BloomFilter /** * Size of bitArray in bytes */ - unsigned int bitArraySize; + size_t bitArraySize; }; + +/** + * Get size of the bloom filter. + * + * @param bf the filter + * @return number of bytes used for the data of the bloom filter + */ +size_t +GNUNET_CONTAINER_bloomfilter_get_size (const struct GNUNET_CONTAINER_BloomFilter + *bf) +{ + if (bf == NULL) + return 0; + return bf->bitArraySize; +} + + +/** + * Copy an existing memory. Any association with a file + * on-disk will be lost in the process. + * @param bf the filter to copy + * @return copy of the bf + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_CONTAINER_bloomfilter_copy (const struct GNUNET_CONTAINER_BloomFilter + *bf) +{ + return GNUNET_CONTAINER_bloomfilter_init (bf->bitArray, bf->bitArraySize, + bf->addressesPerElement); +} + + /** * Sets a bit active in the bitArray. Increment bit-specific * usage counter on disk only if below 4bit max (==15). @@ -85,7 +123,7 @@ struct GNUNET_CONTAINER_BloomFilter static void setBit (char *bitArray, unsigned int bitIdx) { - unsigned int arraySlot; + size_t arraySlot; unsigned int targetBit; arraySlot = bitIdx / 8; @@ -103,7 +141,7 @@ setBit (char *bitArray, unsigned int bitIdx) static void clearBit (char *bitArray, unsigned int bitIdx) { - unsigned int slot; + size_t slot; unsigned int targetBit; slot = bitIdx / 8; @@ -121,7 +159,7 @@ clearBit (char *bitArray, unsigned int bitIdx) static int testBit (char *bitArray, unsigned int bitIdx) { - unsigned int slot; + size_t slot; unsigned int targetBit; slot = bitIdx / 8; @@ -139,43 +177,46 @@ testBit (char *bitArray, unsigned int bitIdx) * * @param bitArray memory area to set the bit in * @param bitIdx which bit to test - * @param fd A file to keep the 4 bit address usage counters in + * @param fh A file to keep the 4 bit address usage counters in */ static void -incrementBit (char *bitArray, unsigned int bitIdx, int fd) +incrementBit (char *bitArray, unsigned int bitIdx, + const struct GNUNET_DISK_FileHandle *fh) { - unsigned int fileSlot; + OFF_T fileSlot; unsigned char value; unsigned int high; unsigned int low; unsigned int targetLoc; setBit (bitArray, bitIdx); - if (fd == -1) + if (GNUNET_DISK_handle_invalid (fh)) return; /* Update the counter file on disk */ fileSlot = bitIdx / 2; targetLoc = bitIdx % 2; - GNUNET_assert (fileSlot == (unsigned int) LSEEK (fd, fileSlot, SEEK_SET)); - if (1 != READ (fd, &value, 1)) + GNUNET_assert (fileSlot == + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); + if (1 != GNUNET_DISK_file_read (fh, &value, 1)) value = 0; low = value & 0xF; high = (value & (~0xF)) >> 4; if (targetLoc == 0) - { - if (low < 0xF) - low++; - } + { + if (low < 0xF) + low++; + } else - { - if (high < 0xF) - high++; - } + { + if (high < 0xF) + high++; + } value = ((high << 4) | low); - GNUNET_assert (fileSlot == (unsigned int) LSEEK (fd, fileSlot, SEEK_SET)); - GNUNET_assert (1 == WRITE (fd, &value, 1)); + GNUNET_assert (fileSlot == + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); + GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); } /** @@ -184,50 +225,51 @@ incrementBit (char *bitArray, unsigned int bitIdx, int fd) * * @param bitArray memory area to set the bit in * @param bitIdx which bit to test - * @param fd A file to keep the 4bit address usage counters in + * @param fh A file to keep the 4bit address usage counters in */ static void -decrementBit (char *bitArray, unsigned int bitIdx, int fd) +decrementBit (char *bitArray, unsigned int bitIdx, + const struct GNUNET_DISK_FileHandle *fh) { - unsigned int fileSlot; + OFF_T fileSlot; unsigned char value; unsigned int high; unsigned int low; unsigned int targetLoc; - if (fd == -1) + if (GNUNET_DISK_handle_invalid (fh)) return; /* cannot decrement! */ /* Each char slot in the counter file holds two 4 bit counters */ fileSlot = bitIdx / 2; targetLoc = bitIdx % 2; - LSEEK (fd, fileSlot, SEEK_SET); - if (1 != READ (fd, &value, 1)) + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET); + if (1 != GNUNET_DISK_file_read (fh, &value, 1)) value = 0; low = value & 0xF; high = (value & 0xF0) >> 4; /* decrement, but once we have reached the max, never go back! */ if (targetLoc == 0) + { + if ((low > 0) && (low < 0xF)) + low--; + if (low == 0) { - if ((low > 0) && (low < 0xF)) - low--; - if (low == 0) - { - clearBit (bitArray, bitIdx); - } + clearBit (bitArray, bitIdx); } + } else + { + if ((high > 0) && (high < 0xF)) + high--; + if (high == 0) { - if ((high > 0) && (high < 0xF)) - high--; - if (high == 0) - { - clearBit (bitArray, bitIdx); - } + clearBit (bitArray, bitIdx); } + } value = ((high << 4) | low); - LSEEK (fd, fileSlot, SEEK_SET); - GNUNET_assert (1 == WRITE (fd, &value, 1)); + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET); + GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); } #define BUFFSIZE 65536 @@ -235,54 +277,57 @@ decrementBit (char *bitArray, unsigned int bitIdx, int fd) /** * Creates a file filled with zeroes * - * @param fd the file handle + * @param fh the file handle * @param size the size of the file * @return GNUNET_OK if created ok, GNUNET_SYSERR otherwise */ static int -makeEmptyFile (int fd, unsigned int size) +make_empty_file (const struct GNUNET_DISK_FileHandle *fh, size_t size) { - char *buffer; - unsigned int bytesleft = size; + char buffer[BUFFSIZE]; + size_t bytesleft = size; int res = 0; - if (fd == -1) + if (GNUNET_DISK_handle_invalid (fh)) return GNUNET_SYSERR; - buffer = GNUNET_malloc (BUFFSIZE); - memset (buffer, 0, BUFFSIZE); - LSEEK (fd, 0, SEEK_SET); - + memset (buffer, 0, sizeof (buffer)); + GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_SET); while (bytesleft > 0) + { + if (bytesleft > sizeof (buffer)) + { + res = GNUNET_DISK_file_write (fh, buffer, sizeof (buffer)); + if (res >= 0) + bytesleft -= res; + } + else { - if (bytesleft > BUFFSIZE) - { - res = WRITE (fd, buffer, BUFFSIZE); - bytesleft -= BUFFSIZE; - } - else - { - res = WRITE (fd, buffer, bytesleft); - bytesleft = 0; - } - GNUNET_assert (res != -1); + res = GNUNET_DISK_file_write (fh, buffer, bytesleft); + if (res >= 0) + bytesleft -= res; } - GNUNET_free (buffer); + if (GNUNET_SYSERR == res) + return GNUNET_SYSERR; + } return GNUNET_OK; } -/* ************** GNUNET_CONTAINER_BloomFilter GNUNET_CRYPTO_hash iterator ********* */ +/* ************** GNUNET_CONTAINER_BloomFilter iterator ********* */ /** * Iterator (callback) method to be called by the * bloomfilter iterator on each bit that is to be * set or tested for the key. * + * @param cls closure * @param bf the filter to manipulate * @param bit the current bit - * @param additional context specific argument + * @return GNUNET_YES to continue, GNUNET_NO to stop early */ -typedef void (*BitIterator) (struct GNUNET_CONTAINER_BloomFilter * bf, - unsigned int bit, void *arg); +typedef int (*BitIterator) (void *cls, + const struct GNUNET_CONTAINER_BloomFilter * bf, + unsigned int bit); + /** * Call an iterator for each bit that the bloomfilter @@ -294,81 +339,102 @@ typedef void (*BitIterator) (struct GNUNET_CONTAINER_BloomFilter * bf, * @param key the key for which we iterate over the BF bits */ static void -iterateBits (struct GNUNET_CONTAINER_BloomFilter *bf, +iterateBits (const struct GNUNET_CONTAINER_BloomFilter *bf, BitIterator callback, void *arg, const GNUNET_HashCode * key) { GNUNET_HashCode tmp[2]; int bitCount; - int round; + unsigned int round; unsigned int slot = 0; bitCount = bf->addressesPerElement; - memcpy (&tmp[0], key, sizeof (GNUNET_HashCode)); + tmp[0] = *key; round = 0; + GNUNET_assert (bf->bitArraySize > 0); + GNUNET_assert (bf->bitArraySize * 8LL > bf->bitArraySize); while (bitCount > 0) + { + while (slot < (sizeof (GNUNET_HashCode) / sizeof (uint32_t))) + { + if (GNUNET_YES != + callback (arg, bf, + (((uint32_t *) & tmp[round & 1])[slot]) % + ((bf->bitArraySize * 8LL)))) + return; + slot++; + bitCount--; + if (bitCount == 0) + break; + } + if (bitCount > 0) { - while (slot < (sizeof (GNUNET_HashCode) / sizeof (unsigned int))) - { - callback (bf, - (((unsigned int *) &tmp[round & 1])[slot]) & - ((bf->bitArraySize * 8) - 1), arg); - slot++; - bitCount--; - if (bitCount == 0) - break; - } - if (bitCount > 0) - { - GNUNET_CRYPTO_hash (&tmp[round & 1], sizeof (GNUNET_HashCode), - &tmp[(round + 1) & 1]); - round++; - slot = 0; - } + GNUNET_CRYPTO_hash (&tmp[round & 1], sizeof (GNUNET_HashCode), + &tmp[(round + 1) & 1]); + round++; + slot = 0; } + } } + /** * Callback: increment bit * + * @param cls pointer to writeable form of bf * @param bf the filter to manipulate * @param bit the bit to increment - * @param arg not used + * @return GNUNET_YES */ -static void -incrementBitCallback (struct GNUNET_CONTAINER_BloomFilter *bf, - unsigned int bit, void *arg) +static int +incrementBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, + unsigned int bit) { - incrementBit (bf->bitArray, bit, bf->fd); + struct GNUNET_CONTAINER_BloomFilter *b = cls; + + incrementBit (b->bitArray, bit, bf->fh); + return GNUNET_YES; } + /** * Callback: decrement bit * + * @param cls pointer to writeable form of bf * @param bf the filter to manipulate * @param bit the bit to decrement - * @param arg not used + * @return GNUNET_YES */ -static void -decrementBitCallback (struct GNUNET_CONTAINER_BloomFilter *bf, - unsigned int bit, void *arg) +static int +decrementBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, + unsigned int bit) { - decrementBit (bf->bitArray, bit, bf->fd); + struct GNUNET_CONTAINER_BloomFilter *b = cls; + + decrementBit (b->bitArray, bit, bf->fh); + return GNUNET_YES; } + /** * Callback: test if all bits are set * + * @param cls pointer set to GNUNET_NO if bit is not set * @param bf the filter * @param bit the bit to test - * @param arg pointer set to GNUNET_NO if bit is not set + * @return YES if the bit is set, NO if not */ -static void -testBitCallback (struct GNUNET_CONTAINER_BloomFilter *bf, unsigned int bit, - void *cls) +static int +testBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, + unsigned int bit) { int *arg = cls; + if (GNUNET_NO == testBit (bf->bitArray, bit)) + { *arg = GNUNET_NO; + return GNUNET_NO; + } + return GNUNET_YES; } /* *********************** INTERFACE **************** */ @@ -378,84 +444,147 @@ testBitCallback (struct GNUNET_CONTAINER_BloomFilter *bf, unsigned int bit, * * @param filename the name of the file (or the prefix) * @param size the size of the bloom-filter (number of - * bytes of storage space to use) + * bytes of storage space to use); will be rounded up + * to next power of 2 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per * element (number of bits set per element in the set) * @return the bloomfilter */ struct GNUNET_CONTAINER_BloomFilter * -GNUNET_CONTAINER_bloomfilter_load (const char *filename, unsigned int size, +GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size, unsigned int k) { struct GNUNET_CONTAINER_BloomFilter *bf; char *rbuff; - unsigned int pos; + OFF_T pos; int i; - unsigned int ui; + size_t ui; + OFF_T fsize; + int must_read; + GNUNET_assert (NULL != filename); if ((k == 0) || (size == 0)) return NULL; if (size < BUFFSIZE) size = BUFFSIZE; ui = 1; - while (ui < size) + while ( (ui < size) && + (ui * 2 > ui) ) ui *= 2; size = ui; /* make sure it's a power of 2 */ bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); /* Try to open a bloomfilter file */ - if (filename != NULL) + if (GNUNET_YES == GNUNET_DISK_file_test (filename)) + bf->fh = + GNUNET_DISK_file_open (filename, + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (NULL != bf->fh) + { + /* file existed, try to read it! */ + must_read = GNUNET_YES; + if (GNUNET_OK != + GNUNET_DISK_file_handle_size (bf->fh, &fsize)) + { + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + if (fsize == 0) { -#ifndef _MSC_VER - bf->fd = GNUNET_DISK_file_open (filename, O_RDWR | O_CREAT, - S_IRUSR | S_IWUSR); -#else - bf->fd = GNUNET_DISK_file_open (filename, - O_WRONLY | O_CREAT, S_IREAD | S_IWRITE); -#endif - if (-1 == bf->fd) - { - GNUNET_free (bf); - return NULL; - } - bf->filename = GNUNET_strdup (filename); + /* found existing empty file, just overwrite */ + if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } } + else if (fsize != size * 4LL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Size of file on disk is incorrect for this Bloom filter (want %llu, have %llu)\n"), + (unsigned long long) (size * 4LL), + (unsigned long long) fsize); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + } else + { + /* file did not exist, don't read, just create */ + must_read = GNUNET_NO; + bf->fh = + GNUNET_DISK_file_open (filename, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (NULL == bf->fh) + { + GNUNET_free (bf); + return NULL; + } + if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) { - bf->fd = -1; - bf->filename = NULL; + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; } + } + bf->filename = GNUNET_strdup (filename); /* Alloc block */ bf->bitArray = GNUNET_malloc_large (size); + if (bf->bitArray == NULL) + { + if (bf->fh != NULL) + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf->filename); + GNUNET_free (bf); + return NULL; + } bf->bitArraySize = size; bf->addressesPerElement = k; - memset (bf->bitArray, 0, bf->bitArraySize); - - if (bf->fd != -1) + if (GNUNET_YES != must_read) + return bf; /* already done! */ + /* Read from the file what bits we can */ + rbuff = GNUNET_malloc (BUFFSIZE); + pos = 0; + while (pos < size * 8LL) + { + int res; + + res = GNUNET_DISK_file_read (bf->fh, rbuff, BUFFSIZE); + if (res == -1) { - /* Read from the file what bits we can */ - rbuff = GNUNET_malloc (BUFFSIZE); - pos = 0; - while (pos < size * 8) - { - int res; - - res = READ (bf->fd, rbuff, BUFFSIZE); - if (res == 0) - break; /* is ok! we just did not use that many bits yet */ - for (i = 0; i < res; i++) - { - if ((rbuff[i] & 0x0F) != 0) - setBit (bf->bitArray, pos + i * 2); - if ((rbuff[i] & 0xF0) != 0) - setBit (bf->bitArray, pos + i * 2 + 1); - } - if (res < BUFFSIZE) - break; - pos += BUFFSIZE * 2; /* 2 bits per byte in the buffer */ - } + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", bf->filename); GNUNET_free (rbuff); + GNUNET_free (bf->filename); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + if (res == 0) + break; /* is ok! we just did not use that many bits yet */ + for (i = 0; i < res; i++) + { + if ((rbuff[i] & 0x0F) != 0) + setBit (bf->bitArray, pos + i * 2); + if ((rbuff[i] & 0xF0) != 0) + setBit (bf->bitArray, pos + i * 2 + 1); } + if (res < BUFFSIZE) + break; + pos += BUFFSIZE * 2; /* 2 bits per byte in the buffer */ + } + GNUNET_free (rbuff); return bf; } @@ -474,32 +603,26 @@ GNUNET_CONTAINER_bloomfilter_load (const char *filename, unsigned int size, * @return the bloomfilter */ struct GNUNET_CONTAINER_BloomFilter * -GNUNET_CONTAINER_bloomfilter_init (const char *data, unsigned int size, +GNUNET_CONTAINER_bloomfilter_init (const char *data, size_t size, unsigned int k) { struct GNUNET_CONTAINER_BloomFilter *bf; - unsigned int ui; - if ((k == 0) || (size == 0)) + if ((0 == k) || (0 == size)) return NULL; - ui = 1; - while (ui < size) - ui *= 2; - if (size != ui) - { - GNUNET_break (0); - return NULL; - } bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); - bf->fd = -1; bf->filename = NULL; + bf->fh = NULL; bf->bitArray = GNUNET_malloc_large (size); + if (NULL == bf->bitArray) + { + GNUNET_free (bf); + return NULL; + } bf->bitArraySize = size; bf->addressesPerElement = k; - if (data != NULL) + if (NULL != data) memcpy (bf->bitArray, data, size); - else - memset (bf->bitArray, 0, bf->bitArraySize); return bf; } @@ -508,23 +631,25 @@ GNUNET_CONTAINER_bloomfilter_init (const char *data, unsigned int size, * Copy the raw data of this bloomfilter into * the given data array. * + * @param bf bloomfilter to take the raw data from * @param data where to write the data * @param size the size of the given data array * @return GNUNET_SYSERR if the data array is not big enough */ int -GNUNET_CONTAINER_bloomfilter_get_raw_data (struct GNUNET_CONTAINER_BloomFilter - *bf, char *data, unsigned int size) +GNUNET_CONTAINER_bloomfilter_get_raw_data (const struct + GNUNET_CONTAINER_BloomFilter *bf, + char *data, size_t size) { if (NULL == bf) return GNUNET_SYSERR; - if (bf->bitArraySize != size) return GNUNET_SYSERR; memcpy (data, bf->bitArray, size); return GNUNET_OK; } + /** * Free the space associated with a filter * in memory, flush to drive if needed (do not @@ -537,13 +662,14 @@ GNUNET_CONTAINER_bloomfilter_free (struct GNUNET_CONTAINER_BloomFilter *bf) { if (NULL == bf) return; - if (bf->fd != -1) - GNUNET_DISK_file_close (bf->filename, bf->fd); + if (bf->fh != NULL) + GNUNET_DISK_file_close (bf->fh); GNUNET_free_non_null (bf->filename); GNUNET_free (bf->bitArray); GNUNET_free (bf); } + /** * Reset a bloom filter to empty. Clears the file on disk. * @@ -556,8 +682,8 @@ GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf) return; memset (bf->bitArray, 0, bf->bitArraySize); - if (bf->fd != -1) - makeEmptyFile (bf->fd, bf->bitArraySize * 4); + if (bf->filename != NULL) + make_empty_file (bf->fh, bf->bitArraySize * 4LL); } @@ -569,8 +695,8 @@ GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf) * @return GNUNET_YES if the element is in the filter, GNUNET_NO if not */ int -GNUNET_CONTAINER_bloomfilter_test (struct GNUNET_CONTAINER_BloomFilter *bf, - const GNUNET_HashCode * e) +GNUNET_CONTAINER_bloomfilter_test (const struct GNUNET_CONTAINER_BloomFilter + *bf, const GNUNET_HashCode * e) { int res; @@ -581,6 +707,7 @@ GNUNET_CONTAINER_bloomfilter_test (struct GNUNET_CONTAINER_BloomFilter *bf, return res; } + /** * Add an element to the filter * @@ -591,10 +718,9 @@ void GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * e) { - if (NULL == bf) return; - iterateBits (bf, &incrementBitCallback, NULL, e); + iterateBits (bf, &incrementBitCallback, bf, e); } @@ -603,25 +729,70 @@ GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf, * data of the given bloom filter. Assumes that * the size of the data array and the current filter * match. + * * @param bf the filter + * @param data the data to or-in + * @param size number of bytes in data */ int GNUNET_CONTAINER_bloomfilter_or (struct GNUNET_CONTAINER_BloomFilter *bf, - const char *data, unsigned int size) + const char *data, size_t size) { unsigned int i; + unsigned int n; + unsigned long long *fc; + const unsigned long long *dc; if (NULL == bf) return GNUNET_YES; if (bf->bitArraySize != size) return GNUNET_SYSERR; - /* FIXME: we could do this 4-8x faster by - going over int/long arrays */ - for (i = 0; i < size; i++) + fc = (unsigned long long *) bf->bitArray; + dc = (const unsigned long long *) data; + n = size / sizeof (unsigned long long); + + for (i = 0; i < n; i++) + fc[i] |= dc[i]; + for (i = n * sizeof (unsigned long long); i < size; i++) bf->bitArray[i] |= data[i]; return GNUNET_OK; } +/** + * Or the entries of the given raw data array with the + * data of the given bloom filter. Assumes that + * the size of the data array and the current filter + * match. + * + * @param bf the filter + * @param to_or the bloomfilter to or-in + * @param size number of bytes in data + */ +int +GNUNET_CONTAINER_bloomfilter_or2 (struct GNUNET_CONTAINER_BloomFilter *bf, + const struct GNUNET_CONTAINER_BloomFilter + *to_or, size_t size) +{ + unsigned int i; + unsigned int n; + unsigned long long *fc; + const unsigned long long *dc; + + if (NULL == bf) + return GNUNET_YES; + if (bf->bitArraySize != size) + return GNUNET_SYSERR; + fc = (unsigned long long *) bf->bitArray; + dc = (const unsigned long long *) to_or->bitArray; + n = size / sizeof (unsigned long long); + + for (i = 0; i < n; i++) + fc[i] |= dc[i]; + for (i = n * sizeof (unsigned long long); i < size; i++) + bf->bitArray[i] |= to_or->bitArray[i]; + return GNUNET_OK; +} + /** * Remove an element from the filter. * @@ -634,9 +805,9 @@ GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf, { if (NULL == bf) return; - if (bf->fd == -1) + if (bf->filename == NULL) return; - iterateBits (bf, &decrementBitCallback, NULL, e); + iterateBits (bf, &decrementBitCallback, bf, e); } /** @@ -646,14 +817,14 @@ GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf, * * @param bf the filter * @param iterator an iterator over all elements stored in the BF - * @param iterator_arg argument to the iterator function + * @param iterator_cls argument to the iterator function * @param size the new size for the filter * @param k the new number of GNUNET_CRYPTO_hash-function to apply per element */ void GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, GNUNET_HashCodeIterator iterator, - void *iterator_arg, unsigned int size, + void *iterator_cls, size_t size, unsigned int k) { GNUNET_HashCode hc; @@ -667,10 +838,9 @@ GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, bf->bitArraySize = size; bf->bitArray = GNUNET_malloc (size); - memset (bf->bitArray, 0, bf->bitArraySize); - if (bf->fd != -1) - makeEmptyFile (bf->fd, bf->bitArraySize * 4); - while (GNUNET_YES == iterator (&hc, iterator_arg)) + if (bf->filename != NULL) + make_empty_file (bf->fh, bf->bitArraySize * 4LL); + while (GNUNET_YES == iterator (iterator_cls, &hc)) GNUNET_CONTAINER_bloomfilter_add (bf, &hc); }