Replies: 2 comments
-
FASTER is extremely efficient and high-performance but as you see there is a learning curve. It is definitely possible to create a simpler wrapper compatible with ConcurrentDictionary API on top, and this would be quite valuable to new users, but we have not done it ourselves. Feel free to contribute such a wrapper back to the repository. |
Beta Was this translation helpful? Give feedback.
-
Also you should look at this sample in playground. It takes care of all the complexities of using sessions via a session pool. There is a pretty easy-to-use https://github.com/microsoft/FASTER/tree/main/cs/playground/AsyncStress |
Beta Was this translation helpful? Give feedback.
-
Hi, just found FASTER. Looks interesting, but it's awfully complex.
I'm just trying to create a replacement for ConcurrentDictionary, but I can't seem to find out how. More specifically, there's a couple things I want:
Honestly, the documentation for IFunctions has me confused. I don't know if I need to use those somehow or if they are unrelated to what I'm trying to do.
What I've tried so far:
The following code is where I'm at. It's based on various examples I've found on github. It'd be nice to know what's wrong or, perhaps easier, if someone has a drop-in replacement for ConcurrentDictionary based on FASTER.
Edit 1:
I was looking at the docs and my code some more and I'm not really sure whether sessions are thread-safe?. That I think may throw a wrench into what I'm trying to do and might be the reason I'm getting the same key already added exceptions? I tried moving the code that creates the session into the ForAll block and it doesn't work on resuming because it can't find the named session.
Edit 2:
So I decided to use ThreadLocal to get a session per thread. I don't know yet whether that's necessary vs just using one session for all threads. Still don't know how to utilize ResumeSession unless I were to name the session after the thread ID. Don't think that really works anyway, because who knows whether the thread IDs are going to be the same the next time I run the application. Plus, I don't really understand how/whether one session has access to data stored in another session which seems like I'd need in order to do what I want.
Edit 3:
I've decided to try storing session IDs as suggested here: #73.
Changed my code that adds items to do this:
Functions that I was hoping would implement GetOrAdd:
And then the ThreadSafeSession class is:
However, I end up with a bunch of these kind of exceptions:
Edit 4:
Well... after changing my CacheKey class to use an integer rather than a string AND making my test harness run on only a single thread, I was able to apparently get what I wanted. The log files aren't growing.
I don't know what is wrong with using a string in CacheKey. I changed the serializer to simply write/read the string value rather than the length and the bytes. Didn't help.
Changed the IFasterEqualityComparer to use a different hash code algorithm and I changed the equals to do a string.equals call. Didn't help.
And, oddly enough, the integer version seemed to save every single record (store.EntryCount matched the number of tests I ran). But, my original string CacheKey and CacheKeySerializer only seemed to save about 75% of the entries. And the changes I mentioned above resulted in only about 50% of the entries being saved. It's almost like there are hash collisions and equals isn't getting called?
And, as mentioned, I had to run this on a single thread. Still not possible to resume multiple named sessions. I found the store has a RecoverableSessions property but it's always empty (before and after the store.Recover() call).
Edit 5:
Getting closer. I don't understand why, but apparently the implementations of GetHashCode64 I've been trying don't work. I don't see why I can't just return the hash code of the CacheKey._key field, but it just plain doesn't work. What does mostly work is what I found here: https://github.com/microsoft/FASTER/blob/50a19c0ef386998b06230bf8e0c4d7880ccdb859/cs/playground/ClassRecoveryDurability/Types.cs
I say mostly works, because I was expecting every single entry to be in the cache when the application finishes (the Console.WriteLine(store.EntryCount) line). As mentioned in my previous edit, it does have the correct count when I use int in CacheKey rather than string. But when I use string, even with this new GetHashCode64 implementation, I'm only getting 99371 in a 100000 test and only 992297 in a 1000000 test. I guess at least I finally have a solution that uses a string in the key object and doesn't result in the log files continually growing on subsequent runs.
It also still doesn't recover in multi-threaded situation. Only way to recover a session is if there's only one session.
Edit 6:
I decided to remove the ResumeSession calls and always use NewSession. I think that might have fixed the multi-threaded issue. To be honest, I don't have the first clue what ResumeSession is used for. Doesn't seem to be useful for me.
That said, I found that all my values were empty. But, I found I needed to add this to my GetOrAddFunctions class to fix that issue:
And, unfortunately, that's not the only problem. Perhaps this next problem is related to the same reason the EntryCount isn't matching the number of tests. I've updated the AddItem method to this:
So, the idea of this code is to only have console output if:
If this was working correctly, I'd expect no output on the initial run (because all keys should result in NotFound) and I'd expect no output on subsequent runs (because the value found for that key matches what we expect).
On the initial run, if I use a small enough amount of tests it runs fine. And on subsequent runs on this amount of tests, it runs fine.
If, however, I use a large enough amount of tests (100000 it seems will do it), the initial run apparently finds matching records (which it shouldn't as all the keys are unique). And those records that it thinks it has matched all have empty values (which is also wrong because I've never upserted an empty value).
Edit 7:
It would appear my PageSizeBits and/or MemorySizeBits is causing these unexpected duplicate empty valued entries to be created. Removing those settings seems to fix the problem. Seems like a bug in FASTER, but not sure.
Beta Was this translation helpful? Give feedback.
All reactions