private unsafe string MarshalAndFreeRocksDbString(IntPtr resultPtr, long resultLength, Encoding encoding) { var result = CurrentFramework.CreateString((sbyte *)resultPtr.ToPointer(), 0, (int)resultLength, encoding); rocksdb_free(resultPtr); return(result); }
private unsafe int Comparator_Compare(IntPtr state, IntPtr a, UIntPtr alen, IntPtr b, UIntPtr blen) { var getComparatorPtr = (*((ComparatorState *)state)).GetComparatorPtr; var getComparator = CurrentFramework.GetDelegateForFunctionPointer <GetComparator>(getComparatorPtr); var comparator = getComparator(); return(comparator.Compare(a, alen, b, blen)); }
public static T LoadFunc <T>(INativeLibImporter importer, IntPtr libraryHandle, string entryPoint) { IntPtr procAddress = importer.GetProcAddress(libraryHandle, entryPoint); if (procAddress == IntPtr.Zero) { throw new NativeLoadException(string.Format("Unable to get address of {0} ({1})", entryPoint, typeof(T)), null); } return(CurrentFramework.GetDelegateForFunctionPointer <T>(procAddress)); }
public unsafe ComparatorBase(string name = null, IntPtr state = default(IntPtr)) { Name = name ?? GetType().FullName; _destroy = s => this.Destroy(s); Handle = Native.Instance.rocksdb_comparator_create( state: IntPtr.Zero, destructor: CurrentFramework.GetFunctionPointerForDelegate(_destroy), compare: CurrentFramework.GetFunctionPointerForDelegate <CompareFunc>(Compare), getName: CurrentFramework.GetFunctionPointerForDelegate <GetNameFunc>(GetName) ); }
/// <summary> /// Returns true if a particular target runtime is available. /// </summary> /// <param name="framework">The framework being sought</param> /// <returns>True if it's available, false if not</returns> public static bool IsAvailable(RuntimeFramework framework) { switch (framework.Runtime) { case RuntimeType.Mono: return(IsMonoInstalled()); case RuntimeType.Net: return(CurrentFramework.Matches(framework) || IsDotNetInstalled(framework.Version)); default: return(false); } }
/// <summary> /// REQUIRES: The client must provide a merge operator if Merge operation /// needs to be accessed. Calling Merge on a DB without a merge operator /// would result in Status::NotSupported. The client must ensure that the /// merge operator supplied here has the same name and *exactly* the same /// semantics as the merge operator provided to previous open calls on /// the same DB. The only exception is reserved for upgrade, where a DB /// previously without a merge operator is introduced to Merge operation /// for the first time. It's necessary to specify a merge operator when /// openning the DB in this case. /// Default: nullptr /// </summary> public ColumnFamilyOptions SetMergeOperator(MergeOperator mergeOperator) { // Allocate some memory for the name bytes var name = mergeOperator.Name ?? mergeOperator.GetType().FullName; var nameBytes = Encoding.UTF8.GetBytes(name + "\0"); var namePtr = Marshal.AllocHGlobal(nameBytes.Length); Marshal.Copy(nameBytes, 0, namePtr, nameBytes.Length); // Hold onto a reference to everything that needs to stay alive MergeOperatorRef = new MergeOperatorReferences { GetMergeOperator = () => mergeOperator, DestructorDelegate = MergeOperator_Destroy, NameDelegate = MergeOperator_GetNamePtr, DeleteValueDelegate = MergeOperator_DeleteValue, FullMergeDelegate = MergeOperator_FullMerge, PartialMergeDelegate = MergeOperator_PartialMerge, }; // Allocate the state var state = new MergeOperatorState { NamePtr = namePtr, GetMergeOperatorPtr = CurrentFramework.GetFunctionPointerForDelegate <GetMergeOperator>(MergeOperatorRef.GetMergeOperator) }; var statePtr = Marshal.AllocHGlobal(Marshal.SizeOf(state)); Marshal.StructureToPtr(state, statePtr, false); // Create the merge operator IntPtr handle = Native.Instance.rocksdb_mergeoperator_create( state: statePtr, destructor: MergeOperatorRef.DestructorDelegate, delete_value: MergeOperatorRef.DeleteValueDelegate, full_merge: MergeOperatorRef.FullMergeDelegate, partial_merge: MergeOperatorRef.PartialMergeDelegate, name: MergeOperatorRef.NameDelegate ); return(SetMergeOperator(handle)); }
/// <summary> /// Comparator used to define the order of keys in the table. /// Default: a comparator that uses lexicographic byte-wise ordering /// /// REQUIRES: The client must ensure that the comparator supplied /// here has the same name and orders keys *exactly* the same as the /// comparator provided to previous open calls on the same DB. /// </summary> public ColumnFamilyOptions SetComparator(Comparator comparator) { // Allocate some memory for the name bytes var name = comparator.Name ?? comparator.GetType().FullName; var nameBytes = Encoding.UTF8.GetBytes(name + "\0"); var namePtr = Marshal.AllocHGlobal(nameBytes.Length); Marshal.Copy(nameBytes, 0, namePtr, nameBytes.Length); // Hold onto a reference to everything that needs to stay alive ComparatorRef = new ComparatorReferences { GetComparator = () => comparator, CompareDelegate = Comparator_Compare, DestructorDelegate = Comparator_Destroy, NameDelegate = Comparator_GetNamePtr, }; // Allocate the state var state = new ComparatorState { NamePtr = namePtr, GetComparatorPtr = CurrentFramework.GetFunctionPointerForDelegate <GetComparator>(ComparatorRef.GetComparator) }; var statePtr = Marshal.AllocHGlobal(Marshal.SizeOf(state)); Marshal.StructureToPtr(state, statePtr, false); // Create the comparator IntPtr handle = Native.Instance.rocksdb_comparator_create( state: statePtr, destructor: ComparatorRef.DestructorDelegate, compare: ComparatorRef.CompareDelegate, name: ComparatorRef.NameDelegate ); return(SetComparator(handle)); }
/// <summary> /// Executes a multi_get with automatic marshalling /// </summary> /// <param name="db"></param> /// <param name="read_options"></param> /// <param name="keys"></param> /// <param name="numKeys">when non-zero, specifies the number of keys in the array to fetch</param> /// <param name="keyLengths">when non-null specifies the lengths of each key to fetch</param> /// <param name="errptrs">when non-null, must be an array that will be populated with error codes</param> /// <param name="values">when non-null is a pre-allocated array to put the resulting values in</param> /// <param name="cf"></param> /// <returns></returns> public unsafe KeyValuePair <string, string>[] rocksdb_multi_get( IntPtr db, IntPtr read_options, string[] keys, IntPtr[] errptrs, ulong numKeys = 0, KeyValuePair <string, string>[] values = null, ColumnFamilyHandle[] cf = null, Encoding encoding = null) { if (encoding == null) { encoding = Encoding.UTF8; } int count = numKeys == 0 ? keys.Length : (int)numKeys; IntPtr[] keyPtrs = new IntPtr[count]; var keyLengths = new ulong[count]; IntPtr[] valuePtrs = new IntPtr[count]; ulong[] valueLengths = new ulong[count]; if (values == null) { values = new KeyValuePair <string, string> [count]; } if (errptrs == null) { errptrs = new IntPtr[count]; } // first we have to encode each key for (int i = 0; i < count; i++) { var key = keys[i]; fixed(char *k = key) { var klength = key.Length; int bklength = encoding.GetByteCount(k, klength); var bk = Marshal.AllocHGlobal(bklength); encoding.GetBytes(k, klength, (byte *)bk.ToPointer(), bklength); keyPtrs[i] = bk; keyLengths[i] = (ulong)bklength; } } if (cf == null) { rocksdb_multi_get(db, read_options, (ulong)count, keyPtrs, keyLengths, valuePtrs, valueLengths, errptrs); } else { IntPtr[] cfhs = new IntPtr[cf.Length]; for (int i = 0; i < count; i++) { cfhs[i] = cf[i].Handle; } rocksdb_multi_get_cf(db, read_options, cfhs, (ulong)count, keyPtrs, keyLengths, valuePtrs, valueLengths, errptrs); } // free the buffers allocated for each encoded key foreach (var keyPtr in keyPtrs) { Marshal.FreeHGlobal(keyPtr); } // now marshal all of the values for (int i = 0; i < count; i++) { var resultPtr = valuePtrs[i]; if (resultPtr != IntPtr.Zero) { var bv = (sbyte *)resultPtr.ToPointer(); var bvLength = valueLengths[i]; values[i] = new KeyValuePair <string, string>(keys[i], CurrentFramework.CreateString(bv, 0, (int)bvLength, encoding)); rocksdb_free(resultPtr); } else { values[i] = new KeyValuePair <string, string>(keys[i], null); } } return(values); }
private unsafe string MarshalString(IntPtr resultPtr, long resultLength, Encoding encoding) { return(CurrentFramework.CreateString((sbyte *)resultPtr.ToPointer(), 0, (int)resultLength, encoding)); }
public static T Import <T>(INativeLibImporter importer, string libName, string version, bool suppressUnload) where T : class { var subdir = GetArchName(RuntimeInformation.ProcessArchitecture); var assemblyName = new AssemblyName("DynamicLink"); var assemblyBuilder = CurrentFramework.DefineDynamicAssembly(assemblyName, System.Reflection.Emit.AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynLinkModule"); string typeName = typeof(T).Name + "_impl"; var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, typeof(T)); FieldBuilder field_importer = typeBuilder.DefineField("importer", typeof(INativeLibImporter), FieldAttributes.Private | FieldAttributes.InitOnly); FieldBuilder field_libraryHandle = typeBuilder.DefineField("libraryHandle", typeof(IntPtr), FieldAttributes.Private | FieldAttributes.InitOnly); var methods = typeof(T).GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m => m.IsAbstract && !m.IsGenericMethod).ToArray(); // Define delegate types for each of the method signatures var delegateMap = new Dictionary <string, Type>(); foreach (var method in methods) { var sig = GetMethodSig(method); if (delegateMap.ContainsKey(sig)) { continue; } var delegateTypeInfo = CreateDelegateType(moduleBuilder, method); delegateMap.Add(sig, delegateTypeInfo.AsType()); } // Define one field for each method to hold a delegate var delegates = methods.Select(m => new { MethodInfo = m, DelegateType = delegateMap[GetMethodSig(m)], }).ToArray(); var fields = delegates.Select((d, i) => typeBuilder.DefineField($"{d.MethodInfo.Name}_func_{i}", d.DelegateType, FieldAttributes.Private)).ToArray(); // Create the constructor which will initialize the importer and library handle // and also use the importer to populate each of the delegate fields ConstructorBuilder constructor = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(INativeLibImporter), typeof(IntPtr) }); { var baseConstructor = typeof(T).GetTypeInfo().GetConstructors().Where(con => con.GetParameters().Length == 0).First(); ILGenerator il = constructor.GetILGenerator(); // Call base constructor il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Call, baseConstructor); // Store importer field il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_1); // importer il.Emit(OpCodes.Stfld, field_importer); // Load and store library handle il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_2); // library handle il.Emit(OpCodes.Stfld, field_libraryHandle); var getDelegateMethod = typeof(INativeLibImporter).GetTypeInfo().GetMethod("GetDelegate"); // Initialize each delegate field for (int i = 0; i < fields.Length; i++) { var delegateType = delegates[i].DelegateType; il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_1); // importer il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_libraryHandle); il.Emit(OpCodes.Ldstr, delegates[i].MethodInfo.Name); // use method name from original class as entry point il.Emit(OpCodes.Ldtoken, delegateType); // the delegate type il.Emit(OpCodes.Call, typeof(System.Type).GetTypeInfo().GetMethod("GetTypeFromHandle")); // typeof() il.Emit(OpCodes.Callvirt, getDelegateMethod); // importer.GetDelegate() il.Emit(OpCodes.Isinst, delegateType); // as <delegate type> il.Emit(OpCodes.Stfld, fields[i]); } // End of constructor il.Emit(OpCodes.Ret); } // Create destructor var destructor = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig); { var baseDestructor = typeof(T).GetTypeInfo().GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); var il = destructor.GetILGenerator(); var end = il.DefineLabel(); il.BeginExceptionBlock(); if (!suppressUnload) { il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_importer); // .importer il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_libraryHandle); // .libraryHandle il.Emit(OpCodes.Callvirt, typeof(INativeLibImporter).GetTypeInfo().GetMethod("FreeLibrary")); // INativeLibImporter::FreeLibrary() } //il.Emit(OpCodes.Leave, end); il.BeginFinallyBlock(); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Call, baseDestructor); // object::Finalize() //il.Emit(OpCodes.Endfinally); il.EndExceptionBlock(); il.MarkLabel(end); il.Emit(OpCodes.Ret); } // Now override each method from the base class for (int i = 0; i < fields.Length; i++) { var baseMethod = delegates[i].MethodInfo; var args = baseMethod.GetParameters(); var omethod = typeBuilder.DefineMethod( baseMethod.Name, (baseMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.NewSlot)) | MethodAttributes.Virtual, baseMethod.CallingConvention, baseMethod.ReturnType, args.Select(arg => arg.ParameterType).ToArray() ); var il = omethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, fields[i]); // {field} if (args.Length >= 1) { il.Emit(OpCodes.Ldarg_1); } if (args.Length >= 2) { il.Emit(OpCodes.Ldarg_2); } if (args.Length >= 3) { il.Emit(OpCodes.Ldarg_3); } for (short argNum = 4; argNum <= args.Length; argNum++) { il.Emit(OpCodes.Ldarg_S, argNum); } il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Callvirt, delegates[i].DelegateType.GetTypeInfo().GetMethod("Invoke")); il.Emit(OpCodes.Ret); } var type = typeBuilder.CreateTypeInfo(); var versionParts = version.Split('.'); var names = versionParts.Select((p, i) => libName + "-" + string.Join(".", versionParts.Take(i + 1))) .Reverse() .Concat(Enumerable.Repeat(libName, 1)); // try to load locally var paths = new[] { Path.Combine("native", subdir), "native", subdir, "", }; // If the RocksDbNative package is referenced, then dynamically load it here so that it can tell us where the native libraries are string nativeCodeBase = null; try { var nativeLibName = new AssemblyName("RocksDbNative"); var native = Assembly.Load(nativeLibName); var nativePkgClass = native.GetTypes().First(t => t.FullName == "RocksDbSharp.NativePackage"); var getCodeBaseMethod = nativePkgClass.GetTypeInfo().GetMethod("GetCodeBase"); var getCodeBase = getCodeBaseMethod.CreateDelegate <Func <string> >(); nativeCodeBase = getCodeBase(); } catch (Exception) { } var basePaths = new string[] { nativeCodeBase, Path.GetDirectoryName(UriToPath(Transitional.CurrentFramework.GetBaseDirectory())), Path.GetDirectoryName(UriToPath(Assembly.GetEntryAssembly()?.CodeBase)), Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location), Path.GetDirectoryName(UriToPath(typeof(PosixImporter).GetTypeInfo().Assembly.CodeBase)), Path.GetDirectoryName(typeof(PosixImporter).GetTypeInfo().Assembly.Location), }; var search = basePaths .Where(p => p != null) .Distinct() .SelectMany(basePath => paths.SelectMany(path => names.Select(n => Path.Combine(basePath, path, importer.Translate(n)))) .Concat(names.Select(n => importer.Translate(n))) ) .Select(path => new SearchPath { Path = path }) .ToArray(); foreach (var spec in search) { var construct = type.GetConstructor(new Type[] { typeof(INativeLibImporter), typeof(IntPtr) }); IntPtr lib = IntPtr.Zero; try { lib = importer.LoadLibrary(spec.Path); if (lib == IntPtr.Zero) { throw new NativeLoadException("LoadLibrary returned 0", null); } } catch (TargetInvocationException tie) { spec.Error = tie.InnerException; continue; } catch (Exception e) { spec.Error = e; continue; } var obj = construct.Invoke(new object[] { importer, lib }); var t = obj as T; return(t); } throw new NativeLoadException("Unable to locate rocksdb native library, either install it, or use RocksDbNative nuget package\nSearched:\n" + string.Join("\n", search.Select(s => $"{s.Path}: ({s.Error.GetType().Name}) {s.Error.Message}")), null); }
private static MergeOperator GetMergeOperatorFromPtr(IntPtr getMergeOperatorPtr) { var getMergeOperator = CurrentFramework.GetDelegateForFunctionPointer <GetMergeOperator>(getMergeOperatorPtr); return(getMergeOperator()); }