#include "squid.h"
#include "fs/rock/RockDirMap.h"
-Rock::DirMap::DirMap(int roughLimit): hintPast(-1), hintNext(0),
- bitLimit(roundLimit(roughLimit)), bitCount(0), words(NULL), wordCount(0)
+Rock::DirMap::DirMap(const int aLimit): hintPast(-1), hintNext(0),
+ limit(aLimit), count(0), slots(NULL)
{
- syncWordCount();
allocate();
}
Rock::DirMap::DirMap(const DirMap &m):
hintPast(m.hintPast), hintNext(m.hintNext),
- bitLimit(m.bitLimit), bitCount(m.bitCount),
- words(NULL), wordCount(m.wordCount)
+ limit(m.limit), count(m.count),
+ slots(NULL)
{
- syncWordCount();
copyFrom(m);
}
hintPast = m.hintPast;
hintNext = m.hintNext;
- bitLimit = m.bitLimit;
- bitCount = m.bitCount;
+ limit = m.limit;
+ count = m.count;
- wordCount = m.wordCount;
copyFrom(m);
return *this;
}
void
-Rock::DirMap::resize(const int roughLimit)
+Rock::DirMap::resize(const int newLimit)
{
- const int newLimit = roundLimit(roughLimit);
// TODO: optimize?
- if (newLimit != bitLimit) {
+ if (newLimit != limit) {
DirMap old(*this);
deallocate();
- bitLimit = newLimit;
- syncWordCount();
+ limit = newLimit;
copyFrom(old);
}
}
int
Rock::DirMap::entryLimit() const
{
- return bitLimit;
+ return limit;
}
int
Rock::DirMap::entryCount() const
{
- return bitCount;
+ return count;
}
bool
Rock::DirMap::full() const
{
- return bitCount >= bitLimit;
+ return count >= limit;
}
bool
Rock::DirMap::valid(const int pos) const
{
- return 0 <= pos && pos < bitLimit;
+ return 0 <= pos && pos < limit;
}
int
return next;
}
-/// low-level allocation, assumes wordCount is set
+/// allocation, assumes limit is set
void
Rock::DirMap::allocate()
{
- assert(!words);
- words = new unsigned long[wordCount];
- memset(words, 0, ramSize());
+ assert(!slots);
+ slots = new uint8_t[limit];
+ memset(slots, 0, ramSize());
}
-/// low-level deallocation; may place the object in an inconsistent state
+/// deallocation; may place the object in an inconsistent state
void
Rock::DirMap::deallocate()
{
- delete[] words;
- words = NULL;
+ delete [] slots;
+ slots = NULL;
}
/// low-level copy; assumes all counts have been setup
Rock::DirMap::copyFrom(const DirMap &m)
{
allocate();
- if (m.wordCount)
- memcpy(words, m.words, min(ramSize(), m.ramSize()));
+ if (m.limit)
+ memcpy(slots, m.slots, min(ramSize(), m.ramSize()));
}
/// low-level ram size calculation for mem*() calls
int
Rock::DirMap::ramSize() const
{
- return sizeof(*words) * wordCount;
-}
-
-/* XXX: Number of bits in a long and other constants from filemap.cc */
-#if SIZEOF_LONG == 8
-#define LONG_BIT_SHIFT 6
-#define BITS_IN_A_LONG 0x40
-#define LONG_BIT_MASK 0x3F
-#define ALL_ONES (unsigned long) 0xFFFFFFFFFFFFFFFF
-#elif SIZEOF_LONG == 4
-#define LONG_BIT_SHIFT 5
-#define BITS_IN_A_LONG 0x20
-#define LONG_BIT_MASK 0x1F
-#define ALL_ONES (unsigned long) 0xFFFFFFFF
-#else
-#define LONG_BIT_SHIFT 5
-#define BITS_IN_A_LONG 0x20
-#define LONG_BIT_MASK 0x1F
-#define ALL_ONES (unsigned long) 0xFFFFFFFF
-#endif
-
-#define FM_INITIAL_NUMBER (1<<14)
+ return sizeof(*slots) * limit;
+}
int
Rock::DirMap::AbsoluteEntryLimit()
{
const int sfilenoMax = 0xFFFFFF; // Core sfileno maximum
- return ((sfilenoMax+1) >> LONG_BIT_SHIFT) << LONG_BIT_SHIFT;
-}
-
-/// Adjust limit so that there are no "extra" bits in the last word
-// that are above the limit but still found by findNext.
-int
-Rock::DirMap::roundLimit(const int roughLimit) const
-{
- const int allowedLimit = min(roughLimit, AbsoluteEntryLimit());
- const int newLimit = (allowedLimit >> LONG_BIT_SHIFT) << LONG_BIT_SHIFT;
- debugs(8, 3, HERE << "adjusted map limit from " << roughLimit << " to " <<
- newLimit);
- return newLimit;
-}
-
-/// calculate wordCount for the number of entries (bitLimit)
-void
-Rock::DirMap::syncWordCount()
-{
- wordCount = bitLimit >> LONG_BIT_SHIFT;
- debugs(8, 3, HERE << wordCount << ' ' << BITS_IN_A_LONG <<
- "-bit long words for " << bitLimit << " bits");
+ return sfilenoMax;
}
void
{
if (!has(pos)) {
assert(valid(pos));
-
- const unsigned long bitmask = (1L << (pos & LONG_BIT_MASK));
- words[pos >> LONG_BIT_SHIFT] |= bitmask;
-
- ++bitCount;
+ slots[pos] = 1;
+ ++count;
debugs(8, 6, HERE << pos);
} else {
debugs(8, 3, HERE << pos << " in vain");
Rock::DirMap::clear(const int pos)
{
if (has(pos)) {
- const unsigned long bitmask = (1L << (pos & LONG_BIT_MASK));
- words[pos >> LONG_BIT_SHIFT] &= ~bitmask;
- --bitCount;
+ slots[pos] = 0;
+ --count;
debugs(8, 6, HERE << pos);
} else {
debugs(8, 3, HERE << pos << " in vain");
if (!valid(pos)) // the only place where we are forgiving
return false;
- const unsigned long bitmask = (1L << (pos & LONG_BIT_MASK));
- return words[pos >> LONG_BIT_SHIFT] & bitmask;
+ return slots[pos];
}
/// low-level empty-slot search routine, uses and updates hints
// adjust and try the scan-based hint
if (!valid(hintNext))
hintNext = 0;
- if (valid(hintNext) && !has(hintNext))
- return hintNext++;
-
- // start scan with the scan-based hint
- int wordPos = hintNext >> LONG_BIT_SHIFT;
-
- for (int i = 0; i < wordCount; ++i) {
- if (words[wordPos] != ALL_ONES)
- break;
- wordPos = (wordPos + 1) % wordCount;
- }
-
- for (int bitPos = 0; bitPos < BITS_IN_A_LONG; ++bitPos) {
- hintNext = ((unsigned long) wordPos << LONG_BIT_SHIFT) | bitPos;
-
- if (hintNext < bitLimit && !has(hintNext))
+ for (int i = 0; i < limit; ++i) {
+ if (!has(hintNext))
return hintNext++;
+
+ hintNext = (hintNext + 1) % limit;
}
// the map is full
namespace Rock {
/// \ingroup Rock
-/// bitmap of used db slots indexed by sfileno
+/// map of used db slots indexed by sfileno
class DirMap
{
public:
- // the map may adjust the limit down a little; see roundLimit()
- DirMap(const int roughLimit = 0);
+ DirMap(const int aLimit = 0);
DirMap(const DirMap &map);
~DirMap();
DirMap &operator =(const DirMap &map);
- void resize(const int newLimit); ///< forgets higher bits or appends zeros
+ void resize(const int newLimit); ///< forgets higher slots or appends zeros
bool full() const; ///< there are no empty slots left
bool has(int n) const; ///< whether slot n is occupied
bool valid(int n) const; ///< whether n is a valid slot coordinate
- int entryCount() const; ///< number of bits turned on
- int entryLimit() const; ///< maximum number of bits that can be turned on
+ int entryCount() const; ///< number of used slots
+ int entryLimit() const; ///< maximum number of slots that can be used
void use(int n); ///< mark slot n as used
void clear(int n); ///< mark slot n as unused
///< unreliable next empty slot suggestion #2 (scan based)
mutable int hintNext;
- int bitLimit; ///< maximum number of map entries
- int bitCount; ///< current number of map entries
+ int limit; ///< maximum number of map slots
+ int count; ///< current number of map slots
- unsigned long *words; ///< low level storage
- int wordCount; ///< number of words allocated
+ typedef uint8_t Slot;
+ Slot *slots; ///< slots storage
- int roundLimit(const int roughLimit) const;
- void syncWordCount();
int ramSize() const;
void allocate();
void deallocate();
// We do not reuse struct _fileMap because we cannot control its size,
// resulting in sfilenos that are pointing beyond the database.
-// TODO: Consider using std::bitset. Is it really slower for findNext()?
-
-
#endif /* SQUID_FS_ROCK_DIR_MAP_H */