Spreads / Spreads.LMDB

Low-level zero-overhead and the fastest LMDB .NET wrapper with some additional native methods useful for Spreads
http://docs.dataspreads.io/spreads/libs/lmdb/api/README.html
Mozilla Public License 2.0
80 stars 9 forks source link

CursorGetOption.GetMultiple issue #18

Open jakoss opened 5 years ago

jakoss commented 5 years ago

I'm trying to get multiple structs saved by single key. I came up with this code:

public Span<CodeSegment> MatchTrack(long trackId)
        {
            var value = default(DirectBuffer);
            using (var cursor = databaseHolder.StoreDatabase.OpenReadOnlyCursor(tx))
            {
                if (cursor.TryGet(ref trackId, ref value, CursorGetOption.GetMultiple))
                {
                    return MemoryMarshal.Cast<byte, CodeSegment>(value.Span);
                }
            }
            return null;
        }

But i'm getting exception:

Type DirectBuffer is not fixed size. Either add Size parameter to StructLayout attribute or use Spreads.Serialization attribute to explicitly opt-in to treat non-primitive user-defined structs as fixed-size.

I'm saving those structs like this:

public void AddToStore(long trackId, List<CodeSegment> codeSegments)
        {
            foreach (var item in codeSegments)
            {
                var codeSegment = item;
                storeCursor.TryPut(ref trackId, ref codeSegment, CursorPutOptions.None);
            }
        }

The struct itself is:

[StructLayout(LayoutKind.Sequential, Size = 2 * sizeof(int))]
    public struct CodeSegment
    {
        #region Constructors

        /// <summary>
        /// Creates new CodeSegment with given parameters.
        /// </summary>
        /// <param name="code">Code.</param>
        /// <param name="time">Code timestamp.</param>
        public CodeSegment(int code, int time)
        {
            Code = code;
            Time = time;
        }

        #endregion Constructors

        #region Properties

        public int Code;
        public int Time;

        #endregion Properties
    }

Am i thinking wrong? Is it even possible to read multiple values at once into a span?

jakoss commented 5 years ago

I also tried:

public Span<CodeSegment> MatchTrack(long trackId)
        {
            var keyMemory = BitConverter.GetBytes(trackId).AsMemory();
            using (keyMemory.Pin())
            {
                var key = new DirectBuffer(keyMemory.Span);
                var value = default(DirectBuffer);
                using (var cursor = databaseHolder.StoreDatabase.OpenReadOnlyCursor(tx))
                {
                    if (cursor.TryGet(ref key, ref value, CursorGetOption.GetMultiple))
                    {
                        return MemoryMarshal.Cast<byte, CodeSegment>(value.Span);
                    }
                }
            }

            return null;
        }

but this gives me:

image

buybackoff commented 5 years ago

Sorry, but get multiple was never explicitly covered and we had #5 not so long ago. This is a good up-for-grabs and a pull request candidate.