Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/tighten hash usage 2 (fixing Issues #316, #423, and probably #492) #493

Open
wants to merge 53 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
69cac7b
Creating a new version of feature/tighten_hash_usage based off develo…
JoshuaGreen May 17, 2024
dec54dd
Updating comment.
JoshuaGreen May 17, 2024
cf8b6bc
Correcting this comment.
JoshuaGreen May 17, 2024
7150d8a
No reason not to include these even though they're already needed in …
JoshuaGreen May 17, 2024
29bc885
Adding a useful comment.
JoshuaGreen May 17, 2024
881c20c
Removing some unnecessary changes.
JoshuaGreen May 17, 2024
c85b0de
Oops, we need to initialize the element here.
JoshuaGreen May 18, 2024
bcbbe73
Switching to the idiomatic expression.
JoshuaGreen May 18, 2024
b3159bd
sh->MallocCount should be the number of allocated blocks. We should …
JoshuaGreen May 23, 2024
a32691c
Oops, forgot to update a couple of computations.
JoshuaGreen May 27, 2024
3d2071f
The FXF code must be generic. However, on some systems, with our pre…
JoshuaGreen May 28, 2024
6a27c3e
Making the comment a bit more accurate.
JoshuaGreen May 28, 2024
cc8b444
Hoping to simplify the logic by moving the boilerplate into functions…
JoshuaGreen Jun 1, 2024
fe2c881
Using the write check, not that it should really matter in our uses.
JoshuaGreen Jun 1, 2024
bd7d0b5
Striving to free memory in the reverse order that it was allocated in…
JoshuaGreen Jun 7, 2024
527a697
Removing an unnecessary check.
JoshuaGreen Jun 8, 2024
0c09c82
Restoring the "on equivalent key" behavior. I'm not sure we need it,…
JoshuaGreen Jun 8, 2024
3fd0c08
Breaking apart large blocks by default since it seems to be useful; m…
JoshuaGreen Jun 8, 2024
3f7f1b6
First crack at allowing one to set the desired alignment at compile-t…
JoshuaGreen Aug 12, 2024
85c1b01
Fixing some asserts.
JoshuaGreen Aug 13, 2024
ae429e4
Might as well use macros for everything.
JoshuaGreen Aug 13, 2024
0f04b2e
Fixing these macros (maybe).
JoshuaGreen Aug 13, 2024
4c7d4b5
Getting a better compile-time estimate for the minimum alignment, at …
JoshuaGreen Aug 13, 2024
6978868
Doing our best to properly estimate this value under all circumstances.
JoshuaGreen Aug 13, 2024
eda84bc
Aiming for portability.
JoshuaGreen Aug 14, 2024
5599b89
Trying to guarantee exactly what we need.
JoshuaGreen Aug 16, 2024
d734868
SEGMENTED code needs to compile.
JoshuaGreen Aug 17, 2024
83130b2
Removing some hard-coded values, hopefully correctly.
JoshuaGreen Aug 17, 2024
e5fae8a
Moving some of the debugging infrastructure inside the free store man…
JoshuaGreen Aug 18, 2024
644aeb2
Adding some compile-time checks that should eliminate the run-time ones.
JoshuaGreen Aug 18, 2024
a97bcc3
Tightening some assertions.
JoshuaGreen Aug 18, 2024
36dbd69
Noting in the other place where we may leak memory (if we happen to c…
JoshuaGreen Aug 21, 2024
cbce3da
Only compute that value once.
JoshuaGreen Aug 21, 2024
eaf4979
Macroizing more.
JoshuaGreen Aug 22, 2024
c5b57f0
Fixing a dumb typo.
JoshuaGreen Aug 23, 2024
1dbcabf
Simplifying the expression. If the sum overflow, then so does the in…
JoshuaGreen Aug 23, 2024
a6b0b14
Reusing code.
JoshuaGreen Aug 23, 2024
fa4df87
We have a macro for that.
JoshuaGreen Aug 23, 2024
e822687
That should really be configurable at compile-time.
JoshuaGreen Aug 23, 2024
6c04627
If memory is leaking then treat it as still allocated rather than ava…
JoshuaGreen Aug 24, 2024
efaf8b0
It looks a bit better this way.
JoshuaGreen Aug 24, 2024
81b58bc
Eliminating compiler warnings, because I can.
JoshuaGreen Aug 28, 2024
7d4c233
Shift the operation to the compile-time constant now that the outer c…
JoshuaGreen Aug 28, 2024
3de22b7
Documenting where one of our ideas came from.
JoshuaGreen Aug 31, 2024
84ec9dc
The comments should be based on the FXF infrastructure, not on how Po…
JoshuaGreen Sep 2, 2024
d591331
We might as well make this macro signed regardless of how it's defined.
JoshuaGreen Sep 7, 2024
e00318f
One more sanity check.
JoshuaGreen Sep 8, 2024
f880972
Adding an alignment sanity check in debug mode. Maybe someday we'll …
JoshuaGreen Sep 18, 2024
aac65c4
Ensure we "use" alignment.
JoshuaGreen Sep 18, 2024
b5190e7
Some more sanity checks.
JoshuaGreen Sep 19, 2024
9f6cefe
In the off-chance the offset we compute is a nontrivial multiple of t…
JoshuaGreen Sep 20, 2024
a3d4d67
Isolating the alignment hackery to one location.
JoshuaGreen Sep 21, 2024
06deb88
Making fxfAlloc type-safe.
JoshuaGreen Sep 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 133 additions & 71 deletions DHT/dht.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ void set_dhtDebug(int const d) {dhtDebug = d;}
#endif /*DEBUG_DHT*/

#if !defined(New) /* TODO: Is this the correct check for all of the below lines? */
# define New(type) ((type *)fxfAlloc(sizeof(type)))
# define nNew(n,type) ((type *)nNewImpl(n,sizeof(type)))
# define New(type) fxfAlloc(sizeof(type), type)
# define nNew(n,type) ((type *)nNewImpl(n,sizeof(type),ALIGNMENT_OF_TYPE(type)))
# define Nil(type) ((type *)0)
static inline void * nNewImpl(size_t const nmemb, size_t const size) {
return ((size && (nmemb > (((size_t)-1)/size))) ? Nil(void) : fxfAlloc(nmemb*size));
static inline void * nNewImpl(size_t const nmemb, size_t const size, size_t desired_alignment) {
return ((size && (nmemb > (((size_t)-1)/size))) ? Nil(void) : fxfAllocRaw(nmemb*size, desired_alignment));
}
#endif /*New*/

Expand Down Expand Up @@ -197,7 +197,7 @@ static boolean appendDirTable_recursive(dirTable *dt,
TraceFunctionEntry(__func__);
TraceFunctionParam("%p",(void *)dt);
TraceFunctionParam("%p",elmt_to_append);
TraceFunctionParam("%d",elmt_depth);
TraceFunctionParam("%u",elmt_depth);
TraceFunctionParamListEnd();

if (elmt_depth>dt->level)
Expand Down Expand Up @@ -263,7 +263,7 @@ static boolean appendDirTable_recursive(dirTable *dt,
}

TraceFunctionExit(__func__);
TraceFunctionResult("%d",result);
TraceFunctionResult("%d",(int)result);
TraceFunctionResultEnd();
return result;
}
Expand Down Expand Up @@ -396,14 +396,14 @@ static InternHsElement *stepDirTable(dirEnumerate *enumeration)

typedef struct
{
dhtHashValue (*Hash)(dhtConstValue);
int (*Equal)(dhtConstValue, dhtConstValue);
dhtConstValue (*DupKey)(dhtConstValue);
dhtConstValue (*DupData)(dhtConstValue);
void (*FreeKey)(dhtValue);
dhtHashValue (*Hash)(dhtKey);
int (*Equal)(dhtKey, dhtKey);
int (*DupKeyValue)(dhtValue, dhtValue *);
int (*DupData)(dhtValue, dhtValue *);
void (*FreeKeyValue)(dhtValue);
void (*FreeData)(dhtValue);
void (*DumpData)(dhtConstValue,FILE *);
void (*DumpKey)(dhtConstValue,FILE *);
void (*DumpData)(dhtValue,FILE *);
void (*DumpKeyValue)(dhtValue,FILE *);
} Procedures;

typedef struct dht {
Expand All @@ -423,7 +423,7 @@ typedef struct dht {
#if !defined(HashTable)
#define HashTable struct dht
#endif
#define NewHashTable ((HashTable *)fxfAlloc(sizeof(dht)))
#define NewHashTable fxfAlloc(sizeof(dht), HashTable)
#define FreeHashTable(h) fxfFree(h, sizeof(dht))
#define OVERFLOW_SAVE 1
#if defined(OVERFLOW_SAVE)
Expand All @@ -436,7 +436,7 @@ typedef struct dht {
#define ActualLoadFactor(h) (((h)->KeyCount*100)/(h)->DirTab.count)
#endif /*OVERFLOW_SAVE*/

unsigned long dhtKeyCount(dht *h)
unsigned long dhtKeyCount(dht const *h)
{
return h->KeyCount;
}
Expand Down Expand Up @@ -508,17 +508,17 @@ dht *dhtCreate(dhtValueType KeyType, dhtValuePolicy KeyPolicy,
ht->procs.Hash= dhtProcedures[KeyType]->Hash;
ht->procs.Equal= dhtProcedures[KeyType]->Equal;
ht->procs.DumpData= dhtProcedures[DtaType]->Dump;
ht->procs.DumpKey= dhtProcedures[KeyType]->Dump;
ht->procs.DumpKeyValue= dhtProcedures[KeyType]->Dump;

if (KeyPolicy==dhtNoCopy)
{
ht->procs.DupKey= dhtProcedures[dhtSimpleValue]->Dup;
ht->procs.FreeKey= dhtProcedures[dhtSimpleValue]->Free;
ht->procs.DupKeyValue= dhtProcedures[dhtSimpleValue]->Dup;
ht->procs.FreeKeyValue= dhtProcedures[dhtSimpleValue]->Free;
}
else if (KeyPolicy==dhtCopy)
{
ht->procs.DupKey= dhtProcedures[KeyType]->Dup;
ht->procs.FreeKey= dhtProcedures[KeyType]->Free;
ht->procs.DupKeyValue= dhtProcedures[KeyType]->Dup;
ht->procs.FreeKeyValue= dhtProcedures[KeyType]->Free;
}

if (DataPolicy==dhtNoCopy)
Expand Down Expand Up @@ -559,8 +559,8 @@ void dhtDestroy(HashTable *ht)
while (b)
{
InternHsElement *tmp= b;
(ht->procs.FreeKey)((dhtValue)b->HsEl.Key);
(ht->procs.FreeData)((dhtValue)b->HsEl.Data);
(ht->procs.FreeData)(b->HsEl.Data);
(ht->procs.FreeKeyValue)(b->HsEl.Key.value);
b= b->Next;
FreeInternHsElement(tmp);
}
Expand Down Expand Up @@ -599,7 +599,7 @@ void dhtDumpIndented(int ind, HashTable *ht, FILE *f)
while (b)
{
fprintf(f, "%*s ", ind, "");
(ht->procs.DumpKey)(b->HsEl.Key, f);
(ht->procs.DumpKeyValue)(b->HsEl.Key.value, f);
fputs("->", f);
(ht->procs.DumpData)(b->HsEl.Data, f);
b= b->Next;
Expand Down Expand Up @@ -796,14 +796,25 @@ LOCAL void ShrinkHashTable(HashTable *ht)
shrinkDirTable(&ht->DirTab);
}

LOCAL InternHsElement **LookupInternHsElement(HashTable *ht, dhtConstValue key)
LOCAL InternHsElement **LookupInternHsElement(HashTable *ht, dhtKey key)
{
uLong h;
InternHsElement **phe;

TraceFunctionEntry(__func__);
TraceFunctionParam("%p",(void *)ht);
TraceFunctionParam("%p",(void const *)key);
if (ht->KeyPolicy==dhtNoCopy)
{
#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
TraceFunctionParam("%jx",key.value.unsigned_integer);
#else
TraceFunctionParam("%lx",(unsigned long)key.value.unsigned_integer);
#endif
}
else
{
TraceFunctionParam("%p",(void const *)key.value.object_pointer); // TODO: something more generic here?
}
TraceFunctionParamListEnd();

h = DynamicHash(ht->p, ht->maxp, (ht->procs.Hash)(key));
Expand All @@ -827,14 +838,25 @@ LOCAL InternHsElement **LookupInternHsElement(HashTable *ht, dhtConstValue key)
return phe;
}

void dhtRemoveElement(HashTable *ht, dhtConstValue key)
void dhtRemoveElement(HashTable *ht, dhtKey key)
{
MYNAME(dhtRemoveElement)
InternHsElement **phe, *he;

TraceFunctionEntry(__func__);
TraceFunctionParam("%p",(void *)ht);
TraceFunctionParam("%p",(void const *)key);
if (ht->KeyPolicy==dhtNoCopy)
{
#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
TraceFunctionParam("%jx",key.value.unsigned_integer);
#else
TraceFunctionParam("%lx",(unsigned long)key.value.unsigned_integer);
#endif
}
else
{
TraceFunctionParam("%p",(void const *)key.value.object_pointer); // TODO: something more generic here?
}
TraceFunctionParamListEnd();

phe= LookupInternHsElement(ht, key);
Expand All @@ -849,8 +871,8 @@ void dhtRemoveElement(HashTable *ht, dhtConstValue key)
ht->NextStep= ht->NextStep->Next;

*phe= he->Next;
(ht->procs.FreeData)((dhtValue)he->HsEl.Data);
(ht->procs.FreeKey)((dhtValue)he->HsEl.Key);
(ht->procs.FreeData)(he->HsEl.Data);
(ht->procs.FreeKeyValue)(he->HsEl.Key.value);
FreeInternHsElement(he);
ht->KeyCount--;
if (ActualLoadFactor(ht) < ht->MinLoadFactor)
Expand All @@ -877,40 +899,52 @@ void dhtRemoveElement(HashTable *ht, dhtConstValue key)
TraceFunctionResultEnd();
}

dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data)
/* dhtEnterElement adds the key, data pair. If an equivalent key already exists
then the data will be updated and the existing key will be replaced by the
provided key. (The latter can matter if keys contain data that doesn't affect
the equivalence check.)
This function allocates copies before freeing any old data, allowing us to bail
on failure while leaving the old data intact. This isn't ideal from a memory-
usage perspective, so if this "strong exception guarantee" is unnecessary then
the code can likely be simplified and improved. */
dhtElement *dhtEnterElement(HashTable *ht, dhtKey key, dhtValue data)
{
InternHsElement **phe, *he;
dhtConstValue KeyV;
dhtConstValue DataV;
dhtKey KeyV;
dhtValue DataV;
dhtValue *KeyVPtr;
dhtValue *DataVPtr;

TraceFunctionEntry(__func__);
TraceFunctionParam("%p",(void *)ht);
TraceFunctionParam("%p",(void const *)key);
TraceFunctionParam("%p",(void const *)data);
TraceFunctionParamListEnd();

assert(key!=0);
KeyV = (ht->procs.DupKey)(key);
if (KeyV==0)
if (ht->KeyPolicy==dhtNoCopy)
{
TraceText("key duplication failed\n");
TraceFunctionExit(__func__);
TraceFunctionResult("%p",(void *)dhtNilElement);
TraceFunctionResultEnd();
return dhtNilElement;
#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
TraceFunctionParam("%jx",key.value.unsigned_integer);
#else
TraceFunctionParam("%lx",(unsigned long)key.value.unsigned_integer);
#endif
}

DataV = data==0 ? 0 : (ht->procs.DupData)(data);
if (data!=0 && DataV==0)
else
{
(ht->procs.FreeKey)((dhtValue)KeyV);
TraceText("data duplication failed\n");
TraceFunctionExit(__func__);
TraceFunctionResult("%p",(void *)dhtNilElement);
TraceFunctionResultEnd();
return dhtNilElement;
TraceFunctionParam("%p",(void const *)key.value.object_pointer); // TODO: something more generic here?
}
if (ht->DtaPolicy==dhtNoCopy)
{
#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
TraceFunctionParam("%jx",data.unsigned_integer);
#else
TraceFunctionParam("%lx",(unsigned long)data.unsigned_integer);
#endif
}
else
{
TraceFunctionParam("%p",(void const *)data.object_pointer); // TODO: something more generic here?
}

assert(key.value.object_pointer!=0); /* TODO: This assert assumes that object_pointer is the active member.
Is there a more generic test we could do? Do we need one? */

phe = LookupInternHsElement(ht,key);
TraceValue("%p",(void *)phe);
he = *phe;
Expand All @@ -923,50 +957,78 @@ dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data
TraceEOL();
if (he==0)
{
(ht->procs.FreeKey)((dhtValue)KeyV);
(ht->procs.FreeData)((dhtValue)DataV);
TraceText("allocation of new intern Hs element failed\n");
TraceFunctionExit(__func__);
TraceFunctionResult("%p",(void *)dhtNilElement);
TraceFunctionResultEnd();
return dhtNilElement;
}
else
{
*phe = he;
he->Next = NilInternHsElement;
ht->KeyCount++;
}
KeyVPtr = &he->HsEl.Key.value;
DataVPtr = &he->HsEl.Data;
}
else
{
KeyVPtr = &KeyV.value;
DataVPtr = &DataV;
}
if ((ht->procs.DupKeyValue)(key.value, KeyVPtr))
{
if (!*phe)
FreeInternHsElement(he);
TraceText("key duplication failed\n");
TraceFunctionExit(__func__);
TraceFunctionResult("%p",(void *)dhtNilElement);
TraceFunctionResultEnd();
return dhtNilElement;
}
if ((ht->procs.DupData)(data, DataVPtr))
{
(ht->procs.FreeKeyValue)(*KeyVPtr);
if (!*phe)
FreeInternHsElement(he);
TraceText("data duplication failed\n");
TraceFunctionExit(__func__);
TraceFunctionResult("%p",(void *)dhtNilElement);
TraceFunctionResultEnd();
return dhtNilElement;
}
if (*phe)
{
if (ht->DtaPolicy == dhtCopy)
(ht->procs.FreeData)((dhtValue)he->HsEl.Data);
(ht->procs.FreeData)(he->HsEl.Data);
if (ht->KeyPolicy == dhtCopy)
(ht->procs.FreeKey)((dhtValue)he->HsEl.Key);
(ht->procs.FreeKeyValue)(he->HsEl.Key.value);
he->HsEl.Key = KeyV;
he->HsEl.Data = DataV;
}
else
{
*phe = he;
he->Next = NilInternHsElement;
ht->KeyCount++;
}

he->HsEl.Key = KeyV;
he->HsEl.Data = DataV;

if (ActualLoadFactor(ht)>ht->MaxLoadFactor)
{
/*
#if 0
fputs("Dumping Hash-Table before expansion\n",stderr);
fDumpHashTable(ht, stderr);
*/
#endif
if (ExpandHashTable(ht)!=dhtOkStatus)
{
/* TODO: It seems strange to return dhtNilElement AFTER we've added a new entry
or overwritten an old one. Should we return something else here? Should
we check and deal with this issue BEFORE creating or overwriting an entry? */
TraceText("expansion failed\n");
TraceFunctionExit(__func__);
TraceFunctionResult("%p",(void *)dhtNilElement);
TraceFunctionResultEnd();
return dhtNilElement;
}
/*
#if 0
fputs("Dumping Hash-Table after expansion\n",stderr);
fDumpHashTable(ht, stderr);
*/
#endif
}

TraceFunctionExit(__func__);
Expand All @@ -975,7 +1037,7 @@ dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data
return &he->HsEl;
}

dhtElement *dhtLookupElement(HashTable *ht, dhtConstValue key)
dhtElement *dhtLookupElement(HashTable *ht, dhtKey key)
{
InternHsElement **phe;
dhtElement *result;
Expand Down
Loading