├── .gitignore
├── LICENSE
├── README.md
├── RocksDbNative
├── NativePackage.cs
├── RocksDbNative.csproj
└── build
│ ├── net40
│ └── RocksDbNative.targets
│ └── net45
│ └── RocksDbNative.targets
├── RocksDbSharp.sln
├── RocksDbSharp
├── AutoNativeImport.cs
├── BinaryComparer.cs
├── BlockBasedTableOptions.cs
├── BloomFilterPolicy.cs
├── Cache.cs
├── Checkpoint.cs
├── ColumnFamilies.cs
├── ColumnFamilyHandle.cs
├── ColumnFamilyOptions.cs
├── Comparator.cs
├── DbOptions.cs
├── Env.cs
├── EnvOptions.cs
├── IngestExternalFileOptions.cs
├── Iterator.cs
├── MergeOperator.cs
├── Native.Load.cs
├── Native.Marshaled.cs
├── Native.Wrap.cs
├── Native.cs
├── Options.cs
├── ReadOptions.cs
├── RocksDb.cs
├── RocksDbException.cs
├── RocksDbSharp.csproj
├── RocksDbSharpException.cs
├── SliceTransform.cs
├── Snapshot.cs
├── SstFileWriter.cs
├── Transitional.cs
├── WriteBatch.cs
├── WriteBatchWithIndex.cs
└── WriteOptions.cs
├── Versions.targets.include
├── examples
├── ColumnFamilyExample
│ ├── ColumnFamilyExample.csproj
│ └── Program.cs
├── PrefixExample
│ ├── PrefixExample.csproj
│ └── Program.cs
├── SimpleExampleHighLevel
│ ├── Program.cs
│ └── SimpleExampleHighLevel.csproj
└── SimpleExampleLowLevel
│ ├── Program.cs
│ └── SimpleExampleLowLevel.csproj
├── nuget
├── build-and-pack.cmd
└── instructions.txt
└── tests
└── RocksDbSharpTest
├── FunctionalTests.cs
├── RocksDbSharpTest.csproj
└── TestBinaryComparer.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | # Download this file using PowerShell v3 under Windows with the following comand
2 | # Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | [Bb]in/
15 | [Oo]bj/
16 |
17 | # NuGet Packages
18 | *.nupkg
19 | # The packages folder can be ignored because of Package Restore
20 | **/packages/*
21 | # except build/, which is used as an MSBuild target.
22 | !**/packages/build/
23 | # Uncomment if necessary however generally it will be regenerated when needed
24 | #!**/packages/repositories.config
25 |
26 | # MSTest test Results
27 | [Tt]est[Rr]esult*/
28 | [Bb]uild[Ll]og.*
29 |
30 | *_i.c
31 | *_p.c
32 | *.ilk
33 | *.meta
34 | *.obj
35 | *.pch
36 | *.pdb
37 | *.pgc
38 | *.pgd
39 | *.rsp
40 | *.sbr
41 | *.tlb
42 | *.tli
43 | *.tlh
44 | *.tmp
45 | *.tmp_proj
46 | *.log
47 | *.vspscc
48 | *.vssscc
49 | .builds
50 | *.pidb
51 | *.log
52 | *.scc
53 |
54 | # OS generated files #
55 | .DS_Store*
56 | ehthumbs.db
57 | Icon?
58 | Thumbs.db
59 |
60 | # Visual C++ cache files
61 | ipch/
62 | *.aps
63 | *.ncb
64 | *.opensdf
65 | *.sdf
66 | *.cachefile
67 |
68 | # Visual Studio profiler
69 | *.psess
70 | *.vsp
71 | *.vspx
72 |
73 | # Guidance Automation Toolkit
74 | *.gpState
75 |
76 | # ReSharper is a .NET coding add-in
77 | _ReSharper*/
78 | *.[Rr]e[Ss]harper
79 |
80 | # TeamCity is a build add-in
81 | _TeamCity*
82 |
83 | # DotCover is a Code Coverage Tool
84 | *.dotCover
85 |
86 | # NCrunch
87 | *.ncrunch*
88 | .*crunch*.local.xml
89 |
90 | # Installshield output folder
91 | [Ee]xpress/
92 |
93 | # DocProject is a documentation generator add-in
94 | DocProject/buildhelp/
95 | DocProject/Help/*.HxT
96 | DocProject/Help/*.HxC
97 | DocProject/Help/*.hhc
98 | DocProject/Help/*.hhk
99 | DocProject/Help/*.hhp
100 | DocProject/Help/Html2
101 | DocProject/Help/html
102 |
103 | # Click-Once directory
104 | publish/
105 |
106 | # Publish Web Output
107 | *.Publish.xml
108 |
109 | # Windows Azure Build Output
110 | csx
111 | *.build.csdef
112 |
113 | # Windows Store app package directory
114 | AppPackages/
115 |
116 | # Others
117 | sql/
118 | *.Cache
119 | ClientBin/
120 | [Ss]tyle[Cc]op.*
121 | ~$*
122 | *~
123 | *.dbmdl
124 | *.[Pp]ublish.xml
125 | *.pfx
126 | *.publishsettings
127 | modulesbin/
128 | tempbin/
129 |
130 | # EPiServer Site file (VPP)
131 | AppData/
132 |
133 | # RIA/Silverlight projects
134 | Generated_Code/
135 |
136 | # Backup & report files from converting an old project file to a newer
137 | # Visual Studio version. Backup files are not needed, because we have git ;-)
138 | _UpgradeReport_Files/
139 | Backup*/
140 | UpgradeLog*.XML
141 | UpgradeLog*.htm
142 |
143 | # vim
144 | *.txt~
145 | *.swp
146 | *.swo
147 |
148 | # svn
149 | .svn
150 |
151 | # SQL Server files
152 | **/App_Data/*.mdf
153 | **/App_Data/*.ldf
154 | **/App_Data/*.sdf
155 |
156 |
157 | #LightSwitch generated files
158 | GeneratedArtifacts/
159 | _Pvt_Extensions/
160 | ModelManifest.xml
161 |
162 | # =========================
163 | # Windows detritus
164 | # =========================
165 |
166 | # Windows image file caches
167 | Thumbs.db
168 | ehthumbs.db
169 |
170 | # Folder config file
171 | Desktop.ini
172 |
173 | # Recycle Bin used on file shares
174 | $RECYCLE.BIN/
175 |
176 | # Mac desktop service store files
177 | .DS_Store
178 |
179 | # SASS Compiler cache
180 | .sass-cache
181 |
182 | # Visual Studio 2014 CTP
183 | **/*.sln.ide
184 | .vs/
185 |
186 | amd64/rocksdb.dll
187 | native/**/*.dll
188 | native/
189 | native*/
190 | *.xz
191 | *.zip
192 | *.userprefs
193 | rocksdbversion
194 | version
195 |
196 | *.orig
197 | .ionide/
198 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | (Simplified BSD License)
2 |
3 | Copyright (c) 2015, Warren Falk
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rocksdb-sharp
2 |
3 | ## RocksDb for C# #
4 | RocksDB is a key-value database with a log-structured-merge design, optimized for flash and RAM storage,
5 | which can be tuned to balance write-, read-, and space-amplification factors.
6 |
7 | RocksDB is developed by Facebook and is based on LevelDB.
8 | For more information about RocksDB, visit [RocksDB](http://rocksdb.org/) and on [GitHub](https://github.com/facebook/rocksdb)
9 |
10 | This library provides C# bindings for rocksdb, implemented as a wrapper for the native rocksdb DLL (unmanaged C++) via the rocksdb C API.
11 |
12 | This is a multi-level binding,
13 | providing direct access to the C API functions (low level)
14 | plus some helper wrappers on those to aid in marshaling and exception handling (mid level)
15 | plus an idiomatic C# class hierarchy for ease of use (high level).
16 |
17 | ### Example (High Level)
18 |
19 | ```csharp
20 | var options = new DbOptions()
21 | .SetCreateIfMissing(true);
22 | using (var db = RocksDb.Open(options, path))
23 | {
24 | // Using strings below, but can also use byte arrays for both keys and values
25 | // much care has been taken to minimize buffer copying
26 | db.Put("key", "value");
27 | string value = db.Get("key");
28 | db.Remove("key");
29 | }
30 | ```
31 | ### Usage
32 |
33 | #### Using NuGet:
34 |
35 | ```
36 | install-package RocksDbSharp
37 | ```
38 |
39 | This will install the managed library which will use the unmanaged library installed on
40 | the machine at runtime. If you do not want to install the managed library, you can
41 | include it by additionally installing the "RocksDbNative" package.
42 |
43 | ```
44 | install-package RocksDbNative
45 | ```
46 |
47 | ### Requirements
48 |
49 | On Linux and Mac, the snappy library (libsnappy) must be installed.
50 |
51 | ## Caveats and Warnings:
52 |
53 | ### 64-bit only (Especially on Windows)
54 | RocksDb is supported only in 64-bit mode. Although I contributed a fix that allows it to compile in 32-bit mode, this is untested and unsupported, may not work at all, and almost certainly will have at least some major issues and should not be attempted in production.
55 |
56 | ## Extras
57 |
58 | Windows Build Script: Building rocksdb for Windows is hard; this project contains a build script to make it easy.
59 |
60 | ## Building Native Library
61 |
62 | Pre-built native binaries can be downloaded from the releases page. You may also build them yourself.
63 |
64 | (This is only a high level (and low level) wrapper on the unmanaged library and is not a managed C# port of the rocksdb database. The difficulty of a potential managed port library almost certainly far exceeds any usefulness of such a thing and so is not planned and will probably never exist).
65 |
66 | This is now buildable on Windows thanks to the Bing team at Microsoft who are actively using rocksdb. Rocksdb-sharp should work on any platform provided the native unmanaged library is available.
67 |
68 | ### Windows Native Build Instructions
69 |
70 | #### Prerequisities:
71 | * Git for Windows (specifically, the git bash environment)
72 | * CMake
73 | * Visual Studio 2017 (older versions may work but are not tested)
74 |
75 | #### Build Instructions:
76 | 1. Open "Developer Command Prompt for VS2017"
77 | 2. Run git's ```bash.exe```
78 | 3. cd to the ```native-build``` folder within the repository
79 | 4. execute ```./build-rocksdb.sh```
80 |
81 | This will create a rocksdb.dll and copy it to the where the .sln file is expecting it to be. (If you only need to run this in Windows, you can remove the references to the other two platform binaries from the .sln)
82 |
83 | ### Linux Native Build Instructions
84 |
85 | 1. ```cd native-build```
86 | 2. ```./build-rocksdb.sh```
87 |
88 | ### Mac Native Build Instructions
89 |
90 | 1. ```cd native-build```
91 | 2. ```./build-rocksdb.sh```
92 |
93 | Note: On a Mac, although a change I contributed now allows RocksDb to compile in 32 bit, it is not supported and may not work. You should definitely only run 64-bit Mono to use RocksDb with Mono on Mac.
94 |
95 | ## TODO
96 |
97 | * Many of the less-commonly-used C-API functions imports are yet to be included.
98 |
99 |
--------------------------------------------------------------------------------
/RocksDbNative/NativePackage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 |
5 | namespace RocksDbSharp
6 | {
7 | public class NativePackage
8 | {
9 | public static string GetCodeBase()
10 | {
11 | #if NETSTANDARD1_6
12 | var assemblyLocation = typeof(NativePackage).GetTypeInfo().Assembly.Location;
13 | var assemblyDir = Path.GetDirectoryName(assemblyLocation);
14 | return
15 | Directory.Exists(Path.Combine(assemblyDir, "runtimes")) ? assemblyDir :
16 | Directory.Exists(Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(assemblyDir)), "runtimes")) ? Path.GetDirectoryName(Path.GetDirectoryName(assemblyDir)) :
17 | assemblyDir;
18 | #else
19 | return AppDomain.CurrentDomain.BaseDirectory;
20 | #endif
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/RocksDbNative/RocksDbNative.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | RocksDbNative
5 | netstandard1.6;net40;net45
6 | $(RocksDbVersion).$(RocksDbNativeBuild)
7 | $(Version)
8 | $(Version)
9 | Native RocksDb Binaries (Install RocksDbSharp package for managed wrapper)
10 | Warren Falk
11 | Warren Falk
12 | Warren Falk
13 | BSD-2-Clause
14 | https://github.com/warrenfalk/rocksdb-sharp
15 | http://rocksdb.org/static/logo.svg
16 | https://github.com/warrenfalk/rocksdb-sharp.git
17 | rocksdb leveldb embedded database
18 | Copyright 2016
19 | Native RocksDb Binaries (Install RocksDbSharp package for managed wraper)
20 | False
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
49 |
53 | true
54 | PreserveNewest
55 |
56 |
58 |
59 |
60 | true
61 | build/net40
62 |
63 |
64 | true
65 | build/net45
66 |
67 |
68 |
--------------------------------------------------------------------------------
/RocksDbNative/build/net40/RocksDbNative.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreserveNewest
6 | runtimes\win-x64\native\rocksdb.dll
7 | false
8 |
9 |
10 | PreserveNewest
11 | runtimes\linux-x64\native\librocksdb.so
12 | false
13 |
14 |
15 | PreserveNewest
16 | runtimes\osx-x64\native\librocksdb.dylib
17 | false
18 |
19 |
20 |
--------------------------------------------------------------------------------
/RocksDbNative/build/net45/RocksDbNative.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreserveNewest
6 | runtimes\win-x64\native\rocksdb.dll
7 | false
8 |
9 |
10 | PreserveNewest
11 | runtimes\linux-x64\native\librocksdb.so
12 | false
13 |
14 |
15 | PreserveNewest
16 | runtimes\osx-x64\native\librocksdb.dylib
17 | false
18 |
19 |
20 |
--------------------------------------------------------------------------------
/RocksDbSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26430.12
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleExampleLowLevel", "examples\SimpleExampleLowLevel\SimpleExampleLowLevel.csproj", "{904017BB-5660-418B-B132-46EA6DF54788}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleExampleHighLevel", "examples\SimpleExampleHighLevel\SimpleExampleHighLevel.csproj", "{3504FBA2-3EB1-4B50-9E73-92E7923839B0}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrefixExample", "examples\PrefixExample\PrefixExample.csproj", "{8731668E-3F6B-4B6D-BC95-552804EDDB4D}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColumnFamilyExample", "examples\ColumnFamilyExample\ColumnFamilyExample.csproj", "{AF539614-596B-4271-B1BC-A96F58B22329}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RocksDbSharpTest", "tests\RocksDbSharpTest\RocksDbSharpTest.csproj", "{044901FD-A7BA-48A9-A5BE-8CB40A13CE02}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RocksDbSharp", "RocksDbSharp\RocksDbSharp.csproj", "{53056B3C-FAC0-41ED-9C5B-8BA41DF85F61}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RocksDbNative", "RocksDbNative\RocksDbNative.csproj", "{5DE4B734-CD28-435A-A552-257FDCCDE50A}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {904017BB-5660-418B-B132-46EA6DF54788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {904017BB-5660-418B-B132-46EA6DF54788}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {904017BB-5660-418B-B132-46EA6DF54788}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {904017BB-5660-418B-B132-46EA6DF54788}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {3504FBA2-3EB1-4B50-9E73-92E7923839B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {3504FBA2-3EB1-4B50-9E73-92E7923839B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {3504FBA2-3EB1-4B50-9E73-92E7923839B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {3504FBA2-3EB1-4B50-9E73-92E7923839B0}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {8731668E-3F6B-4B6D-BC95-552804EDDB4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {8731668E-3F6B-4B6D-BC95-552804EDDB4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {8731668E-3F6B-4B6D-BC95-552804EDDB4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {8731668E-3F6B-4B6D-BC95-552804EDDB4D}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {AF539614-596B-4271-B1BC-A96F58B22329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {AF539614-596B-4271-B1BC-A96F58B22329}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {AF539614-596B-4271-B1BC-A96F58B22329}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {AF539614-596B-4271-B1BC-A96F58B22329}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {044901FD-A7BA-48A9-A5BE-8CB40A13CE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {044901FD-A7BA-48A9-A5BE-8CB40A13CE02}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {044901FD-A7BA-48A9-A5BE-8CB40A13CE02}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {044901FD-A7BA-48A9-A5BE-8CB40A13CE02}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {53056B3C-FAC0-41ED-9C5B-8BA41DF85F61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {53056B3C-FAC0-41ED-9C5B-8BA41DF85F61}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {53056B3C-FAC0-41ED-9C5B-8BA41DF85F61}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {53056B3C-FAC0-41ED-9C5B-8BA41DF85F61}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {5DE4B734-CD28-435A-A552-257FDCCDE50A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {5DE4B734-CD28-435A-A552-257FDCCDE50A}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {5DE4B734-CD28-435A-A552-257FDCCDE50A}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {5DE4B734-CD28-435A-A552-257FDCCDE50A}.Release|Any CPU.Build.0 = Release|Any CPU
54 | EndGlobalSection
55 | GlobalSection(SolutionProperties) = preSolution
56 | HideSolutionNode = FALSE
57 | EndGlobalSection
58 | EndGlobal
59 |
--------------------------------------------------------------------------------
/RocksDbSharp/AutoNativeImport.cs:
--------------------------------------------------------------------------------
1 | /*
2 | License: MIT - see license file at https://github.com/warrenfalk/auto-native-import/blob/master/LICENSE
3 | Author: Warren Falk
4 | */
5 | using System;
6 | using System.IO;
7 | using System.Reflection;
8 | using System.Runtime.InteropServices;
9 | using System.Reflection.Emit;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using Transitional;
13 | using System.Linq.Expressions;
14 |
15 | namespace NativeImport
16 | {
17 | public static class Auto
18 | {
19 | ///
20 | /// Imports the library by name (without extensions) locating it based on platform.
21 | ///
22 | /// Use suppressUnload
to prevent the dll from unloading at finalization,
23 | /// which can be useful if you need to call the imported functions in finalizers of
24 | /// other instances and can't predict in which order the finalization will occur
25 | ///
26 | ///
27 | ///
28 | /// true to prevent unloading on finalization
29 | ///
30 | public static T Import(string name, string version, bool suppressUnload = false) where T : class
31 | {
32 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
33 | return Importers.Import(Importers.Windows, name, version, suppressUnload);
34 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
35 | return Importers.Import(Importers.Posix, name, version, suppressUnload);
36 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
37 | return Importers.Import(Importers.Posix, name, version, suppressUnload);
38 | else
39 | return Importers.Import(Importers.Windows, name, version, suppressUnload);
40 | }
41 | }
42 |
43 | public interface INativeLibImporter
44 | {
45 | IntPtr LoadLibrary(string name);
46 | IntPtr GetProcAddress(IntPtr lib, string entryPoint);
47 | void FreeLibrary(IntPtr lib);
48 | string Translate(string name);
49 | object GetDelegate(IntPtr lib, string entryPoint, Type delegateType);
50 | }
51 |
52 | public static class Importers
53 | {
54 | private static Lazy WindowsShared { get; } = new Lazy(() => new WindowsImporter());
55 | private static Lazy PosixShared { get; } = new Lazy(() => new PosixImporter());
56 |
57 | public static INativeLibImporter Windows => WindowsShared.Value;
58 | public static INativeLibImporter Posix => PosixShared.Value;
59 |
60 | static object GetDelegate(INativeLibImporter importer, IntPtr lib, string entryPoint, Type delegateType)
61 | {
62 | IntPtr procAddress = importer.GetProcAddress(lib, entryPoint);
63 | if (procAddress == IntPtr.Zero)
64 | return null;
65 | var method = typeof(CurrentFramework).GetTypeInfo().GetMethod(nameof(CurrentFramework.GetDelegateForFunctionPointer)).MakeGenericMethod(delegateType);
66 | return method.Invoke(null, new object[] { procAddress });
67 | }
68 |
69 | private class WindowsImporter : INativeLibImporter
70 | {
71 | [DllImport("kernel32.dll", EntryPoint = "LoadLibrary", SetLastError = true)]
72 | public static extern IntPtr WinLoadLibrary(string dllToLoad);
73 |
74 | [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
75 | public static extern IntPtr WinGetProcAddress(IntPtr hModule, string procedureName);
76 |
77 | [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
78 | public static extern bool WinFreeLibrary(IntPtr hModule);
79 |
80 | public IntPtr LoadLibrary(string path)
81 | {
82 | var result = WinLoadLibrary(path);
83 | if (result == IntPtr.Zero)
84 | throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
85 | return result;
86 | }
87 |
88 | public IntPtr GetProcAddress(IntPtr lib, string entryPoint)
89 | {
90 | var address = WinGetProcAddress(lib, entryPoint);
91 | return address;
92 | }
93 |
94 | public object GetDelegate(IntPtr lib, string entryPoint, Type delegateType)
95 | => Importers.GetDelegate(this, lib, entryPoint, delegateType);
96 |
97 | public void FreeLibrary(IntPtr lib)
98 | {
99 | WinFreeLibrary(lib);
100 | }
101 |
102 | public string Translate(string name)
103 | {
104 | return name + ".dll";
105 | }
106 | }
107 |
108 | private class PosixImporter : INativeLibImporter
109 | {
110 | public string LibraryExtension { get; }
111 |
112 | #pragma warning disable IDE1006 // Intentionally violating naming conventions because this is meant to match the library being loaded
113 | [DllImport("libdl")]
114 | private static extern IntPtr dlopen(String fileName, int flags);
115 |
116 | [DllImport("libdl")]
117 | private static extern IntPtr dlsym(IntPtr handle, String symbol);
118 |
119 | [DllImport("libdl")]
120 | private static extern int dlclose(IntPtr handle);
121 |
122 | [DllImport("libdl")]
123 | private static extern IntPtr dlerror();
124 |
125 | [DllImport("libc")]
126 | private static extern int uname(IntPtr buf);
127 | #pragma warning restore IDE1006
128 |
129 | public PosixImporter()
130 | {
131 | var platform = GetPlatform();
132 | if (platform.StartsWith("Darwin"))
133 | LibraryExtension = "dylib";
134 | else
135 | LibraryExtension = "so";
136 | }
137 |
138 | static string GetPlatform()
139 | {
140 | IntPtr buf = IntPtr.Zero;
141 | try
142 | {
143 | buf = Marshal.AllocHGlobal(8192);
144 | return (0 == uname(buf)) ? Marshal.PtrToStringAnsi(buf) : "Unknown";
145 | }
146 | catch
147 | {
148 | return "Unknown";
149 | }
150 | finally
151 | {
152 | if (buf != IntPtr.Zero)
153 | Marshal.FreeHGlobal(buf);
154 | }
155 | }
156 |
157 | public IntPtr LoadLibrary(string path)
158 | {
159 | dlerror();
160 | var lib = dlopen(path, 2);
161 | var errPtr = dlerror();
162 | if (errPtr != IntPtr.Zero)
163 | throw new NativeLoadException("dlopen: " + Marshal.PtrToStringAnsi(errPtr), null);
164 | return lib;
165 | }
166 |
167 | public IntPtr GetProcAddress(IntPtr lib, string entryPoint)
168 | {
169 | dlerror();
170 | IntPtr address = dlsym(lib, entryPoint);
171 | return address;
172 | }
173 |
174 | public object GetDelegate(IntPtr lib, string entryPoint, Type delegateType)
175 | => Importers.GetDelegate(this, lib, entryPoint, delegateType);
176 |
177 | public void FreeLibrary(IntPtr lib)
178 | {
179 | dlclose(lib);
180 | }
181 |
182 | public string Translate(string name)
183 | {
184 | return "lib" + name + "." + LibraryExtension;
185 | }
186 | }
187 |
188 | public static string GetArchName(Architecture arch)
189 | {
190 | switch (arch)
191 | {
192 | case Architecture.X86:
193 | return "i386";
194 | case Architecture.X64:
195 | return "amd64";
196 | default:
197 | return arch.ToString().ToLower();
198 | }
199 | }
200 |
201 | private static string GetRuntimeId(Architecture processArchitecture)
202 | {
203 | var arch = processArchitecture.ToString().ToLower();
204 | var os =
205 | RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx" :
206 | RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux" :
207 | "win";
208 | return $"{os}-{arch}";
209 | }
210 |
211 |
212 |
213 | public static T Import(INativeLibImporter importer, string libName, string version, bool suppressUnload) where T : class
214 | {
215 | var subdir = GetArchName(RuntimeInformation.ProcessArchitecture);
216 | var runtimeId = GetRuntimeId(RuntimeInformation.ProcessArchitecture);
217 |
218 | var assemblyName = new AssemblyName("DynamicLink");
219 | var assemblyBuilder = CurrentFramework.DefineDynamicAssembly(assemblyName, System.Reflection.Emit.AssemblyBuilderAccess.Run);
220 | var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynLinkModule");
221 | string typeName = typeof(T).Name + "_impl";
222 | var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, typeof(T));
223 |
224 | FieldBuilder field_importer = typeBuilder.DefineField("importer", typeof(INativeLibImporter), FieldAttributes.Private | FieldAttributes.InitOnly);
225 | FieldBuilder field_libraryHandle = typeBuilder.DefineField("libraryHandle", typeof(IntPtr), FieldAttributes.Private | FieldAttributes.InitOnly);
226 |
227 | var methods = typeof(T).GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m => m.IsAbstract && !m.IsGenericMethod).ToArray();
228 |
229 | // Define delegate types for each of the method signatures
230 | var delegateMap = new Dictionary();
231 | foreach (var method in methods)
232 | {
233 | var sig = GetMethodSig(method);
234 | if (delegateMap.ContainsKey(sig))
235 | continue;
236 | var delegateTypeInfo = CreateDelegateType(moduleBuilder, method);
237 | delegateMap.Add(sig, delegateTypeInfo.AsType());
238 | }
239 |
240 | // Define one field for each method to hold a delegate
241 | var delegates = methods.Select(m => new {
242 | MethodInfo = m,
243 | DelegateType = delegateMap[GetMethodSig(m)],
244 | }).ToArray();
245 | var delegateFields = delegates.Select((d, i) => typeBuilder.DefineField($"{d.MethodInfo.Name}_func_{i}", d.DelegateType, FieldAttributes.Private)).ToArray();
246 |
247 | // Create the constructor which will initialize the importer and library handle
248 | // and also use the importer to populate each of the delegate fields
249 | ConstructorBuilder constructor = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(INativeLibImporter), typeof(IntPtr) });
250 |
251 | {
252 | var baseConstructor = typeof(T).GetTypeInfo().GetConstructors().Where(con => con.GetParameters().Length == 0).First();
253 | ILGenerator il = constructor.GetILGenerator();
254 |
255 | // Call base constructor
256 | il.Emit(OpCodes.Ldarg_0); // this
257 | il.Emit(OpCodes.Call, baseConstructor);
258 |
259 | // Store importer field
260 | il.Emit(OpCodes.Ldarg_0); // this
261 | il.Emit(OpCodes.Ldarg_1); // importer
262 | il.Emit(OpCodes.Stfld, field_importer);
263 |
264 | // Load and store library handle
265 | il.Emit(OpCodes.Ldarg_0); // this
266 | il.Emit(OpCodes.Ldarg_2); // library handle
267 | il.Emit(OpCodes.Stfld, field_libraryHandle);
268 |
269 | var getDelegateMethod = typeof(INativeLibImporter).GetTypeInfo().GetMethod("GetDelegate");
270 | // Initialize each delegate field
271 | for (int i = 0; i < delegateFields.Length; i++)
272 | {
273 | var delegateType = delegates[i].DelegateType;
274 |
275 | il.Emit(OpCodes.Ldarg_0); // this
276 |
277 | il.Emit(OpCodes.Ldarg_1); // importer
278 | il.Emit(OpCodes.Ldarg_0); // this
279 | il.Emit(OpCodes.Ldfld, field_libraryHandle);
280 | il.Emit(OpCodes.Ldstr, delegates[i].MethodInfo.Name); // use method name from original class as entry point
281 | il.Emit(OpCodes.Ldtoken, delegateType); // the delegate type
282 | il.Emit(OpCodes.Call, typeof(System.Type).GetTypeInfo().GetMethod("GetTypeFromHandle")); // typeof()
283 | il.Emit(OpCodes.Callvirt, getDelegateMethod); // importer.GetDelegate()
284 | il.Emit(OpCodes.Isinst, delegateType); // as
285 | il.Emit(OpCodes.Stfld, delegateFields[i]);
286 | }
287 |
288 | // End of constructor
289 | il.Emit(OpCodes.Ret);
290 | }
291 |
292 | // Create destructor
293 | var destructor = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig);
294 | {
295 | var baseDestructor = typeof(T).GetTypeInfo().GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance);
296 | var il = destructor.GetILGenerator();
297 | var end = il.DefineLabel();
298 |
299 | il.BeginExceptionBlock();
300 | if (!suppressUnload)
301 | {
302 | il.Emit(OpCodes.Ldarg_0); // this
303 | il.Emit(OpCodes.Ldfld, field_importer); // .importer
304 | il.Emit(OpCodes.Ldarg_0); // this
305 | il.Emit(OpCodes.Ldfld, field_libraryHandle); // .libraryHandle
306 | il.Emit(OpCodes.Callvirt, typeof(INativeLibImporter).GetTypeInfo().GetMethod("FreeLibrary")); // INativeLibImporter::FreeLibrary()
307 | }
308 | //il.Emit(OpCodes.Leave, end);
309 | il.BeginFinallyBlock();
310 | il.Emit(OpCodes.Ldarg_0); // this
311 | il.Emit(OpCodes.Call, baseDestructor); // object::Finalize()
312 | //il.Emit(OpCodes.Endfinally);
313 | il.EndExceptionBlock();
314 | il.MarkLabel(end);
315 | il.Emit(OpCodes.Ret);
316 | }
317 |
318 | var nativeFunctionMissingExceptionConstructor = typeof(NativeFunctionMissingException).GetTypeInfo().GetConstructor(new[] { typeof(string) });
319 | // Now override each method from the base class
320 | for (int i = 0; i < delegateFields.Length; i++)
321 | {
322 | var baseMethod = delegates[i].MethodInfo;
323 | var args = baseMethod.GetParameters();
324 | var omethod = typeBuilder.DefineMethod(
325 | baseMethod.Name,
326 | (baseMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.NewSlot)) | MethodAttributes.Virtual,
327 | baseMethod.CallingConvention,
328 | baseMethod.ReturnType,
329 | args.Select(arg => arg.ParameterType).ToArray()
330 | );
331 | var il = omethod.GetILGenerator();
332 | il.Emit(OpCodes.Ldarg_0); // this
333 | il.Emit(OpCodes.Ldfld, delegateFields[i]); // {field}
334 | il.Emit(OpCodes.Dup);
335 | var error = il.DefineLabel();
336 | il.Emit(OpCodes.Brfalse_S, error);
337 | if (args.Length >= 1)
338 | il.Emit(OpCodes.Ldarg_1);
339 | if (args.Length >= 2)
340 | il.Emit(OpCodes.Ldarg_2);
341 | if (args.Length >= 3)
342 | il.Emit(OpCodes.Ldarg_3);
343 | for (short argNum = 4; argNum <= args.Length; argNum++)
344 | il.Emit(OpCodes.Ldarg_S, argNum);
345 | il.Emit(OpCodes.Tailcall);
346 | il.Emit(OpCodes.Callvirt, delegates[i].DelegateType.GetTypeInfo().GetMethod("Invoke"));
347 | il.Emit(OpCodes.Ret);
348 | il.MarkLabel(error);
349 | il.Emit(OpCodes.Ldstr, baseMethod.ToString());
350 | il.Emit(OpCodes.Newobj, nativeFunctionMissingExceptionConstructor);
351 | il.Emit(OpCodes.Throw);
352 | }
353 |
354 | var type = typeBuilder.CreateTypeInfo();
355 |
356 | var versionParts = version.Split('.');
357 | var names = versionParts.Select((p, i) => libName + "-" + string.Join(".", versionParts.Take(i + 1)))
358 | .Reverse()
359 | .Concat(Enumerable.Repeat(libName, 1));
360 |
361 | // try to load locally
362 | var paths = new[]
363 | {
364 | Path.Combine("runtimes", runtimeId, "native"),
365 | Path.Combine("native", subdir),
366 | "native",
367 | subdir,
368 | "",
369 | };
370 |
371 | // If the RocksDbNative package is referenced, then dynamically load it here so that it can tell us where the native libraries are
372 | string nativeCodeBase = null;
373 | try
374 | {
375 | var nativeLibName = new AssemblyName("RocksDbNative");
376 | var native = Assembly.Load(nativeLibName);
377 | var nativePkgClass = native.GetTypes().First(t => t.FullName == "RocksDbSharp.NativePackage");
378 | var getCodeBaseMethod = nativePkgClass.GetTypeInfo().GetMethod("GetCodeBase");
379 | var getCodeBase = getCodeBaseMethod.CreateDelegate>();
380 | nativeCodeBase = getCodeBase();
381 | }
382 | catch (Exception)
383 | {
384 | }
385 |
386 | var basePaths = new string[] {
387 | nativeCodeBase,
388 | Path.GetDirectoryName(UriToPath(Transitional.CurrentFramework.GetBaseDirectory())),
389 | Path.GetDirectoryName(UriToPath(Assembly.GetEntryAssembly()?.CodeBase)),
390 | Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location),
391 | Path.GetDirectoryName(UriToPath(typeof(PosixImporter).GetTypeInfo().Assembly.CodeBase)),
392 | Path.GetDirectoryName(typeof(PosixImporter).GetTypeInfo().Assembly.Location),
393 | };
394 | var search = basePaths
395 | .Where(p => p != null)
396 | .Distinct()
397 | .SelectMany(basePath =>
398 | paths.SelectMany(path => names.Select(n => Path.Combine(basePath, path, importer.Translate(n))))
399 | .Concat(names.Select(n => importer.Translate(n)))
400 | )
401 | .Select(path => new SearchPath { Path = path })
402 | .ToArray();
403 |
404 | foreach (var spec in search)
405 | {
406 | var construct = type.GetConstructor(new Type[] { typeof(INativeLibImporter), typeof(IntPtr) });
407 | IntPtr lib = IntPtr.Zero;
408 | try
409 | {
410 | lib = importer.LoadLibrary(spec.Path);
411 | if (lib == IntPtr.Zero)
412 | throw new NativeLoadException("LoadLibrary returned 0", null);
413 | }
414 | catch (TargetInvocationException tie)
415 | {
416 | spec.Error = tie.InnerException;
417 | continue;
418 | }
419 | catch (Exception e)
420 | {
421 | spec.Error = e;
422 | continue;
423 | }
424 | var obj = construct.Invoke(new object[] { importer, lib });
425 | var t = obj as T;
426 | return t;
427 | }
428 |
429 | 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);
430 | }
431 |
432 | private static string UriToPath(string uriString)
433 | {
434 | if (uriString == null || !Uri.IsWellFormedUriString(uriString, UriKind.RelativeOrAbsolute))
435 | return null;
436 | var uri = new Uri(uriString);
437 | return uri.LocalPath;
438 | }
439 |
440 | private class SearchPath
441 | {
442 | public string Path { get; set; }
443 | public Exception Error { get; set; }
444 | }
445 |
446 | private static string GetMethodSig(MethodInfo m)
447 | {
448 | return string.Join("_", Enumerable.Repeat(m.ReturnType.Name, 1).Concat(m.GetParameters().Select(p => p.ParameterType.Name)));
449 | }
450 |
451 | private static TypeInfo CreateDelegateType(ModuleBuilder moduleBuilder, MethodInfo methodTemplate)
452 | {
453 | var sig = GetMethodSig(methodTemplate);
454 | var typeBuilder = moduleBuilder.DefineType(sig, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed, typeof(System.MulticastDelegate));
455 | var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(Object), typeof(IntPtr) });
456 | constructor.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
457 |
458 | var parameters = methodTemplate.GetParameters().Select(pi => pi.ParameterType).ToArray();
459 | var methodBuilder = typeBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, methodTemplate.ReturnType, parameters);
460 | methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
461 |
462 | return typeBuilder.CreateTypeInfo();
463 | }
464 |
465 | }
466 |
467 | public class NativeFunctionMissingException : Exception
468 | {
469 | public NativeFunctionMissingException()
470 | : base("Failed to find entry point")
471 | {
472 | }
473 |
474 | public NativeFunctionMissingException(string entryPoint)
475 | : base($"Failed to find entry point for {entryPoint}", null)
476 | {
477 | }
478 | }
479 |
480 | public class NativeLoadException : Exception
481 | {
482 | public NativeLoadException(string message, Exception inner)
483 | : base(message, inner)
484 | {
485 | }
486 | }
487 | }
488 |
489 |
--------------------------------------------------------------------------------
/RocksDbSharp/BinaryComparer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Collections.Generic;
4 | using System.IO;
5 |
6 | namespace RocksDbSharp
7 | {
8 | // TODO: consider somehow reusing the actual unmanaged comparer
9 | public class BinaryComparer : IEqualityComparer, IComparer
10 | {
11 | public static BinaryComparer Default { get; } = new BinaryComparer();
12 |
13 | public int Compare(byte[] a1, byte[] a2)
14 | {
15 | int length = Math.Min(a1.Length, a2.Length);
16 | unsafe
17 | {
18 | fixed (byte* p1 = a1, p2 = a2)
19 | {
20 | byte* c1 = p1, c2 = p2;
21 | byte* end = c1 + length;
22 | byte* end1 = c1 + a1.Length, end2 = c2 + a2.Length;
23 | for (; c1 < end && *c1 == *c2; c1++, c2++) ;
24 | if (c1 == end1)
25 | return c2 == end2 ? 0 : -1;
26 | if (c2 == end2)
27 | return 1;
28 | return (*c1 < *c2) ? -1 : 1;
29 | }
30 | }
31 | }
32 |
33 | public bool Equals(byte[] a1, byte[] a2)
34 | {
35 | if (ReferenceEquals(a1, a2))
36 | return true;
37 | if (a1 == null || a2 == null || a1.Length != a2.Length)
38 | return false;
39 | unsafe
40 | {
41 | fixed (byte* p1 = a1, p2 = a2)
42 | {
43 | byte* x1 = p1, x2 = p2;
44 | int l = a1.Length;
45 | for (int i = 0; i < l / 8; i++, x1 += 8, x2 += 8)
46 | if (*((long*)x1) != *((long*)x2)) return false;
47 | if ((l & 4) != 0) { if (*((int*)x1) != *((int*)x2)) return false; x1 += 4; x2 += 4; }
48 | if ((l & 2) != 0) { if (*((short*)x1) != *((short*)x2)) return false; x1 += 2; x2 += 2; }
49 | if ((l & 1) != 0) if (*((byte*)x1) != *((byte*)x2)) return false;
50 | return true;
51 | }
52 | }
53 | }
54 |
55 | public bool PrefixEquals(byte[] a1, byte[] a2, int prefix)
56 | {
57 | if (ReferenceEquals(a1, a2))
58 | return true;
59 | prefix = Math.Min(prefix, Math.Max(a1.Length, a2.Length));
60 | var a1length = Math.Min(prefix, a1.Length);
61 | var a2length = Math.Min(prefix, a2.Length);
62 | if (a1 == null || a2 == null || a1length != a2length)
63 | return false;
64 | unsafe
65 | {
66 | fixed (byte* p1 = a1, p2 = a2)
67 | {
68 | byte* x1 = p1, x2 = p2;
69 | int l = a1length;
70 | for (int i = 0; i < l / 8; i++, x1 += 8, x2 += 8)
71 | if (*((long*)x1) != *((long*)x2)) return false;
72 | if ((l & 4) != 0) { if (*((int*)x1) != *((int*)x2)) return false; x1 += 4; x2 += 4; }
73 | if ((l & 2) != 0) { if (*((short*)x1) != *((short*)x2)) return false; x1 += 2; x2 += 2; }
74 | if ((l & 1) != 0) if (*((byte*)x1) != *((byte*)x2)) return false;
75 | return true;
76 | }
77 | }
78 | }
79 |
80 | public int GetHashCode(byte[] obj)
81 | {
82 | return MurMurHash3.Hash(new MemoryStream(obj));
83 | }
84 | }
85 |
86 | /*
87 | This code is public domain.
88 |
89 | The MurmurHash3 algorithm was created by Austin Appleby and put into the public domain. See http://code.google.com/p/smhasher/
90 |
91 | This C# variant was authored by
92 | Elliott B. Edwards and was placed into the public domain as a gist
93 | Status...Working on verification (Test Suite)
94 | Set up to run as a LinqPad (linqpad.net) script (thus the ".Dump()" call)
95 | */
96 | public static class MurMurHash3
97 | {
98 | //Change to suit your needs
99 | const uint seed = 144;
100 |
101 | // TODO: optimize this to use a byte pointer
102 | public static int Hash(Stream stream)
103 | {
104 | const uint c1 = 0xcc9e2d51;
105 | const uint c2 = 0x1b873593;
106 |
107 | uint h1 = seed;
108 | uint k1 = 0;
109 | uint streamLength = 0;
110 |
111 | using (BinaryReader reader = new BinaryReader(stream))
112 | {
113 | byte[] chunk = reader.ReadBytes(4);
114 | while (chunk.Length > 0)
115 | {
116 | streamLength += (uint)chunk.Length;
117 | switch (chunk.Length)
118 | {
119 | case 4:
120 | /* Get four bytes from the input into an uint */
121 | k1 = (uint)
122 | (chunk[0]
123 | | chunk[1] << 8
124 | | chunk[2] << 16
125 | | chunk[3] << 24);
126 |
127 | /* bitmagic hash */
128 | k1 *= c1;
129 | k1 = Rotl32(k1, 15);
130 | k1 *= c2;
131 |
132 | h1 ^= k1;
133 | h1 = Rotl32(h1, 13);
134 | h1 = h1 * 5 + 0xe6546b64;
135 | break;
136 | case 3:
137 | k1 = (uint)
138 | (chunk[0]
139 | | chunk[1] << 8
140 | | chunk[2] << 16);
141 | k1 *= c1;
142 | k1 = Rotl32(k1, 15);
143 | k1 *= c2;
144 | h1 ^= k1;
145 | break;
146 | case 2:
147 | k1 = (uint)
148 | (chunk[0]
149 | | chunk[1] << 8);
150 | k1 *= c1;
151 | k1 = Rotl32(k1, 15);
152 | k1 *= c2;
153 | h1 ^= k1;
154 | break;
155 | case 1:
156 | k1 = (uint)(chunk[0]);
157 | k1 *= c1;
158 | k1 = Rotl32(k1, 15);
159 | k1 *= c2;
160 | h1 ^= k1;
161 | break;
162 |
163 | }
164 | chunk = reader.ReadBytes(4);
165 | }
166 | }
167 |
168 | // finalization, magic chants to wrap it all up
169 | h1 ^= streamLength;
170 | h1 = Fmix(h1);
171 |
172 | unchecked //ignore overflow
173 | {
174 | return (int)h1;
175 | }
176 | }
177 |
178 | private static uint Rotl32(uint x, byte r)
179 | {
180 | return (x << r) | (x >> (32 - r));
181 | }
182 |
183 | private static uint Fmix(uint h)
184 | {
185 | h ^= h >> 16;
186 | h *= 0x85ebca6b;
187 | h ^= h >> 13;
188 | h *= 0xc2b2ae35;
189 | h ^= h >> 16;
190 | return h;
191 | }
192 | }
193 | }
194 |
195 |
--------------------------------------------------------------------------------
/RocksDbSharp/BlockBasedTableOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Dynamic;
3 |
4 | namespace RocksDbSharp
5 | {
6 | public class BlockBasedTableOptions
7 | {
8 | public IntPtr Handle { get; protected set; }
9 |
10 | // The following exists only to retain a reference to those types which are used in-place by rocksdb
11 | // and not copied (or reference things that are used in-place). The idea is to have managed references
12 | // track the behavior of the unmanaged reference as much as possible. This prevents access violations
13 | // when the garbage collector cleans up the last managed reference
14 | internal dynamic References { get; } = new ExpandoObject();
15 |
16 | public BlockBasedTableOptions()
17 | {
18 | this.Handle = Native.Instance.rocksdb_block_based_options_create();
19 | }
20 |
21 | ~BlockBasedTableOptions()
22 | {
23 | if (Handle != IntPtr.Zero)
24 | {
25 | #if !NODESTROY
26 | Native.Instance.rocksdb_block_based_options_destroy(Handle);
27 | #endif
28 | Handle = IntPtr.Zero;
29 | }
30 | }
31 |
32 | public BlockBasedTableOptions SetBlockSize(ulong blockSize)
33 | {
34 | Native.Instance.rocksdb_block_based_options_set_block_size(Handle, (UIntPtr)blockSize);
35 | return this;
36 | }
37 |
38 | public BlockBasedTableOptions SetBlockSizeDeviation(int blockSizeDeviation)
39 | {
40 | Native.Instance.rocksdb_block_based_options_set_block_size_deviation(Handle, blockSizeDeviation);
41 | return this;
42 | }
43 |
44 | public BlockBasedTableOptions SetBlockRestartInterval(int blockRestartInterval)
45 | {
46 | Native.Instance.rocksdb_block_based_options_set_block_restart_interval(Handle, blockRestartInterval);
47 | return this;
48 | }
49 |
50 | public BlockBasedTableOptions SetFilterPolicy(IntPtr filterPolicy)
51 | {
52 | Native.Instance.rocksdb_block_based_options_set_filter_policy(Handle, filterPolicy);
53 | return this;
54 | }
55 |
56 | public BlockBasedTableOptions SetFilterPolicy(BloomFilterPolicy filterPolicy)
57 | {
58 | // store a managed reference to prevent garbage collection
59 | References.FilterPolicy = filterPolicy;
60 | Native.Instance.rocksdb_block_based_options_set_filter_policy(Handle, filterPolicy.Handle);
61 | return this;
62 | }
63 |
64 | public BlockBasedTableOptions SetNoBlockCache(bool noBlockCache)
65 | {
66 | Native.Instance.rocksdb_block_based_options_set_no_block_cache(Handle, noBlockCache);
67 | return this;
68 | }
69 |
70 | public BlockBasedTableOptions SetBlockCache(IntPtr blockCache)
71 | {
72 | Native.Instance.rocksdb_block_based_options_set_block_cache(Handle, blockCache);
73 | return this;
74 | }
75 |
76 | public BlockBasedTableOptions SetBlockCache(Cache blockCache)
77 | {
78 | References.BlockCache = blockCache;
79 | Native.Instance.rocksdb_block_based_options_set_block_cache(Handle, blockCache.Handle);
80 | return this;
81 | }
82 |
83 | public BlockBasedTableOptions SetBlockCacheCompressed(IntPtr blockCacheCompressed)
84 | {
85 | Native.Instance.rocksdb_block_based_options_set_block_cache_compressed(Handle, blockCacheCompressed);
86 | return this;
87 | }
88 |
89 | public BlockBasedTableOptions SetWholeKeyFiltering(bool wholeKeyFiltering)
90 | {
91 | Native.Instance.rocksdb_block_based_options_set_whole_key_filtering(Handle, wholeKeyFiltering);
92 | return this;
93 | }
94 |
95 | public BlockBasedTableOptions SetFormatVersion(int formatVersion)
96 | {
97 | Native.Instance.rocksdb_block_based_options_set_format_version(Handle, formatVersion);
98 | return this;
99 | }
100 |
101 | public BlockBasedTableOptions SetIndexType(BlockBasedTableIndexType indexType)
102 | {
103 | Native.Instance.rocksdb_block_based_options_set_index_type(Handle, indexType);
104 | return this;
105 | }
106 |
107 | public BlockBasedTableOptions SetHashIndexAllowCollision(bool allowCollision)
108 | {
109 | Native.Instance.rocksdb_block_based_options_set_hash_index_allow_collision(Handle, allowCollision);
110 | return this;
111 | }
112 |
113 | public BlockBasedTableOptions SetCacheIndexAndFilterBlocks(bool cacheIndexAndFilterBlocks)
114 | {
115 | Native.Instance.rocksdb_block_based_options_set_cache_index_and_filter_blocks(Handle, cacheIndexAndFilterBlocks);
116 | return this;
117 | }
118 |
119 | public BlockBasedTableOptions SetPinL0FilterAndIndexBlocksInCache(bool pinL0FilterAndIndexBlocksInCache)
120 | {
121 | Native.Instance.rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(Handle, pinL0FilterAndIndexBlocksInCache);
122 | return this;
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/RocksDbSharp/BloomFilterPolicy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace RocksDbSharp
4 | {
5 | public class BloomFilterPolicy
6 | {
7 | public IntPtr Handle { get; protected set; }
8 |
9 | private BloomFilterPolicy(IntPtr handle)
10 | {
11 | this.Handle = handle;
12 | }
13 |
14 | ~BloomFilterPolicy()
15 | {
16 | if (Handle != IntPtr.Zero)
17 | {
18 | #if !NODESTROY
19 | // Commented out until a solution is found to rocksdb issue #1095 (https://github.com/facebook/rocksdb/issues/1095)
20 | // If you create one of these, use it in an Option which will destroy it when finished
21 | // Otherwise don't create one or it will leak
22 | //Native.Instance.rocksdb_filterpolicy_destroy(Handle);
23 | #endif
24 | Handle = IntPtr.Zero;
25 | }
26 | }
27 |
28 | ///
29 | /// Return a new filter policy that uses a bloom filter with approximately
30 | /// the specified number of bits per key.
31 | /// bits_per_key: bits per key in bloom filter. A good value for bits_per_key
32 | /// is 10, which yields a filter with ~ 1% false positive rate.
33 | /// use_block_based_builder: use block based filter rather than full fiter.
34 | /// If you want to builder full filter, it needs to be set to false.
35 | /// Callers must delete the result after any database that is using the
36 | /// result has been closed.
37 | /// Note: if you are using a custom comparator that ignores some parts
38 | /// of the keys being compared, you must not use NewBloomFilterPolicy()
39 | /// and must provide your own FilterPolicy that also ignores the
40 | /// corresponding parts of the keys. For example, if the comparator
41 | /// ignores trailing spaces, it would be incorrect to use a
42 | /// FilterPolicy (like NewBloomFilterPolicy) that does not ignore
43 | /// trailing spaces in keys.
44 | ///
45 | /// Bits per key.
46 | public static BloomFilterPolicy Create(int bits_per_key = 10, bool use_block_based_builder = true) {
47 | IntPtr handle = use_block_based_builder ? Native.Instance.rocksdb_filterpolicy_create_bloom(bits_per_key) : Native.Instance.rocksdb_filterpolicy_create_bloom_full(bits_per_key);
48 | return new BloomFilterPolicy(handle);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/RocksDbSharp/Cache.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace RocksDbSharp
6 | {
7 | public class Cache
8 | {
9 | public IntPtr Handle { get; protected set; }
10 |
11 | private Cache(IntPtr handle)
12 | {
13 | this.Handle = handle;
14 | }
15 |
16 | ~Cache()
17 | {
18 | if (Handle != IntPtr.Zero)
19 | {
20 | Native.Instance.rocksdb_cache_destroy(Handle);
21 | Handle = IntPtr.Zero;
22 | }
23 | }
24 |
25 | public static Cache CreateLru(ulong capacity)
26 | {
27 | IntPtr handle = Native.Instance.rocksdb_cache_create_lru(new UIntPtr(capacity));
28 | return new Cache(handle);
29 | }
30 |
31 | public Cache SetCapacity(ulong capacity)
32 | {
33 | Native.Instance.rocksdb_cache_set_capacity(Handle, new UIntPtr(capacity));
34 | return this;
35 | }
36 |
37 | public ulong GetUsage()
38 | {
39 | return Native.Instance.rocksdb_cache_get_usage(Handle).ToUInt64();
40 | }
41 |
42 | public ulong GetPinnedUsage()
43 | {
44 | return Native.Instance.rocksdb_cache_get_pinned_usage(Handle).ToUInt64();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/RocksDbSharp/Checkpoint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace RocksDbSharp
6 | {
7 | public class Checkpoint : IDisposable
8 | {
9 | public IntPtr Handle { get; }
10 |
11 | public Checkpoint(IntPtr handle)
12 | {
13 | Handle = handle;
14 | }
15 |
16 | public void Save(string checkpointDir, ulong logSizeForFlush = 0)
17 | => Native.Instance.rocksdb_checkpoint_create(Handle, checkpointDir, logSizeForFlush);
18 |
19 | public void Dispose()
20 | {
21 | Native.Instance.rocksdb_checkpoint_object_destroy(Handle);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/RocksDbSharp/ColumnFamilies.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace RocksDbSharp
9 | {
10 | public class ColumnFamilies : IEnumerable
11 | {
12 | private List Descriptors { get; } = new List();
13 |
14 | public static readonly string DefaultName = "default";
15 |
16 | public class Descriptor
17 | {
18 | public string Name { get; }
19 | public ColumnFamilyOptions Options { get; }
20 |
21 | public Descriptor(string name, ColumnFamilyOptions options)
22 | {
23 | this.Name = name;
24 | this.Options = options;
25 | }
26 | }
27 |
28 | public ColumnFamilies(ColumnFamilyOptions options = null)
29 | {
30 | Descriptors.Add(new Descriptor(DefaultName, options ?? new ColumnFamilyOptions()));
31 | }
32 |
33 | public IEnumerable Names => this.Select(cfd => cfd.Name);
34 |
35 | public IEnumerable OptionHandles => this.Select(cfd => cfd.Options.Handle);
36 |
37 | public void Add(Descriptor descriptor)
38 | {
39 | if (descriptor.Name == DefaultName)
40 | Descriptors[0] = descriptor;
41 | else
42 | Descriptors.Add(descriptor);
43 | }
44 |
45 | public void Add(string name, ColumnFamilyOptions options)
46 | {
47 | Add(new Descriptor(name, options));
48 | }
49 |
50 | public IEnumerator GetEnumerator()
51 | {
52 | return Descriptors.GetEnumerator();
53 | }
54 |
55 | IEnumerator IEnumerable.GetEnumerator()
56 | {
57 | return Descriptors.GetEnumerator();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/RocksDbSharp/ColumnFamilyHandle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RocksDbSharp
8 | {
9 | #pragma warning disable IDE1006 // Naming (missing I) for backward source-compatibility reasons
10 | public interface ColumnFamilyHandle
11 | #pragma warning restore IDE1006
12 | {
13 | IntPtr Handle { get; }
14 | }
15 |
16 | class ColumnFamilyHandleInternal : ColumnFamilyHandle, IDisposable
17 | {
18 | public ColumnFamilyHandleInternal(IntPtr handle)
19 | {
20 | this.Handle = handle;
21 | }
22 |
23 | public IntPtr Handle { get; protected set; }
24 |
25 | public void Dispose()
26 | {
27 | if (Handle != IntPtr.Zero)
28 | {
29 | #if !NODESTROY
30 | Native.Instance.rocksdb_column_family_handle_destroy(Handle);
31 | #endif
32 | Handle = IntPtr.Zero;
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/RocksDbSharp/Comparator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using System.Text;
5 | using Transitional;
6 |
7 | namespace RocksDbSharp
8 | {
9 | public interface Comparator
10 | {
11 | string Name { get; }
12 | int Compare(IntPtr a, UIntPtr alen, IntPtr b, UIntPtr blen);
13 | }
14 |
15 | public abstract class StringComparatorBase : Comparator
16 | {
17 | public Encoding Encoding { get; }
18 |
19 | public string Name { get; }
20 |
21 | public StringComparatorBase(Encoding encoding = null, string name = null, IntPtr state = default(IntPtr))
22 | {
23 | Name = name ?? typeof(StringComparatorBase).Name;
24 | Encoding = encoding ?? Encoding.UTF8;
25 | }
26 |
27 | public abstract int Compare(string a, string b);
28 |
29 | public unsafe int Compare(IntPtr a, UIntPtr alen, IntPtr b, UIntPtr blen)
30 | {
31 | var astr = Encoding.GetString((byte*)a, (int)alen);
32 | var bstr = Encoding.GetString((byte*)b, (int)blen);
33 | return Compare(astr, bstr);
34 | }
35 | }
36 |
37 | public class StringComparator : StringComparatorBase
38 | {
39 | public Comparison CompareFunc { get; }
40 |
41 | public StringComparator(IComparer comparer = null, Encoding encoding = null, string name = null)
42 | : base(encoding, name)
43 | {
44 | if (comparer == null)
45 | comparer = StringComparer.CurrentCulture;
46 | CompareFunc = comparer.Compare;
47 | }
48 |
49 | public StringComparator(bool ignoreCase, Encoding encoding = null, string name = null)
50 | : this(ignoreCase ? StringComparer.CurrentCultureIgnoreCase : StringComparer.CurrentCulture, encoding, name)
51 | {
52 | }
53 |
54 | public override int Compare(string a, string b) => CompareFunc(a, b);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/RocksDbSharp/Env.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace RocksDbSharp
6 | {
7 | public class Env
8 | {
9 | public IntPtr Handle { get; protected set; }
10 |
11 | private Env(IntPtr handle)
12 | {
13 | Handle = handle;
14 | }
15 |
16 | public static Env CreateDefaultEnv()
17 | {
18 | return new Env(Native.Instance.rocksdb_create_default_env());
19 | }
20 |
21 | public static Env CreateMemEnv()
22 | {
23 | return new Env(Native.Instance.rocksdb_create_mem_env());
24 | }
25 |
26 | public Env SetBackgroundThreads(int value)
27 | {
28 | Native.Instance.rocksdb_env_set_background_threads(Handle, value);
29 | return this;
30 | }
31 |
32 | public Env SetHighPriorityBackgroundThreads(int value)
33 | {
34 | Native.Instance.rocksdb_env_set_high_priority_background_threads(Handle, value);
35 | return this;
36 | }
37 |
38 | public void JoinAllThreads()
39 | {
40 | Native.Instance.rocksdb_env_join_all_threads(Handle);
41 | }
42 |
43 | ~Env()
44 | {
45 | if (Handle != IntPtr.Zero)
46 | {
47 | #if !NODESTROY
48 | Native.Instance.rocksdb_env_destroy(Handle);
49 | #endif
50 | Handle = IntPtr.Zero;
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/RocksDbSharp/EnvOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace RocksDbSharp
6 | {
7 | public class EnvOptions
8 | {
9 | public IntPtr Handle { get; protected set; }
10 |
11 | public EnvOptions()
12 | {
13 | Handle = Native.Instance.rocksdb_envoptions_create();
14 | }
15 |
16 | ~EnvOptions()
17 | {
18 | if (Handle != IntPtr.Zero)
19 | {
20 | #if !NODESTROY
21 | Native.Instance.rocksdb_envoptions_destroy(Handle);
22 | #endif
23 | Handle = IntPtr.Zero;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/RocksDbSharp/IngestExternalFileOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace RocksDbSharp
6 | {
7 | public class IngestExternalFileOptions
8 | {
9 | public IntPtr Handle { get; protected set; }
10 |
11 | public IngestExternalFileOptions()
12 | {
13 | Handle = Native.Instance.rocksdb_ingestexternalfileoptions_create();
14 | }
15 |
16 | ~IngestExternalFileOptions()
17 | {
18 | if (Handle != IntPtr.Zero)
19 | {
20 | #if !NODESTROY
21 | Native.Instance.rocksdb_ingestexternalfileoptions_destroy(Handle);
22 | #endif
23 | Handle = IntPtr.Zero;
24 | }
25 | }
26 |
27 | public IngestExternalFileOptions SetMoveFiles(bool moveFiles)
28 | {
29 | Native.Instance.rocksdb_ingestexternalfileoptions_set_move_files(Handle, moveFiles);
30 | return this;
31 | }
32 |
33 | public IngestExternalFileOptions SetSnapshotConsistency(bool snapshotConsistency)
34 | {
35 | Native.Instance.rocksdb_ingestexternalfileoptions_set_snapshot_consistency(Handle, snapshotConsistency);
36 | return this;
37 | }
38 |
39 | public IngestExternalFileOptions SetAllowGlobalSeqno(bool allow)
40 | {
41 | Native.Instance.rocksdb_ingestexternalfileoptions_set_allow_global_seqno(Handle, allow);
42 | return this;
43 | }
44 |
45 | public IngestExternalFileOptions SetAllowBlockingFlush(bool allow)
46 | {
47 | Native.Instance.rocksdb_ingestexternalfileoptions_set_allow_blocking_flush(Handle, allow);
48 | return this;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/RocksDbSharp/Iterator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Transitional;
8 |
9 | namespace RocksDbSharp
10 | {
11 | public class Iterator : IDisposable
12 | {
13 | private IntPtr handle;
14 | #pragma warning disable CS0414
15 | private ReadOptions readOptions;
16 | #pragma warning restore CS0414
17 |
18 | internal Iterator(IntPtr handle)
19 | {
20 | this.handle = handle;
21 | }
22 |
23 | internal Iterator(IntPtr handle, ReadOptions readOptions) : this(handle)
24 | {
25 | // Note: passing readOptions in here has no actual effect except to keep readOptions
26 | // from being garbage collected whilst the Iterator is still alive because the
27 | // the iterator on the native side will actually read things from some of the readOptions
28 | // directly
29 | this.readOptions = readOptions;
30 | }
31 |
32 | public IntPtr Handle { get { return handle; } }
33 |
34 | public void Dispose()
35 | {
36 | if (handle != IntPtr.Zero)
37 | {
38 | #if !NODESTROY
39 | Native.Instance.rocksdb_iter_destroy(handle);
40 | #endif
41 | handle = IntPtr.Zero;
42 | }
43 | }
44 |
45 | ///
46 | /// Detach the iterator from its handle but don't dispose the handle
47 | ///
48 | ///
49 | public IntPtr Detach()
50 | {
51 | var r = handle;
52 | handle = IntPtr.Zero;
53 | return r;
54 | }
55 |
56 | public bool Valid()
57 | {
58 | return Native.Instance.rocksdb_iter_valid(handle);
59 | }
60 |
61 | public Iterator SeekToFirst()
62 | {
63 | Native.Instance.rocksdb_iter_seek_to_first(handle);
64 | return this;
65 | }
66 |
67 | public Iterator SeekToLast()
68 | {
69 | Native.Instance.rocksdb_iter_seek_to_last(handle);
70 | return this;
71 | }
72 |
73 | public unsafe Iterator Seek(byte *key, ulong klen)
74 | {
75 | Native.Instance.rocksdb_iter_seek(handle, key, (UIntPtr)klen);
76 | return this;
77 | }
78 |
79 | public Iterator Seek(byte[] key)
80 | {
81 | return Seek(key, (ulong)key.GetLongLength(0));
82 | }
83 |
84 | public Iterator Seek(byte[] key, ulong klen)
85 | {
86 | Native.Instance.rocksdb_iter_seek(handle, key, (UIntPtr)klen);
87 | return this;
88 | }
89 |
90 | public Iterator Seek(string key)
91 | {
92 | Native.Instance.rocksdb_iter_seek(handle, key);
93 | return this;
94 | }
95 |
96 | public unsafe Iterator SeekForPrev(byte* key, ulong klen)
97 | {
98 | Native.Instance.rocksdb_iter_seek_for_prev(handle, key, (UIntPtr)klen);
99 | return this;
100 | }
101 |
102 | public Iterator SeekForPrev(byte[] key)
103 | {
104 | SeekForPrev(key, (ulong)key.Length);
105 | return this;
106 | }
107 |
108 | public Iterator SeekForPrev(byte[] key, ulong klen)
109 | {
110 | Native.Instance.rocksdb_iter_seek_for_prev(handle, key, (UIntPtr)klen);
111 | return this;
112 | }
113 |
114 | public Iterator SeekForPrev(string key)
115 | {
116 | Native.Instance.rocksdb_iter_seek_for_prev(handle, key);
117 | return this;
118 | }
119 |
120 | public Iterator Next()
121 | {
122 | Native.Instance.rocksdb_iter_next(handle);
123 | return this;
124 | }
125 |
126 | public Iterator Prev()
127 | {
128 | Native.Instance.rocksdb_iter_prev(handle);
129 | return this;
130 | }
131 |
132 | public byte[] Key()
133 | {
134 | return Native.Instance.rocksdb_iter_key(handle);
135 | }
136 |
137 | public byte[] Value()
138 | {
139 | return Native.Instance.rocksdb_iter_value(handle);
140 | }
141 |
142 | public string StringKey()
143 | {
144 | return Native.Instance.rocksdb_iter_key_string(handle);
145 | }
146 |
147 | public string StringValue()
148 | {
149 | return Native.Instance.rocksdb_iter_value_string(handle);
150 | }
151 |
152 | // TODO: figure out how to best implement rocksdb_iter_get_error
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/RocksDbSharp/MergeOperator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace RocksDbSharp
6 | {
7 | public interface MergeOperator
8 | {
9 | string Name { get; }
10 | IntPtr PartialMerge(IntPtr key, UIntPtr keyLength, IntPtr operandsList, IntPtr operandsListLength, int numOperands, IntPtr success, IntPtr newValueLength);
11 | IntPtr FullMerge(IntPtr key, UIntPtr keyLength, IntPtr existingValue, UIntPtr existingValueLength, IntPtr operandsList, IntPtr operandsListLength, int numOperands, IntPtr success, IntPtr newValueLength);
12 | void DeleteValue(IntPtr value, UIntPtr valueLength);
13 | }
14 |
15 | public static class MergeOperators
16 | {
17 | ///
18 | /// This function performs merge(left_op, right_op)
19 | /// when both the operands are themselves merge operation types.
20 | /// Save the result in *new_value and return true. If it is impossible
21 | /// or infeasible to combine the two operations, return false instead.
22 | /// This is called to combine two-merge operands (if possible)
23 | ///
24 | /// The key that's associated with this merge operation
25 | ///
26 | /// the sequence of merge operations to apply, front() first
27 | ///
28 | ///
29 | /// Client is responsible for filling the merge result here
30 | ///
31 | ///
32 | public delegate IntPtr PartialMergeFunc(IntPtr key, UIntPtr keyLength, IntPtr operandsList, IntPtr operandsListLength, int numOperands, IntPtr success, IntPtr newValueLength);
33 | ///
34 | /// Gives the client a way to express the read -> modify -> write semantics.
35 | /// Called when a Put/Delete is the *existing_value (or nullptr)
36 | ///
37 | /// The key that's associated with this merge operation.
38 | ///
39 | /// null indicates that the key does not exist before this op
40 | ///
41 | /// the sequence of merge operations to apply, front() first.
42 | ///
43 | ///
44 | /// Client is responsible for filling the merge result here
45 | ///
46 | ///
47 | public delegate IntPtr FullMergeFunc(IntPtr key, UIntPtr keyLength, IntPtr existingValue, UIntPtr existingValueLength, IntPtr operandsList, IntPtr operandsListLength, int numOperands, IntPtr success, IntPtr newValueLength);
48 | public delegate void DeleteValueFunc(IntPtr value, UIntPtr valueLength);
49 |
50 | public static MergeOperator Create(
51 | string name,
52 | PartialMergeFunc partialMerge,
53 | FullMergeFunc fullMerge,
54 | DeleteValueFunc deleteValue)
55 | {
56 | return new MergeOperatorImpl(name, partialMerge, fullMerge, deleteValue);
57 | }
58 |
59 | private class MergeOperatorImpl : MergeOperator
60 | {
61 | public string Name { get; }
62 | private PartialMergeFunc PartialMerge { get; }
63 | private FullMergeFunc FullMerge { get; }
64 | private DeleteValueFunc DeleteValue { get; }
65 |
66 | public MergeOperatorImpl(string name, PartialMergeFunc partialMerge, FullMergeFunc fullMerge, DeleteValueFunc deleteValue)
67 | {
68 | Name = name;
69 | PartialMerge = partialMerge;
70 | FullMerge = fullMerge;
71 | DeleteValue = deleteValue;
72 | }
73 |
74 | IntPtr MergeOperator.PartialMerge(IntPtr key, UIntPtr keyLength, IntPtr operandsList, IntPtr operandsListLength, int numOperands, IntPtr success, IntPtr newValueLength)
75 | => PartialMerge(key, keyLength, operandsList, operandsListLength, numOperands, success, newValueLength);
76 |
77 | IntPtr MergeOperator.FullMerge(IntPtr key, UIntPtr keyLength, IntPtr existingValue, UIntPtr existingValueLength, IntPtr operandsList, IntPtr operandsListLength, int numOperands, IntPtr success, IntPtr newValueLength)
78 | => FullMerge(key, keyLength, existingValue, existingValueLength, operandsList, operandsListLength, numOperands, success, newValueLength);
79 |
80 | void MergeOperator.DeleteValue(IntPtr value, UIntPtr valueLength)
81 | => DeleteValue(value, valueLength);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/RocksDbSharp/Native.Load.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace RocksDbSharp
9 | {
10 | public abstract partial class Native
11 | {
12 | public static Native Instance;
13 |
14 | static Native()
15 | {
16 | if (RuntimeInformation.ProcessArchitecture == Architecture.X86 && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
17 | throw new RocksDbSharpException("Rocksdb on windows is not supported for 32 bit applications");
18 | Instance = NativeImport.Auto.Import("rocksdb", "6.2.2", true);
19 | }
20 |
21 | public Native()
22 | {
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/RocksDbSharp/Native.Wrap.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using System.Text;
5 | using size_t = System.UIntPtr;
6 |
7 | #pragma warning disable IDE1006 // Intentionally violating naming conventions because this is meant to match the C API
8 | namespace RocksDbSharp
9 | {
10 | /*
11 | These wrappers provide translation from the error output of the C API into exceptions
12 | */
13 | public abstract partial class Native
14 | {
15 | public void rocksdb_put(
16 | /*rocksdb_t**/ IntPtr db,
17 | /*const rocksdb_writeoptions_t**/ IntPtr writeOptions,
18 | string key,
19 | string val,
20 | ColumnFamilyHandle cf = null,
21 | System.Text.Encoding encoding = null)
22 | {
23 | rocksdb_put(db, writeOptions, key, val, out IntPtr errptr, cf, encoding);
24 | if (errptr != IntPtr.Zero)
25 | throw new RocksDbException(errptr);
26 | }
27 |
28 | public void rocksdb_put(
29 | IntPtr db,
30 | IntPtr writeOptions,
31 | byte[] key,
32 | long keyLength,
33 | byte[] value,
34 | long valueLength,
35 | ColumnFamilyHandle cf)
36 | {
37 | IntPtr errptr;
38 | UIntPtr sklength = (UIntPtr)keyLength;
39 | UIntPtr svlength = (UIntPtr)valueLength;
40 | if (cf == null)
41 | rocksdb_put(db, writeOptions, key, sklength, value, svlength, out errptr);
42 | else
43 | rocksdb_put_cf(db, writeOptions, cf.Handle, key, sklength, value, svlength, out errptr);
44 | if (errptr != IntPtr.Zero)
45 | throw new RocksDbException(errptr);
46 | }
47 |
48 |
49 | public string rocksdb_get(
50 | /*rocksdb_t**/ IntPtr db,
51 | /*const rocksdb_readoptions_t**/ IntPtr read_options,
52 | string key,
53 | ColumnFamilyHandle cf,
54 | System.Text.Encoding encoding = null)
55 | {
56 | var result = rocksdb_get(db, read_options, key, out IntPtr errptr, cf, encoding);
57 | if (errptr != IntPtr.Zero)
58 | throw new RocksDbException(errptr);
59 | return result;
60 | }
61 |
62 | public IntPtr rocksdb_get(
63 | IntPtr db,
64 | IntPtr read_options,
65 | byte[] key,
66 | long keyLength,
67 | out long vallen,
68 | ColumnFamilyHandle cf)
69 | {
70 | UIntPtr sklength = (UIntPtr)keyLength;
71 | var result = cf == null
72 | ? rocksdb_get(db, read_options, key, sklength, out UIntPtr valLength, out IntPtr errptr)
73 | : rocksdb_get_cf(db, read_options, cf.Handle, key, sklength, out valLength, out errptr);
74 | if (errptr != IntPtr.Zero)
75 | throw new RocksDbException(errptr);
76 | vallen = (long)valLength;
77 | return result;
78 | }
79 |
80 | public byte[] rocksdb_get(
81 | IntPtr db,
82 | IntPtr read_options,
83 | byte[] key,
84 | long keyLength = 0,
85 | ColumnFamilyHandle cf = null)
86 | {
87 | var result = rocksdb_get(db, read_options, key, keyLength == 0 ? key.Length : keyLength, out IntPtr errptr, cf);
88 | if (errptr != IntPtr.Zero)
89 | throw new RocksDbException(errptr);
90 | return result;
91 | }
92 |
93 | public System.Collections.Generic.KeyValuePair[] rocksdb_multi_get(
94 | IntPtr db,
95 | IntPtr read_options,
96 | string[] keys,
97 | ColumnFamilyHandle[] cf = null,
98 | System.Text.Encoding encoding = null)
99 | {
100 | if (encoding == null)
101 | encoding = System.Text.Encoding.UTF8;
102 | IntPtr[] errptrs = new IntPtr[keys.Length];
103 | var result = rocksdb_multi_get(db, read_options, keys, cf: cf, errptrs: errptrs, encoding: encoding);
104 | foreach (var errptr in errptrs)
105 | if (errptr != IntPtr.Zero)
106 | throw new RocksDbException(errptr);
107 | return result;
108 | }
109 |
110 |
111 | public System.Collections.Generic.KeyValuePair[] rocksdb_multi_get(
112 | IntPtr db,
113 | IntPtr read_options,
114 | byte[][] keys,
115 | ulong[] keyLengths = null,
116 | ColumnFamilyHandle[] cf = null)
117 | {
118 | IntPtr[] errptrs = new IntPtr[keys.Length];
119 | var result = rocksdb_multi_get(db, read_options, keys, keyLengths: keyLengths, cf: cf, errptrs: errptrs);
120 | foreach (var errptr in errptrs)
121 | if (errptr != IntPtr.Zero)
122 | throw new RocksDbException(errptr);
123 | return result;
124 | }
125 |
126 | public void rocksdb_delete(
127 | /*rocksdb_t**/ IntPtr db,
128 | /*const rocksdb_writeoptions_t**/ IntPtr writeOptions,
129 | /*const*/ string key,
130 | ColumnFamilyHandle cf)
131 | {
132 | rocksdb_delete(db, writeOptions, key, out IntPtr errptr, cf);
133 | if (errptr != IntPtr.Zero)
134 | throw new RocksDbException(errptr);
135 | }
136 |
137 | [Obsolete("Use UIntPtr version instead")]
138 | public void rocksdb_delete(
139 | /*rocksdb_t**/ IntPtr db,
140 | /*const rocksdb_writeoptions_t**/ IntPtr writeOptions,
141 | /*const*/ byte[] key,
142 | long keylen)
143 | {
144 | UIntPtr sklength = (UIntPtr)keylen;
145 | rocksdb_delete(db, writeOptions, key, sklength, out IntPtr errptr);
146 | if (errptr != IntPtr.Zero)
147 | throw new RocksDbException(errptr);
148 | }
149 |
150 | [Obsolete("Use UIntPtr version instead")]
151 | public void rocksdb_delete_cf(
152 | /*rocksdb_t**/ IntPtr db,
153 | /*const rocksdb_writeoptions_t**/ IntPtr writeOptions,
154 | /*const*/ byte[] key,
155 | long keylen,
156 | ColumnFamilyHandle cf)
157 | {
158 | rocksdb_delete_cf(db, writeOptions, cf.Handle, key, (UIntPtr)keylen, out IntPtr errptr);
159 | if (errptr != IntPtr.Zero)
160 | throw new RocksDbException(errptr);
161 | }
162 |
163 | [Obsolete("Use UIntPtr version instead")]
164 | public void rocksdb_ingest_external_file(IntPtr db, string[] file_list, ulong list_len, IntPtr opt)
165 | {
166 | UIntPtr llen = (UIntPtr)list_len;
167 | rocksdb_ingest_external_file(db, file_list, llen, opt, out IntPtr errptr);
168 | if (errptr != IntPtr.Zero)
169 | throw new RocksDbException(errptr);
170 | }
171 |
172 | [Obsolete("Use UIntPtr version instead")]
173 | public void rocksdb_ingest_external_file_cf(IntPtr db, IntPtr handle, string[] file_list, ulong list_len, IntPtr opt)
174 | {
175 | UIntPtr llen = (UIntPtr)list_len;
176 | rocksdb_ingest_external_file_cf(db, handle, file_list, llen, opt, out IntPtr errptr);
177 | if (errptr != IntPtr.Zero)
178 | throw new RocksDbException(errptr);
179 | }
180 |
181 | [Obsolete("Use UIntPtr version instead")]
182 | public void rocksdb_sstfilewriter_add(
183 | IntPtr writer,
184 | byte[] key,
185 | ulong keylen,
186 | byte[] val,
187 | ulong vallen)
188 | {
189 | UIntPtr sklength = (UIntPtr)keylen;
190 | UIntPtr svlength = (UIntPtr)vallen;
191 | rocksdb_sstfilewriter_add(writer, key, sklength, val, svlength, out IntPtr errptr);
192 | if (errptr != IntPtr.Zero)
193 | throw new RocksDbException(errptr);
194 | }
195 |
196 | public unsafe void rocksdb_sstfilewriter_add(
197 | IntPtr writer,
198 | string key,
199 | string val)
200 | {
201 | rocksdb_sstfilewriter_add(writer, key, val, out IntPtr errptr);
202 | if (errptr != IntPtr.Zero)
203 | throw new RocksDbException(errptr);
204 | }
205 |
206 | public string rocksdb_writebatch_wi_get_from_batch(
207 | IntPtr wb,
208 | IntPtr options,
209 | string key,
210 | ColumnFamilyHandle cf,
211 | System.Text.Encoding encoding = null)
212 | {
213 | var result = rocksdb_writebatch_wi_get_from_batch(wb, options, key, out IntPtr errptr, cf, encoding);
214 | if (errptr != IntPtr.Zero)
215 | throw new RocksDbException(errptr);
216 | return result;
217 | }
218 |
219 | public IntPtr rocksdb_writebatch_wi_get_from_batch(
220 | IntPtr wb,
221 | IntPtr options,
222 | byte[] key,
223 | ulong keyLength,
224 | out ulong vallen,
225 | ColumnFamilyHandle cf)
226 | {
227 | UIntPtr sklength = (UIntPtr)keyLength;
228 | var result = cf == null
229 | ? rocksdb_writebatch_wi_get_from_batch(wb, options, key, sklength, out UIntPtr valLength, out IntPtr errptr)
230 | : rocksdb_writebatch_wi_get_from_batch_cf(wb, options, cf.Handle, key, sklength, out valLength, out errptr);
231 | if (errptr != IntPtr.Zero)
232 | throw new RocksDbException(errptr);
233 | vallen = (ulong)valLength;
234 | return result;
235 | }
236 |
237 | public byte[] rocksdb_writebatch_wi_get_from_batch(
238 | IntPtr wb,
239 | IntPtr options,
240 | byte[] key,
241 | ulong keyLength = 0,
242 | ColumnFamilyHandle cf = null)
243 | {
244 | var result = rocksdb_writebatch_wi_get_from_batch(wb, options, key, keyLength == 0 ? (ulong)key.Length : keyLength, out IntPtr errptr, cf);
245 | if (errptr != IntPtr.Zero)
246 | throw new RocksDbException(errptr);
247 | return result;
248 | }
249 |
250 | public string rocksdb_writebatch_wi_get_from_batch_and_db(
251 | IntPtr wb,
252 | IntPtr db,
253 | IntPtr read_options,
254 | string key,
255 | ColumnFamilyHandle cf,
256 | System.Text.Encoding encoding = null)
257 | {
258 | var result = rocksdb_writebatch_wi_get_from_batch_and_db(wb, db, read_options, key, out IntPtr errptr, cf, encoding);
259 | if (errptr != IntPtr.Zero)
260 | throw new RocksDbException(errptr);
261 | return result;
262 | }
263 |
264 | public IntPtr rocksdb_writebatch_wi_get_from_batch_and_db(
265 | IntPtr wb,
266 | IntPtr db,
267 | IntPtr read_options,
268 | byte[] key,
269 | ulong keyLength,
270 | out ulong vallen,
271 | ColumnFamilyHandle cf)
272 | {
273 | UIntPtr sklength = (UIntPtr)keyLength;
274 | var result = cf == null
275 | ? rocksdb_writebatch_wi_get_from_batch_and_db(wb, db, read_options, key, sklength, out UIntPtr valLength, out IntPtr errptr)
276 | : rocksdb_writebatch_wi_get_from_batch_and_db_cf(wb, db, read_options, cf.Handle, key, sklength, out valLength, out errptr);
277 | if (errptr != IntPtr.Zero)
278 | throw new RocksDbException(errptr);
279 | vallen = (ulong)valLength;
280 | return result;
281 | }
282 |
283 | public byte[] rocksdb_writebatch_wi_get_from_batch_and_db(
284 | IntPtr wb,
285 | IntPtr db,
286 | IntPtr read_options,
287 | byte[] key,
288 | ulong keyLength = 0,
289 | ColumnFamilyHandle cf = null)
290 | {
291 | var result = rocksdb_writebatch_wi_get_from_batch_and_db(wb, db, read_options, key, keyLength == 0 ? (ulong)key.Length : keyLength, out IntPtr errptr, cf);
292 | if (errptr != IntPtr.Zero)
293 | throw new RocksDbException(errptr);
294 | return result;
295 | }
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/RocksDbSharp/Options.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Dynamic;
3 |
4 | namespace RocksDbSharp
5 | {
6 | /*
7 | Configure options for a RocksDb store.
8 |
9 | Note on SetXXX() syntax:
10 | Why not syntax like new Options { XXX = ... } instead? Two reasons
11 | 1. The rocksdb C API does not support reading the options and so a class with properties is not an appropriate representation
12 | 2. The API functions are named as imperatives and don't always begin with "set" so one like "OptimizeLevelStyleCompaction" wouldn't work right
13 | */
14 | public abstract class OptionsHandle
15 | {
16 | // The following exists only to retain a reference to those types which are used in-place by rocksdb
17 | // and not copied (or reference things that are used in-place). The idea is to have managed references
18 | // track the behavior of the unmanaged reference as much as possible. This prevents access violations
19 | // when the garbage collector cleans up the last managed reference
20 | internal dynamic References { get; } = new ExpandoObject();
21 |
22 | public IntPtr Handle { get; private set; }
23 |
24 | public OptionsHandle()
25 | {
26 | this.Handle = Native.Instance.rocksdb_options_create();
27 | }
28 |
29 | ~OptionsHandle()
30 | {
31 | if (Handle != IntPtr.Zero)
32 | {
33 | #if !NODESTROY
34 | Native.Instance.rocksdb_options_destroy(Handle);
35 | #endif
36 | Handle = IntPtr.Zero;
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/RocksDbSharp/ReadOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Transitional;
8 |
9 | namespace RocksDbSharp
10 | {
11 | public class ReadOptions
12 | {
13 | private IntPtr iterateUpperBound;
14 |
15 | public ReadOptions()
16 | {
17 | Handle = Native.Instance.rocksdb_readoptions_create();
18 | }
19 |
20 | public IntPtr Handle { get; protected set; }
21 |
22 | ~ReadOptions()
23 | {
24 | if (Handle != IntPtr.Zero)
25 | {
26 | #if !NODESTROY
27 | Native.Instance.rocksdb_readoptions_destroy(Handle);
28 | if (iterateUpperBound != IntPtr.Zero)
29 | Marshal.FreeHGlobal(iterateUpperBound);
30 | #endif
31 | Handle = IntPtr.Zero;
32 | }
33 | }
34 |
35 | public ReadOptions SetVerifyChecksums(bool value)
36 | {
37 | Native.Instance.rocksdb_readoptions_set_verify_checksums(Handle, value);
38 | return this;
39 | }
40 |
41 | public ReadOptions SetFillCache(bool value)
42 | {
43 | Native.Instance.rocksdb_readoptions_set_fill_cache(Handle, value);
44 | return this;
45 | }
46 |
47 | public ReadOptions SetSnapshot(Snapshot snapshot)
48 | {
49 | Native.Instance.rocksdb_readoptions_set_snapshot(Handle, snapshot.Handle);
50 | return this;
51 | }
52 |
53 | ///
54 | /// Enforce that the iterator only iterates over the same prefix as the seek.
55 | /// This option is effective only for prefix seeks, i.e. prefix_extractor is
56 | /// non-null for the column family and total_order_seek is false. Unlike
57 | /// iterate_upper_bound, prefix_same_as_start only works within a prefix
58 | /// but in both directions.
59 | /// Default: false
60 | ///
61 | ///
62 | ///
63 | public ReadOptions SetPrefixSameAsStart(bool prefixSameAsStart)
64 | {
65 | Native.Instance.rocksdb_readoptions_set_prefix_same_as_start(Handle, prefixSameAsStart);
66 | return this;
67 | }
68 |
69 | public unsafe ReadOptions SetIterateUpperBound(byte* key, ulong keylen)
70 | {
71 | UIntPtr klen = (UIntPtr)keylen;
72 | Native.Instance.rocksdb_readoptions_set_iterate_upper_bound(Handle, key, klen);
73 | return this;
74 | }
75 |
76 | public ReadOptions SetIterateUpperBound(byte[] key, ulong keyLen)
77 | {
78 | if (iterateUpperBound != IntPtr.Zero)
79 | Marshal.FreeHGlobal(iterateUpperBound);
80 | iterateUpperBound = Marshal.AllocHGlobal(key.Length);
81 | Marshal.Copy(key, 0, iterateUpperBound, key.Length);
82 | UIntPtr klen = (UIntPtr)keyLen;
83 | Native.Instance.rocksdb_readoptions_set_iterate_upper_bound(Handle, iterateUpperBound, klen);
84 | return this;
85 | }
86 |
87 | public ReadOptions SetIterateUpperBound(byte[] key)
88 | {
89 | return SetIterateUpperBound(key, (ulong)key.GetLongLength(0));
90 | }
91 |
92 | public unsafe ReadOptions SetIterateUpperBound(string stringKey, Encoding encoding = null)
93 | {
94 | var key = (encoding ?? Encoding.UTF8).GetBytes(stringKey);
95 | return SetIterateUpperBound(key);
96 | }
97 |
98 | public ReadOptions SetReadTier(int value)
99 | {
100 | Native.Instance.rocksdb_readoptions_set_read_tier(Handle, value);
101 | return this;
102 | }
103 |
104 | public ReadOptions SetTailing(bool value)
105 | {
106 | Native.Instance.rocksdb_readoptions_set_tailing(Handle, value);
107 | return this;
108 | }
109 |
110 | public ReadOptions SetReadaheadSize(ulong size)
111 | {
112 | UIntPtr readaheadSize = (UIntPtr)size;
113 | Native.Instance.rocksdb_readoptions_set_readahead_size(Handle, readaheadSize);
114 | return this;
115 | }
116 |
117 | public ReadOptions SetPinData(bool enable)
118 | {
119 | Native.Instance.rocksdb_readoptions_set_pin_data(Handle, enable);
120 | return this;
121 | }
122 |
123 | public ReadOptions SetTotalOrderSeek(bool enable)
124 | {
125 | Native.Instance.rocksdb_readoptions_set_total_order_seek(Handle, enable);
126 | return this;
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/RocksDbSharp/RocksDb.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Dynamic;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using Transitional;
8 |
9 | namespace RocksDbSharp
10 | {
11 | public class RocksDb : IDisposable
12 | {
13 | internal static ReadOptions DefaultReadOptions { get; } = new ReadOptions();
14 | internal static OptionsHandle DefaultOptions { get; } = new DbOptions();
15 | internal static WriteOptions DefaultWriteOptions { get; } = new WriteOptions();
16 | internal static Encoding DefaultEncoding => Encoding.UTF8;
17 | private Dictionary columnFamilies;
18 |
19 | // Managed references to unmanaged resources that need to live at least as long as the db
20 | internal dynamic References { get; } = new ExpandoObject();
21 |
22 | public IntPtr Handle { get; protected set; }
23 |
24 | private RocksDb(IntPtr handle, dynamic optionsReferences, dynamic cfOptionsRefs, Dictionary columnFamilies = null)
25 | {
26 | this.Handle = handle;
27 | References.Options = optionsReferences;
28 | References.CfOptions = cfOptionsRefs;
29 | this.columnFamilies = columnFamilies;
30 | }
31 |
32 | public void Dispose()
33 | {
34 | if (columnFamilies != null)
35 | {
36 | foreach (var cfh in columnFamilies.Values)
37 | cfh.Dispose();
38 | }
39 | Native.Instance.rocksdb_close(Handle);
40 | }
41 |
42 | public static RocksDb Open(OptionsHandle options, string path)
43 | {
44 | IntPtr db = Native.Instance.rocksdb_open(options.Handle, path);
45 | return new RocksDb(db, optionsReferences: null, cfOptionsRefs: null);
46 | }
47 |
48 | public static RocksDb OpenReadOnly(OptionsHandle options, string path, bool errorIfLogFileExists)
49 | {
50 | IntPtr db = Native.Instance.rocksdb_open_for_read_only(options.Handle, path, errorIfLogFileExists);
51 | return new RocksDb(db, optionsReferences: null, cfOptionsRefs: null);
52 | }
53 |
54 | public static RocksDb OpenWithTtl(OptionsHandle options, string path, int ttlSeconds)
55 | {
56 | IntPtr db = Native.Instance.rocksdb_open_with_ttl(options.Handle, path, ttlSeconds);
57 | return new RocksDb(db, optionsReferences: null, cfOptionsRefs: null);
58 | }
59 |
60 | public static RocksDb Open(DbOptions options, string path, ColumnFamilies columnFamilies)
61 | {
62 | string[] cfnames = columnFamilies.Names.ToArray();
63 | IntPtr[] cfoptions = columnFamilies.OptionHandles.ToArray();
64 | IntPtr[] cfhandles = new IntPtr[cfnames.Length];
65 | IntPtr db = Native.Instance.rocksdb_open_column_families(options.Handle, path, cfnames.Length, cfnames, cfoptions, cfhandles);
66 | var cfHandleMap = new Dictionary();
67 | foreach (var pair in cfnames.Zip(cfhandles.Select(cfh => new ColumnFamilyHandleInternal(cfh)), (name, cfh) => new { Name = name, Handle = cfh }))
68 | cfHandleMap.Add(pair.Name, pair.Handle);
69 | return new RocksDb(db,
70 | optionsReferences: options.References,
71 | cfOptionsRefs: columnFamilies.Select(cfd => cfd.Options.References).ToArray(),
72 | columnFamilies: cfHandleMap);
73 | }
74 |
75 | public static RocksDb OpenReadOnly(DbOptions options, string path, ColumnFamilies columnFamilies, bool errIfLogFileExists)
76 | {
77 | string[] cfnames = columnFamilies.Names.ToArray();
78 | IntPtr[] cfoptions = columnFamilies.OptionHandles.ToArray();
79 | IntPtr[] cfhandles = new IntPtr[cfnames.Length];
80 | IntPtr db = Native.Instance.rocksdb_open_for_read_only_column_families(options.Handle, path, cfnames.Length, cfnames, cfoptions, cfhandles, errIfLogFileExists);
81 | var cfHandleMap = new Dictionary();
82 | foreach (var pair in cfnames.Zip(cfhandles.Select(cfh => new ColumnFamilyHandleInternal(cfh)), (name, cfh) => new { Name = name, Handle = cfh }))
83 | cfHandleMap.Add(pair.Name, pair.Handle);
84 | return new RocksDb(db,
85 | optionsReferences: options.References,
86 | cfOptionsRefs: columnFamilies.Select(cfd => cfd.Options.References).ToArray(),
87 | columnFamilies: cfHandleMap);
88 | }
89 |
90 | ///
91 | /// Usage:
92 | ///
98 | ///
99 | ///
100 | public Checkpoint Checkpoint()
101 | {
102 | var checkpoint = Native.Instance.rocksdb_checkpoint_object_create(Handle);
103 | return new Checkpoint(checkpoint);
104 | }
105 |
106 | public void SetOptions(IEnumerable> options)
107 | {
108 | var keys = options.Select(e => e.Key).ToArray();
109 | var values = options.Select(e => e.Value).ToArray();
110 | Native.Instance.rocksdb_set_options(Handle, keys.Length, keys, values);
111 | }
112 |
113 | public string Get(string key, ColumnFamilyHandle cf = null, ReadOptions readOptions = null, Encoding encoding = null)
114 | {
115 | return Native.Instance.rocksdb_get(Handle, (readOptions ?? DefaultReadOptions).Handle, key, cf, encoding ?? DefaultEncoding);
116 | }
117 |
118 | public byte[] Get(byte[] key, ColumnFamilyHandle cf = null, ReadOptions readOptions = null)
119 | {
120 | return Get(key, key.GetLongLength(0), cf, readOptions);
121 | }
122 |
123 | public byte[] Get(byte[] key, long keyLength, ColumnFamilyHandle cf = null, ReadOptions readOptions = null)
124 | {
125 | return Native.Instance.rocksdb_get(Handle, (readOptions ?? DefaultReadOptions).Handle, key, keyLength, cf);
126 | }
127 |
128 | ///
129 | /// Reads the contents of the database value associated with , if present, into the supplied
130 | /// at up to bytes, returning the
131 | /// length of the value in the database, or -1 if the key is not present.
132 | ///
133 | ///
134 | ///
135 | ///
136 | ///
137 | ///
138 | ///
139 | /// The actual length of the database field if it exists, otherwise -1
140 | public long Get(byte[] key, byte[] buffer, long offset, long length, ColumnFamilyHandle cf = null, ReadOptions readOptions = null)
141 | {
142 | return Get(key, key.GetLongLength(0), buffer, offset, length, cf, readOptions);
143 | }
144 |
145 | ///
146 | /// Reads the contents of the database value associated with , if present, into the supplied
147 | /// at up to bytes, returning the
148 | /// length of the value in the database, or -1 if the key is not present.
149 | ///
150 | ///
151 | ///
152 | ///
153 | ///
154 | ///
155 | ///
156 | /// The actual length of the database field if it exists, otherwise -1
157 | public long Get(byte[] key, long keyLength, byte[] buffer, long offset, long length, ColumnFamilyHandle cf = null, ReadOptions readOptions = null)
158 | {
159 | unsafe
160 | {
161 | var ptr = Native.Instance.rocksdb_get(Handle, (readOptions ?? DefaultReadOptions).Handle, key, keyLength, out long valLength, cf);
162 | if (ptr == IntPtr.Zero)
163 | return -1;
164 | var copyLength = Math.Min(length, valLength);
165 | Marshal.Copy(ptr, buffer, (int)offset, (int)copyLength);
166 | Native.Instance.rocksdb_free(ptr);
167 | return valLength;
168 | }
169 | }
170 |
171 | public KeyValuePair[] MultiGet(byte[][] keys, ColumnFamilyHandle[] cf = null, ReadOptions readOptions = null)
172 | {
173 | return Native.Instance.rocksdb_multi_get(Handle, (readOptions ?? DefaultReadOptions).Handle, keys);
174 | }
175 |
176 | public KeyValuePair[] MultiGet(string[] keys, ColumnFamilyHandle[] cf = null, ReadOptions readOptions = null)
177 | {
178 | return Native.Instance.rocksdb_multi_get(Handle, (readOptions ?? DefaultReadOptions).Handle, keys);
179 | }
180 |
181 | public void Write(WriteBatch writeBatch, WriteOptions writeOptions = null)
182 | {
183 | Native.Instance.rocksdb_write(Handle, (writeOptions ?? DefaultWriteOptions).Handle, writeBatch.Handle);
184 | }
185 |
186 | public void Write(WriteBatchWithIndex writeBatch, WriteOptions writeOptions = null)
187 | {
188 | Native.Instance.rocksdb_write_writebatch_wi(Handle, (writeOptions ?? DefaultWriteOptions).Handle, writeBatch.Handle);
189 | }
190 |
191 | public void Remove(string key, ColumnFamilyHandle cf = null, WriteOptions writeOptions = null)
192 | {
193 | Native.Instance.rocksdb_delete(Handle, (writeOptions ?? DefaultWriteOptions).Handle, key, cf);
194 | }
195 |
196 | public void Remove(byte[] key, ColumnFamilyHandle cf = null, WriteOptions writeOptions = null)
197 | {
198 | Remove(key, key.Length, cf, writeOptions);
199 | }
200 |
201 | public void Remove(byte[] key, long keyLength, ColumnFamilyHandle cf = null, WriteOptions writeOptions = null)
202 | {
203 | if (cf == null)
204 | Native.Instance.rocksdb_delete(Handle, (writeOptions ?? DefaultWriteOptions).Handle, key, (UIntPtr)keyLength);
205 | else
206 | Native.Instance.rocksdb_delete_cf(Handle, (writeOptions ?? DefaultWriteOptions).Handle, cf.Handle, key, (UIntPtr)keyLength);
207 | }
208 |
209 | public void Put(string key, string value, ColumnFamilyHandle cf = null, WriteOptions writeOptions = null, Encoding encoding = null)
210 | {
211 | Native.Instance.rocksdb_put(Handle, (writeOptions ?? DefaultWriteOptions).Handle, key, value, cf, encoding ?? DefaultEncoding);
212 | }
213 |
214 | public void Put(byte[] key, byte[] value, ColumnFamilyHandle cf = null, WriteOptions writeOptions = null)
215 | {
216 | Put(key, key.GetLongLength(0), value, value.GetLongLength(0), cf, writeOptions);
217 | }
218 |
219 | public void Put(byte[] key, long keyLength, byte[] value, long valueLength, ColumnFamilyHandle cf = null, WriteOptions writeOptions = null)
220 | {
221 | Native.Instance.rocksdb_put(Handle, (writeOptions ?? DefaultWriteOptions).Handle, key, keyLength, value, valueLength, cf);
222 | }
223 |
224 | public Iterator NewIterator(ColumnFamilyHandle cf = null, ReadOptions readOptions = null)
225 | {
226 | IntPtr iteratorHandle = cf == null
227 | ? Native.Instance.rocksdb_create_iterator(Handle, (readOptions ?? DefaultReadOptions).Handle)
228 | : Native.Instance.rocksdb_create_iterator_cf(Handle, (readOptions ?? DefaultReadOptions).Handle, cf.Handle);
229 | // Note: passing in read options here only to ensure that it is not collected before the iterator
230 | return new Iterator(iteratorHandle, readOptions);
231 | }
232 |
233 | public Iterator[] NewIterators(ColumnFamilyHandle[] cfs, ReadOptions[] readOptions)
234 | {
235 | throw new NotImplementedException("TODO: Implement NewIterators()");
236 | // See rocksdb_create_iterators
237 | }
238 |
239 | public Snapshot CreateSnapshot()
240 | {
241 | IntPtr snapshotHandle = Native.Instance.rocksdb_create_snapshot(Handle);
242 | return new Snapshot(Handle, snapshotHandle);
243 | }
244 |
245 | public static IEnumerable ListColumnFamilies(DbOptions options, string name)
246 | {
247 | return Native.Instance.rocksdb_list_column_families(options.Handle, name);
248 | }
249 |
250 | public ColumnFamilyHandle CreateColumnFamily(ColumnFamilyOptions cfOptions, string name)
251 | {
252 | var cfh = Native.Instance.rocksdb_create_column_family(Handle, cfOptions.Handle, name);
253 | var cfhw = new ColumnFamilyHandleInternal(cfh);
254 | columnFamilies.Add(name, cfhw);
255 | return cfhw;
256 | }
257 |
258 | public void DropColumnFamily(string name)
259 | {
260 | var cf = GetColumnFamily(name);
261 | Native.Instance.rocksdb_drop_column_family(Handle, cf.Handle);
262 | columnFamilies.Remove(name);
263 | }
264 |
265 | public ColumnFamilyHandle GetDefaultColumnFamily()
266 | {
267 | return GetColumnFamily(ColumnFamilies.DefaultName);
268 | }
269 |
270 | public ColumnFamilyHandle GetColumnFamily(string name)
271 | {
272 | if (columnFamilies == null)
273 | throw new RocksDbSharpException("Database not opened for column families");
274 | return columnFamilies[name];
275 | }
276 |
277 | public string GetProperty(string propertyName)
278 | {
279 | return Native.Instance.rocksdb_property_value_string(Handle, propertyName);
280 | }
281 |
282 | public string GetProperty(string propertyName, ColumnFamilyHandle cf)
283 | {
284 | return Native.Instance.rocksdb_property_value_cf_string(Handle, cf.Handle, propertyName);
285 | }
286 |
287 | public void IngestExternalFiles(string[] files, IngestExternalFileOptions ingestOptions, ColumnFamilyHandle cf = null)
288 | {
289 | if (cf == null)
290 | Native.Instance.rocksdb_ingest_external_file(Handle, files, (UIntPtr)files.GetLongLength(0), ingestOptions.Handle);
291 | else
292 | Native.Instance.rocksdb_ingest_external_file_cf(Handle, cf.Handle, files, (UIntPtr)files.GetLongLength(0), ingestOptions.Handle);
293 | }
294 |
295 | public void CompactRange(byte[] start, byte[] limit, ColumnFamilyHandle cf = null)
296 | {
297 | if (cf == null)
298 | Native.Instance.rocksdb_compact_range(Handle, start, (UIntPtr)(start?.GetLongLength(0) ?? 0L), limit, (UIntPtr)(limit?.GetLongLength(0) ?? 0L));
299 | else
300 | Native.Instance.rocksdb_compact_range_cf(Handle, cf.Handle, start, (UIntPtr)(start?.GetLongLength(0) ?? 0L), limit, (UIntPtr)(limit?.GetLongLength(0) ?? 0L));
301 | }
302 |
303 | public void CompactRange(string start, string limit, ColumnFamilyHandle cf = null, Encoding encoding = null)
304 | {
305 | if (encoding == null)
306 | encoding = Encoding.UTF8;
307 | CompactRange(start == null ? null : encoding.GetBytes(start), limit == null ? null : encoding.GetBytes(limit), cf);
308 | }
309 | }
310 | }
311 |
--------------------------------------------------------------------------------
/RocksDbSharp/RocksDbException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace RocksDbSharp
5 | {
6 | public class RocksDbException : RocksDbSharpException
7 | {
8 | public RocksDbException(IntPtr errptr)
9 | : base(Marshal.PtrToStringAnsi(errptr))
10 | {
11 | Native.Instance.rocksdb_free(errptr);
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/RocksDbSharp/RocksDbSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | RocksDbSharp
5 | netstandard1.6;net40;net45
6 | True
7 | $(RocksDbVersion).$(RocksDbSharpBuild)
8 | $(Version)
9 | $(Version)
10 | .Net Bindings for RocksDb. See the Project Site for more information. (Note: Also install RocksDbNative package to have native binaries included with build)
11 | Warren Falk
12 | Warren Falk
13 | Warren Falk
14 | BSD-2-Clause
15 | https://github.com/warrenfalk/rocksdb-sharp
16 | http://rocksdb.org/static/logo.svg
17 | https://github.com/warrenfalk/rocksdb-sharp.git
18 | rocksdb leveldb embedded database
19 | Copyright 2016
20 | .Net Bindings for RocksDb. See the Project Site for more information. (Note: Also install RocksDbNative package to have native binaries included with build)
21 | False
22 |
23 |
24 |
25 |
26 |
27 |
28 | TRACE;DEBUG
29 |
30 |
31 |
32 | TRACE
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/RocksDbSharp/RocksDbSharpException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace RocksDbSharp
5 | {
6 | public class RocksDbSharpException : Exception
7 | {
8 | public RocksDbSharpException(string message)
9 | : base(message)
10 | {
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/RocksDbSharp/SliceTransform.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace RocksDbSharp
4 | {
5 | public class SliceTransform
6 | {
7 | public IntPtr Handle { get; protected set; }
8 |
9 | private SliceTransform(IntPtr handle)
10 | {
11 | this.Handle = handle;
12 | }
13 |
14 | public static SliceTransform CreateFixedPrefix(/*(size_t)*/ ulong fixed_prefix_length)
15 | {
16 | UIntPtr fixedPrefix = (UIntPtr)fixed_prefix_length;
17 | IntPtr handle = Native.Instance.rocksdb_slicetransform_create_fixed_prefix(fixedPrefix);
18 | return new SliceTransform(handle);
19 | }
20 |
21 | public static SliceTransform CreateNoOp()
22 | {
23 | IntPtr handle = Native.Instance.rocksdb_slicetransform_create_noop();
24 | return new SliceTransform(handle);
25 | }
26 |
27 | ~SliceTransform()
28 | {
29 | if (Handle != IntPtr.Zero)
30 | {
31 | #if !NODESTROY
32 | // Commented out until a solution is found to rocksdb issue #1095 (https://github.com/facebook/rocksdb/issues/1095)
33 | // If you create one of these, use it in an Option which will destroy it when finished
34 | // Otherwise don't create one or it will leak
35 | //Native.Instance.rocksdb_slicetransform_destroy(Handle);
36 | #endif
37 | Handle = IntPtr.Zero;
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/RocksDbSharp/Snapshot.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RocksDbSharp
8 | {
9 | ///
10 | /// A Snapshot is an immutable object and can therefore be safely
11 | /// accessed from multiple threads without any external synchronization.
12 | ///
13 | public class Snapshot : IDisposable
14 | {
15 | private IntPtr dbHandle;
16 | public IntPtr Handle { get; private set; }
17 |
18 | internal Snapshot(IntPtr dbHandle, IntPtr snapshotHandle)
19 | {
20 | this.dbHandle = dbHandle;
21 | Handle = snapshotHandle;
22 | }
23 |
24 | public void Dispose()
25 | {
26 | if (Handle != IntPtr.Zero)
27 | {
28 | #if !NODESTROY
29 | Native.Instance.rocksdb_release_snapshot(dbHandle, Handle);
30 | #endif
31 | Handle = IntPtr.Zero;
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/RocksDbSharp/SstFileWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Dynamic;
4 | using System.Text;
5 | using Transitional;
6 |
7 | namespace RocksDbSharp
8 | {
9 | public class SstFileWriter : IDisposable
10 | {
11 | public IntPtr Handle { get; protected set; }
12 |
13 | internal dynamic References { get; } = new ExpandoObject();
14 |
15 | public SstFileWriter(EnvOptions envOptions = null, ColumnFamilyOptions ioOptions = null)
16 | {
17 | if (envOptions == null)
18 | envOptions = new EnvOptions();
19 | var opts = ioOptions ?? new ColumnFamilyOptions();
20 | References.EnvOptions = envOptions;
21 | References.IoOptions = ioOptions;
22 | Handle = Native.Instance.rocksdb_sstfilewriter_create(envOptions.Handle, opts.Handle);
23 | }
24 |
25 | public void Dispose()
26 | {
27 | if (Handle != IntPtr.Zero)
28 | {
29 | var handle = Handle;
30 | Handle = IntPtr.Zero;
31 | Native.Instance.rocksdb_sstfilewriter_destroy(handle);
32 | }
33 | }
34 |
35 | public void Open(string filename)
36 | {
37 | Native.Instance.rocksdb_sstfilewriter_open(Handle, filename);
38 | }
39 |
40 | public void Add(string key, string val)
41 | {
42 | Native.Instance.rocksdb_sstfilewriter_add(Handle, key, val);
43 | }
44 |
45 | public void Add(byte[] key, byte[] val)
46 | {
47 | Native.Instance.rocksdb_sstfilewriter_add(Handle, key, (UIntPtr)key.GetLongLength(0), val, (UIntPtr)val.GetLongLength(0));
48 | }
49 |
50 | public void Finish()
51 | {
52 | Native.Instance.rocksdb_sstfilewriter_finish(Handle);
53 | }
54 |
55 | public void Put(byte[] key, byte[] val)
56 | {
57 | Native.Instance.rocksdb_sstfilewriter_put(Handle, key, (UIntPtr)key.Length, val, (UIntPtr)val.Length);
58 | }
59 |
60 | public void Merge(byte[] key, byte[] val)
61 | {
62 | Native.Instance.rocksdb_sstfilewriter_merge(Handle, key, (UIntPtr)key.Length, val, (UIntPtr)val.Length);
63 | }
64 |
65 | public void Delete(byte[] key)
66 | {
67 | Native.Instance.rocksdb_sstfilewriter_delete(Handle, key, (UIntPtr)key.Length);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/RocksDbSharp/Transitional.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Reflection.Emit;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 |
7 | ///
8 | /// The purpose of this file is to ease the transition from framework to framework.
9 | /// As much as possible, in this shared code project, we'll try to use .Net Core compatible code
10 | /// And then add code here to make that work.
11 | /// When not possible, we'll create our own wrapper functions and then create different implementations
12 | /// based on preprocessor defines
13 | ///
14 |
15 | #if NET40
16 | namespace System
17 | {
18 | ///
19 | /// Shim in the new TypeInfo API as just a reference back to Type
20 | ///
21 | internal class TypeInfo
22 | {
23 | private Type Type { get; }
24 |
25 | internal TypeInfo(Type type)
26 | {
27 | Type = type;
28 | }
29 |
30 | internal MethodInfo GetMethod(string name) => Type.GetMethod(name);
31 |
32 | internal MethodInfo GetMethod(string name, BindingFlags flags) => Type.GetMethod(name, flags);
33 |
34 | internal MethodInfo[] GetMethods(BindingFlags bindingFlags) => Type.GetMethods(bindingFlags);
35 |
36 | public Type AsType() => Type;
37 |
38 | public ConstructorInfo[] GetConstructors() => Type.GetConstructors();
39 |
40 | public ConstructorInfo GetConstructor(Type[] args) => Type.GetConstructor(args);
41 |
42 | public Assembly Assembly => Type.Assembly;
43 | }
44 | }
45 | #endif
46 |
47 | namespace Transitional
48 | {
49 | internal static class CurrentFramework
50 | {
51 | public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access)
52 | #if NET40
53 | => AppDomain.CurrentDomain.DefineDynamicAssembly(name, access);
54 | #else
55 | => AssemblyBuilder.DefineDynamicAssembly(name, access);
56 | #endif
57 |
58 | public static unsafe string CreateString(sbyte* value, int startIndex, int length, System.Text.Encoding enc)
59 | #if NETSTANDARD1_6
60 | {
61 | int vlength = enc.GetCharCount((byte*)value, length);
62 | if (vlength == 0)
63 | {
64 | return string.Empty;
65 | }
66 | fixed (char* v = new char[vlength])
67 | {
68 | enc.GetChars((byte*)value, length, v, vlength);
69 | return new string(v, 0, vlength);
70 | }
71 | }
72 | #else
73 | => new string(value, startIndex, length, enc);
74 | #endif
75 |
76 | public static T GetDelegateForFunctionPointer(IntPtr ptr)
77 | #if NETSTANDARD1_6
78 | => Marshal.GetDelegateForFunctionPointer(ptr);
79 | #else
80 | => (T)(object)Marshal.GetDelegateForFunctionPointer(ptr, typeof(T));
81 | #endif
82 |
83 | public static IntPtr GetFunctionPointerForDelegate(T func)
84 | #if NETSTANDARD1_6
85 | => Marshal.GetFunctionPointerForDelegate(func);
86 | #else
87 | => Marshal.GetFunctionPointerForDelegate((Delegate)(object)func);
88 | #endif
89 |
90 | public static string GetBaseDirectory()
91 | #if NETSTANDARD1_6
92 | => AppContext.BaseDirectory;
93 | #else
94 | => AppDomain.CurrentDomain.BaseDirectory;
95 | #endif
96 |
97 | }
98 |
99 | internal static class TransitionalExtensions
100 | {
101 | #if NET40 || NETSTANDARD1_6
102 | public static long GetLongLength(this T[] array, int dimension) => array.GetLength(dimension);
103 | #endif
104 |
105 | public static T CreateDelegate(this MethodInfo methodInfo)
106 | #if NET40
107 | => (T)(object)Delegate.CreateDelegate(typeof(T), methodInfo);
108 | #else
109 | => (T)(object)methodInfo.CreateDelegate(typeof(T));
110 | #endif
111 |
112 |
113 | #if NET40
114 | public static TypeInfo CreateTypeInfo(this TypeBuilder builder)
115 | {
116 | var type = builder.CreateType();
117 | return new TypeInfo(type);
118 | }
119 |
120 | public static TypeInfo GetTypeInfo(this Type type)
121 | {
122 | return new TypeInfo(type);
123 | }
124 | #endif
125 |
126 | #if NET45 || NET40
127 | public unsafe static string GetString(this Encoding encoding, byte* bytes, int count)
128 | {
129 | var ptr = new IntPtr((void*)bytes);
130 | if (ReferenceEquals(encoding, Encoding.ASCII))
131 | return Marshal.PtrToStringAnsi(ptr, count);
132 | // An ugly double copy which is necessary in older frameworks without the unsafe GetString()
133 | byte[] temp = new byte[count];
134 | Marshal.Copy(ptr, temp, 0, count);
135 | return encoding.GetString(temp);
136 | }
137 | #endif
138 | }
139 | }
140 |
141 |
142 | #if !NETSTANDARD1_6
143 | namespace System.Runtime.InteropServices
144 | {
145 | public static class OSPlatform
146 | {
147 | public static string Linux { get; } = "Linux";
148 | public static string OSX { get; } = "OSX";
149 | public static string Windows { get; } = "Windows";
150 | }
151 |
152 | public enum Architecture
153 | {
154 | X86 = 0,
155 | X64 = 1,
156 | Arm = 2,
157 | Arm64 = 3
158 | }
159 |
160 | internal static class RuntimeInformation
161 | {
162 | internal static bool IsOSPlatform(string osplatform)
163 | {
164 | switch ((int)Environment.OSVersion.Platform)
165 | {
166 | case (int)PlatformID.Win32Windows: // Win9x supported?
167 | case (int)PlatformID.Win32S: // Win16 NTVDM on Win x86?
168 | case (int)PlatformID.Win32NT: // Windows NT
169 | case (int)PlatformID.WinCE:
170 | return osplatform == OSPlatform.Windows;
171 | case (int)PlatformID.Unix:
172 | return osplatform == OSPlatform.Linux;
173 | case (int)PlatformID.MacOSX:
174 | case 128: // Mono Mac
175 | return osplatform == OSPlatform.OSX;
176 | default:
177 | return false;
178 | }
179 | }
180 |
181 | internal static Architecture ProcessArchitecture => Environment.Is64BitProcess? Architecture.X64 : Architecture.X86;
182 | }
183 | }
184 | #endif
--------------------------------------------------------------------------------
/RocksDbSharp/WriteBatch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace RocksDbSharp
5 | {
6 | public interface IWriteBatch : IDisposable
7 | {
8 | IntPtr Handle { get; }
9 | IWriteBatch Clear();
10 | int Count();
11 | IWriteBatch Put(string key, string val, Encoding encoding = null);
12 | IWriteBatch Put(byte[] key, byte[] val, ColumnFamilyHandle cf = null);
13 | IWriteBatch Put(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf = null);
14 | unsafe void Put(byte* key, ulong klen, byte* val, ulong vlen, ColumnFamilyHandle cf = null);
15 | IWriteBatch Putv(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes);
16 | IWriteBatch PutvCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes);
17 | IWriteBatch Merge(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf = null);
18 | unsafe void Merge(byte* key, ulong klen, byte* val, ulong vlen, ColumnFamilyHandle cf = null);
19 | IWriteBatch MergeCf(IntPtr columnFamily, byte[] key, ulong klen, byte[] val, ulong vlen);
20 | unsafe void MergeCf(IntPtr columnFamily, byte* key, ulong klen, byte* val, ulong vlen);
21 | IWriteBatch Mergev(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes);
22 | IWriteBatch MergevCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes);
23 | IWriteBatch Delete(byte[] key, ColumnFamilyHandle cf = null);
24 | IWriteBatch Delete(byte[] key, ulong klen, ColumnFamilyHandle cf = null);
25 | unsafe void Delete(byte* key, ulong klen, ColumnFamilyHandle cf = null);
26 | unsafe void Deletev(int numKeys, IntPtr keysList, IntPtr keysListSizes, ColumnFamilyHandle cf = null);
27 | IWriteBatch DeleteRange(byte[] startKey, ulong sklen, byte[] endKey, ulong eklen, ColumnFamilyHandle cf = null);
28 | unsafe void DeleteRange(byte* startKey, ulong sklen, byte* endKey, ulong eklen, ColumnFamilyHandle cf = null);
29 | unsafe void DeleteRangev(int numKeys, IntPtr startKeysList, IntPtr startKeysListSizes, IntPtr endKeysList, IntPtr endKeysListSizes, ColumnFamilyHandle cf = null);
30 | IWriteBatch PutLogData(byte[] blob, ulong len);
31 | IWriteBatch Iterate(IntPtr state, PutDelegate put, DeletedDelegate deleted);
32 | byte[] ToBytes();
33 | byte[] ToBytes(byte[] buffer, int offset = 0, int size = -1);
34 | void SetSavePoint();
35 | void RollbackToSavePoint();
36 | }
37 |
38 | public class WriteBatch : IWriteBatch, IDisposable
39 | {
40 | private IntPtr handle;
41 | private Encoding defaultEncoding = Encoding.UTF8;
42 |
43 | public WriteBatch()
44 | : this(Native.Instance.rocksdb_writebatch_create())
45 | {
46 | }
47 |
48 | public WriteBatch(byte[] rep, long size = -1)
49 | : this(Native.Instance.rocksdb_writebatch_create_from(rep, size < 0 ? (UIntPtr)rep.Length : (UIntPtr)size))
50 | {
51 | }
52 |
53 | private WriteBatch(IntPtr handle)
54 | {
55 | this.handle = handle;
56 | }
57 |
58 | public IntPtr Handle { get { return handle; } }
59 |
60 | public void Dispose()
61 | {
62 | if (handle != IntPtr.Zero)
63 | {
64 | #if !NODESTROY
65 | Native.Instance.rocksdb_writebatch_destroy(handle);
66 | #endif
67 | handle = IntPtr.Zero;
68 | }
69 | }
70 |
71 | public WriteBatch Clear()
72 | {
73 | Native.Instance.rocksdb_writebatch_clear(handle);
74 | return this;
75 | }
76 |
77 | public int Count()
78 | {
79 | return Native.Instance.rocksdb_writebatch_count(handle);
80 | }
81 |
82 | public WriteBatch Put(string key, string val, Encoding encoding = null)
83 | {
84 | if (encoding == null)
85 | encoding = defaultEncoding;
86 | Native.Instance.rocksdb_writebatch_put(handle, key, val, encoding);
87 | return this;
88 | }
89 |
90 | public WriteBatch Put(byte[] key, byte[] val, ColumnFamilyHandle cf = null)
91 | {
92 | return Put(key, (ulong)key.Length, val, (ulong)val.Length, cf);
93 | }
94 |
95 | public WriteBatch Put(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf = null)
96 | {
97 | if (cf == null)
98 | Native.Instance.rocksdb_writebatch_put(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
99 | else
100 | Native.Instance.rocksdb_writebatch_put_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
101 | return this;
102 | }
103 |
104 | public unsafe void Put(byte* key, ulong klen, byte* val, ulong vlen, ColumnFamilyHandle cf = null)
105 | {
106 | if (cf == null)
107 | Native.Instance.rocksdb_writebatch_put(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
108 | else
109 | Native.Instance.rocksdb_writebatch_put_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
110 | }
111 |
112 | public WriteBatch Putv(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
113 | {
114 | Native.Instance.rocksdb_writebatch_putv(handle, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
115 | return this;
116 | }
117 |
118 | public WriteBatch PutvCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
119 | {
120 | Native.Instance.rocksdb_writebatch_putv_cf(handle, columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
121 | return this;
122 | }
123 |
124 | public WriteBatch Merge(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf = null)
125 | {
126 | if (cf == null)
127 | Native.Instance.rocksdb_writebatch_merge(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
128 | else
129 | Native.Instance.rocksdb_writebatch_merge_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
130 | return this;
131 | }
132 |
133 | public unsafe void Merge(byte* key, ulong klen, byte* val, ulong vlen, ColumnFamilyHandle cf = null)
134 | {
135 | if (cf == null)
136 | Native.Instance.rocksdb_writebatch_merge(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
137 | else
138 | Native.Instance.rocksdb_writebatch_merge_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
139 | }
140 |
141 | public WriteBatch MergeCf(IntPtr columnFamily, byte[] key, ulong klen, byte[] val, ulong vlen)
142 | {
143 | Native.Instance.rocksdb_writebatch_merge_cf(handle, columnFamily, key, (UIntPtr)klen, val, (UIntPtr)vlen);
144 | return this;
145 | }
146 |
147 | public unsafe void MergeCf(IntPtr columnFamily, byte* key, ulong klen, byte* val, ulong vlen)
148 | {
149 | Native.Instance.rocksdb_writebatch_merge_cf(handle, columnFamily, key, (UIntPtr)klen, val, (UIntPtr)vlen);
150 | }
151 |
152 | public WriteBatch Mergev(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
153 | {
154 | Native.Instance.rocksdb_writebatch_mergev(handle, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
155 | return this;
156 | }
157 |
158 | public WriteBatch MergevCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
159 | {
160 | Native.Instance.rocksdb_writebatch_mergev_cf(handle, columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
161 | return this;
162 | }
163 |
164 | public WriteBatch Delete(byte[] key, ColumnFamilyHandle cf = null)
165 | {
166 | return Delete(key, (ulong)key.Length, cf);
167 | }
168 |
169 | public WriteBatch Delete(byte[] key, ulong klen, ColumnFamilyHandle cf = null)
170 | {
171 | if (cf == null)
172 | Native.Instance.rocksdb_writebatch_delete(handle, key, (UIntPtr)klen);
173 | else
174 | Native.Instance.rocksdb_writebatch_delete_cf(handle, cf.Handle, key, (UIntPtr)klen);
175 | return this;
176 | }
177 |
178 | public unsafe void Delete(byte* key, ulong klen, ColumnFamilyHandle cf = null)
179 | {
180 | if (cf == null)
181 | Native.Instance.rocksdb_writebatch_delete(handle, key, (UIntPtr)klen);
182 | else
183 | Native.Instance.rocksdb_writebatch_delete_cf(handle, cf.Handle, key, (UIntPtr)klen);
184 | }
185 |
186 | public unsafe void Deletev(int numKeys, IntPtr keysList, IntPtr keysListSizes, ColumnFamilyHandle cf = null)
187 | {
188 | if (cf == null)
189 | Native.Instance.rocksdb_writebatch_deletev(handle, numKeys, keysList, keysListSizes);
190 | else
191 | Native.Instance.rocksdb_writebatch_deletev_cf(handle, cf.Handle, numKeys, keysList, keysListSizes);
192 | }
193 |
194 | public WriteBatch DeleteRange(byte[] startKey, ulong sklen, byte[] endKey, ulong eklen, ColumnFamilyHandle cf = null)
195 | {
196 | if (cf == null)
197 | Native.Instance.rocksdb_writebatch_delete_range(handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
198 | else
199 | Native.Instance.rocksdb_writebatch_delete_range_cf(handle, cf.Handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
200 | return this;
201 | }
202 |
203 | public unsafe void DeleteRange(byte* startKey, ulong sklen, byte* endKey, ulong eklen, ColumnFamilyHandle cf = null)
204 | {
205 | if (cf == null)
206 | Native.Instance.rocksdb_writebatch_delete_range(handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
207 | else
208 | Native.Instance.rocksdb_writebatch_delete_range_cf(handle, cf.Handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
209 | }
210 |
211 | public unsafe void DeleteRangev(int numKeys, IntPtr startKeysList, IntPtr startKeysListSizes, IntPtr endKeysList, IntPtr endKeysListSizes, ColumnFamilyHandle cf = null)
212 | {
213 | if (cf == null)
214 | Native.Instance.rocksdb_writebatch_delete_rangev(handle, numKeys, startKeysList, startKeysListSizes, endKeysList, endKeysListSizes);
215 | else
216 | Native.Instance.rocksdb_writebatch_delete_rangev_cf(handle, cf.Handle, numKeys, startKeysList, startKeysListSizes, endKeysList, endKeysListSizes);
217 | }
218 |
219 | public WriteBatch PutLogData(byte[] blob, ulong len)
220 | {
221 | Native.Instance.rocksdb_writebatch_put_log_data(handle, blob, (UIntPtr)len);
222 | return this;
223 | }
224 |
225 | public WriteBatch Iterate(IntPtr state, PutDelegate put, DeletedDelegate deleted)
226 | {
227 | Native.Instance.rocksdb_writebatch_iterate(handle, state, put, deleted);
228 | return this;
229 | }
230 |
231 | ///
232 | /// Get the write batch as bytes
233 | ///
234 | ///
235 | public byte[] ToBytes()
236 | {
237 | return Native.Instance.rocksdb_writebatch_data(handle);
238 | }
239 |
240 | ///
241 | /// Get the write batch as bytes
242 | ///
243 | ///
244 | ///
245 | ///
246 | /// null if size was not large enough to hold the data
247 | public byte[] ToBytes(byte[] buffer, int offset = 0, int size = -1)
248 | {
249 | if (size < 0)
250 | size = buffer.Length;
251 | if (Native.Instance.rocksdb_writebatch_data(handle, buffer, 0, size) > 0)
252 | return buffer;
253 | return null;
254 | }
255 |
256 | public void SetSavePoint()
257 | {
258 | Native.Instance.rocksdb_writebatch_set_save_point(handle);
259 | }
260 |
261 | public void RollbackToSavePoint()
262 | {
263 | Native.Instance.rocksdb_writebatch_rollback_to_save_point(handle);
264 | }
265 |
266 | public void PopSavePoint()
267 | {
268 | Native.Instance.rocksdb_writebatch_pop_save_point(handle);
269 | }
270 |
271 | IWriteBatch IWriteBatch.Clear()
272 | => Clear();
273 | IWriteBatch IWriteBatch.Put(string key, string val, Encoding encoding)
274 | => Put(key, val, encoding);
275 | IWriteBatch IWriteBatch.Put(byte[] key, byte[] val, ColumnFamilyHandle cf)
276 | => Put(key, val, cf);
277 | IWriteBatch IWriteBatch.Put(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf)
278 | => Put(key, klen, val, vlen, cf);
279 | IWriteBatch IWriteBatch.Putv(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
280 | => Putv(numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
281 | IWriteBatch IWriteBatch.PutvCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
282 | => PutvCf(columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
283 | IWriteBatch IWriteBatch.Merge(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf)
284 | => Merge(key, klen, val, vlen, cf);
285 | IWriteBatch IWriteBatch.MergeCf(IntPtr columnFamily, byte[] key, ulong klen, byte[] val, ulong vlen)
286 | => MergeCf(columnFamily, key, klen, val, vlen);
287 | IWriteBatch IWriteBatch.Mergev(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
288 | => Mergev(numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
289 | IWriteBatch IWriteBatch.MergevCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
290 | => MergevCf(columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
291 | IWriteBatch IWriteBatch.Delete(byte[] key, ColumnFamilyHandle cf)
292 | => Delete(key, cf);
293 | IWriteBatch IWriteBatch.Delete(byte[] key, ulong klen, ColumnFamilyHandle cf)
294 | => Delete(key, klen, cf);
295 | IWriteBatch IWriteBatch.DeleteRange(byte[] startKey, ulong sklen, byte[] endKey, ulong eklen, ColumnFamilyHandle cf)
296 | => DeleteRange(startKey, sklen, endKey, eklen, cf);
297 | IWriteBatch IWriteBatch.PutLogData(byte[] blob, ulong len)
298 | => PutLogData(blob, len);
299 | IWriteBatch IWriteBatch.Iterate(IntPtr state, PutDelegate put, DeletedDelegate deleted)
300 | => Iterate(state, put, deleted);
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/RocksDbSharp/WriteBatchWithIndex.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using System.Text;
5 | using Transitional;
6 |
7 | namespace RocksDbSharp
8 | {
9 | public class WriteBatchWithIndex : IWriteBatch
10 | {
11 | private IntPtr handle;
12 | private Encoding defaultEncoding = Encoding.UTF8;
13 |
14 | public WriteBatchWithIndex(ulong reservedBytes = 0, bool overwriteKeys = true)
15 | : this(Native.Instance.rocksdb_writebatch_wi_create((UIntPtr)reservedBytes, overwriteKeys))
16 | {
17 | }
18 |
19 | private WriteBatchWithIndex(IntPtr handle)
20 | {
21 | this.handle = handle;
22 | }
23 |
24 | public IntPtr Handle { get { return handle; } }
25 |
26 | public void Dispose()
27 | {
28 | if (handle != IntPtr.Zero)
29 | {
30 | #if !NODESTROY
31 | Native.Instance.rocksdb_writebatch_wi_destroy(handle);
32 | #endif
33 | handle = IntPtr.Zero;
34 | }
35 | }
36 |
37 | public WriteBatchWithIndex Clear()
38 | {
39 | Native.Instance.rocksdb_writebatch_wi_clear(handle);
40 | return this;
41 | }
42 |
43 | public int Count()
44 | {
45 | return Native.Instance.rocksdb_writebatch_wi_count(handle);
46 | }
47 |
48 | public Iterator CreateIteratorWithBase(Iterator baseIterator, ColumnFamilyHandle cf = null)
49 | {
50 | var handle = cf == null
51 | ? Native.Instance.rocksdb_writebatch_wi_create_iterator_with_base(Handle, baseIterator.Handle)
52 | : Native.Instance.rocksdb_writebatch_wi_create_iterator_with_base_cf(Handle, baseIterator.Handle, cf.Handle);
53 | return new Iterator(handle);
54 | }
55 |
56 | public string Get(string key, ColumnFamilyHandle cf = null, OptionsHandle options = null, Encoding encoding = null)
57 | {
58 | return Native.Instance.rocksdb_writebatch_wi_get_from_batch(Handle, (options ?? RocksDb.DefaultOptions).Handle, key, cf, encoding ?? defaultEncoding);
59 | }
60 |
61 | public byte[] Get(byte[] key, ColumnFamilyHandle cf = null, OptionsHandle options = null)
62 | {
63 | return Get(key, (ulong)key.GetLongLength(0), cf, options);
64 | }
65 |
66 | public byte[] Get(byte[] key, ulong keyLength, ColumnFamilyHandle cf = null, OptionsHandle options = null)
67 | {
68 | return Native.Instance.rocksdb_writebatch_wi_get_from_batch(Handle, (options ?? RocksDb.DefaultOptions).Handle, key, keyLength, cf);
69 | }
70 |
71 | public ulong Get(byte[] key, byte[] buffer, ulong offset, ulong length, ColumnFamilyHandle cf = null, OptionsHandle options = null)
72 | {
73 | return Get(key, (ulong)key.GetLongLength(0), buffer, offset, length, cf, options);
74 | }
75 |
76 | public ulong Get(byte[] key, ulong keyLength, byte[] buffer, ulong offset, ulong length, ColumnFamilyHandle cf = null, OptionsHandle options = null)
77 | {
78 | unsafe
79 | {
80 | var ptr = Native.Instance.rocksdb_writebatch_wi_get_from_batch(Handle, (options ?? RocksDb.DefaultOptions).Handle, key, keyLength, out ulong valLength, cf);
81 | valLength = Math.Min(length, valLength);
82 | Marshal.Copy(ptr, buffer, (int)offset, (int)valLength);
83 | Native.Instance.rocksdb_free(ptr);
84 | return valLength;
85 | }
86 | }
87 |
88 | public string Get(RocksDb db, string key, ColumnFamilyHandle cf = null, ReadOptions options = null, Encoding encoding = null)
89 | {
90 | return Native.Instance.rocksdb_writebatch_wi_get_from_batch_and_db(Handle, db.Handle, (options ?? RocksDb.DefaultReadOptions).Handle, key, cf, encoding ?? defaultEncoding);
91 | }
92 |
93 | public byte[] Get(RocksDb db, byte[] key, ColumnFamilyHandle cf = null, ReadOptions options = null)
94 | {
95 | return Get(db, key, (ulong)key.GetLongLength(0), cf, options);
96 | }
97 |
98 | public byte[] Get(RocksDb db, byte[] key, ulong keyLength, ColumnFamilyHandle cf = null, ReadOptions options = null)
99 | {
100 | return Native.Instance.rocksdb_writebatch_wi_get_from_batch_and_db(Handle, db.Handle, (options ?? RocksDb.DefaultReadOptions).Handle, key, keyLength, cf);
101 | }
102 |
103 | public ulong Get(RocksDb db, byte[] key, byte[] buffer, ulong offset, ulong length, ColumnFamilyHandle cf = null, ReadOptions options = null)
104 | {
105 | return Get(db, key, (ulong)key.GetLongLength(0), buffer, offset, length, cf, options);
106 | }
107 |
108 | public ulong Get(RocksDb db, byte[] key, ulong keyLength, byte[] buffer, ulong offset, ulong length, ColumnFamilyHandle cf = null, ReadOptions options = null)
109 | {
110 | unsafe
111 | {
112 | var ptr = Native.Instance.rocksdb_writebatch_wi_get_from_batch_and_db(Handle, db.Handle, (options ?? RocksDb.DefaultReadOptions).Handle, key, keyLength, out ulong valLength, cf);
113 | valLength = Math.Min(length, valLength);
114 | Marshal.Copy(ptr, buffer, (int)offset, (int)valLength);
115 | Native.Instance.rocksdb_free(ptr);
116 | return valLength;
117 | }
118 | }
119 |
120 | public Iterator NewIterator(Iterator baseIterator, ColumnFamilyHandle cf = null)
121 | {
122 | IntPtr iteratorHandle = cf == null
123 | ? Native.Instance.rocksdb_writebatch_wi_create_iterator_with_base(Handle, baseIterator.Handle)
124 | : Native.Instance.rocksdb_writebatch_wi_create_iterator_with_base_cf(Handle, baseIterator.Handle, cf.Handle);
125 | baseIterator.Detach();
126 | // Note: passing in base iterator here only to ensure that it is not collected before the iterator
127 | return new Iterator(iteratorHandle);
128 | }
129 |
130 | public WriteBatchWithIndex Put(string key, string val, Encoding encoding = null)
131 | {
132 | if (encoding == null)
133 | encoding = defaultEncoding;
134 | Native.Instance.rocksdb_writebatch_wi_put(handle, key, val, encoding);
135 | return this;
136 | }
137 |
138 | public WriteBatchWithIndex Put(byte[] key, byte[] val, ColumnFamilyHandle cf = null)
139 | {
140 | return Put(key, (ulong)key.Length, val, (ulong)val.Length, cf);
141 | }
142 |
143 | public WriteBatchWithIndex Put(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf = null)
144 | {
145 | if (cf == null)
146 | Native.Instance.rocksdb_writebatch_wi_put(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
147 | else
148 | Native.Instance.rocksdb_writebatch_wi_put_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
149 | return this;
150 | }
151 |
152 | public unsafe void Put(byte* key, ulong klen, byte* val, ulong vlen, ColumnFamilyHandle cf = null)
153 | {
154 | if (cf == null)
155 | Native.Instance.rocksdb_writebatch_wi_put(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
156 | else
157 | Native.Instance.rocksdb_writebatch_wi_put_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
158 | }
159 |
160 | public WriteBatchWithIndex Putv(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
161 | {
162 | Native.Instance.rocksdb_writebatch_wi_putv(handle, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
163 | return this;
164 | }
165 |
166 | public WriteBatchWithIndex PutvCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
167 | {
168 | Native.Instance.rocksdb_writebatch_wi_putv_cf(handle, columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
169 | return this;
170 | }
171 |
172 | public WriteBatchWithIndex Merge(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf = null)
173 | {
174 | if (cf == null)
175 | Native.Instance.rocksdb_writebatch_wi_merge(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
176 | else
177 | Native.Instance.rocksdb_writebatch_wi_merge_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
178 | return this;
179 | }
180 |
181 | public unsafe void Merge(byte* key, ulong klen, byte* val, ulong vlen, ColumnFamilyHandle cf = null)
182 | {
183 | if (cf == null)
184 | Native.Instance.rocksdb_writebatch_wi_merge(handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
185 | else
186 | Native.Instance.rocksdb_writebatch_wi_merge_cf(handle, cf.Handle, key, (UIntPtr)klen, val, (UIntPtr)vlen);
187 | }
188 |
189 | public WriteBatchWithIndex MergeCf(IntPtr columnFamily, byte[] key, ulong klen, byte[] val, ulong vlen)
190 | {
191 | Native.Instance.rocksdb_writebatch_wi_merge_cf(handle, columnFamily, key, (UIntPtr)klen, val, (UIntPtr)vlen);
192 | return this;
193 | }
194 |
195 | public unsafe void MergeCf(IntPtr columnFamily, byte* key, ulong klen, byte* val, ulong vlen)
196 | {
197 | Native.Instance.rocksdb_writebatch_wi_merge_cf(handle, columnFamily, key, (UIntPtr)klen, val, (UIntPtr)vlen);
198 | }
199 |
200 | public WriteBatchWithIndex Mergev(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
201 | {
202 | Native.Instance.rocksdb_writebatch_wi_mergev(handle, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
203 | return this;
204 | }
205 |
206 | public WriteBatchWithIndex MergevCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
207 | {
208 | Native.Instance.rocksdb_writebatch_wi_mergev_cf(handle, columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
209 | return this;
210 | }
211 |
212 | public WriteBatchWithIndex Delete(byte[] key, ColumnFamilyHandle cf = null)
213 | {
214 | return Delete(key, (ulong)key.Length, cf);
215 | }
216 |
217 | public WriteBatchWithIndex Delete(byte[] key, ulong klen, ColumnFamilyHandle cf = null)
218 | {
219 | if (cf == null)
220 | Native.Instance.rocksdb_writebatch_wi_delete(handle, key, (UIntPtr)klen);
221 | else
222 | Native.Instance.rocksdb_writebatch_wi_delete_cf(handle, cf.Handle, key, (UIntPtr)klen);
223 | return this;
224 | }
225 |
226 | public unsafe void Delete(byte* key, ulong klen, ColumnFamilyHandle cf = null)
227 | {
228 | if (cf == null)
229 | Native.Instance.rocksdb_writebatch_wi_delete(handle, key, (UIntPtr)klen);
230 | else
231 | Native.Instance.rocksdb_writebatch_wi_delete_cf(handle, cf.Handle, key, (UIntPtr)klen);
232 | }
233 |
234 | public unsafe void Deletev(int numKeys, IntPtr keysList, IntPtr keysListSizes, ColumnFamilyHandle cf = null)
235 | {
236 | if (cf == null)
237 | Native.Instance.rocksdb_writebatch_wi_deletev(handle, numKeys, keysList, keysListSizes);
238 | else
239 | Native.Instance.rocksdb_writebatch_wi_deletev_cf(handle, cf.Handle, numKeys, keysList, keysListSizes);
240 | }
241 |
242 | public WriteBatchWithIndex DeleteRange(byte[] startKey, ulong sklen, byte[] endKey, ulong eklen, ColumnFamilyHandle cf = null)
243 | {
244 | if (cf == null)
245 | Native.Instance.rocksdb_writebatch_wi_delete_range(handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
246 | else
247 | Native.Instance.rocksdb_writebatch_wi_delete_range_cf(handle, cf.Handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
248 | return this;
249 | }
250 |
251 | public unsafe void DeleteRange(byte* startKey, ulong sklen, byte* endKey, ulong eklen, ColumnFamilyHandle cf = null)
252 | {
253 | if (cf == null)
254 | Native.Instance.rocksdb_writebatch_wi_delete_range(handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
255 | else
256 | Native.Instance.rocksdb_writebatch_wi_delete_range_cf(handle, cf.Handle, startKey, (UIntPtr)sklen, endKey, (UIntPtr)eklen);
257 | }
258 |
259 | public unsafe void DeleteRangev(int numKeys, IntPtr startKeysList, IntPtr startKeysListSizes, IntPtr endKeysList, IntPtr endKeysListSizes, ColumnFamilyHandle cf = null)
260 | {
261 | if (cf == null)
262 | Native.Instance.rocksdb_writebatch_wi_delete_rangev(handle, numKeys, startKeysList, startKeysListSizes, endKeysList, endKeysListSizes);
263 | else
264 | Native.Instance.rocksdb_writebatch_wi_delete_rangev_cf(handle, cf.Handle, numKeys, startKeysList, startKeysListSizes, endKeysList, endKeysListSizes);
265 | }
266 |
267 | public WriteBatchWithIndex PutLogData(byte[] blob, ulong len)
268 | {
269 | Native.Instance.rocksdb_writebatch_wi_put_log_data(handle, blob, (UIntPtr)len);
270 | return this;
271 | }
272 |
273 | public WriteBatchWithIndex Iterate(IntPtr state, PutDelegate put, DeletedDelegate deleted)
274 | {
275 | Native.Instance.rocksdb_writebatch_wi_iterate(handle, state, put, deleted);
276 | return this;
277 | }
278 |
279 | ///
280 | /// Get the write batch as bytes
281 | ///
282 | ///
283 | public byte[] ToBytes()
284 | {
285 | return Native.Instance.rocksdb_writebatch_wi_data(handle);
286 | }
287 |
288 | ///
289 | /// Get the write batch as bytes
290 | ///
291 | ///
292 | ///
293 | ///
294 | /// null if size was not large enough to hold the data
295 | public byte[] ToBytes(byte[] buffer, int offset = 0, int size = -1)
296 | {
297 | if (size < 0)
298 | size = buffer.Length;
299 | if (Native.Instance.rocksdb_writebatch_wi_data(handle, buffer, 0, size) > 0)
300 | return buffer;
301 | return null;
302 | }
303 |
304 | public void SetSavePoint()
305 | {
306 | Native.Instance.rocksdb_writebatch_wi_set_save_point(handle);
307 | }
308 |
309 | public void RollbackToSavePoint()
310 | {
311 | Native.Instance.rocksdb_writebatch_wi_rollback_to_save_point(handle);
312 | }
313 |
314 |
315 | IWriteBatch IWriteBatch.Clear()
316 | => Clear();
317 | IWriteBatch IWriteBatch.Put(string key, string val, Encoding encoding)
318 | => Put(key, val, encoding);
319 | IWriteBatch IWriteBatch.Put(byte[] key, byte[] val, ColumnFamilyHandle cf)
320 | => Put(key, val, cf);
321 | IWriteBatch IWriteBatch.Put(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf)
322 | => Put(key, klen, val, vlen, cf);
323 | IWriteBatch IWriteBatch.Putv(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
324 | => Putv(numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
325 | IWriteBatch IWriteBatch.PutvCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
326 | => PutvCf(columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
327 | IWriteBatch IWriteBatch.Merge(byte[] key, ulong klen, byte[] val, ulong vlen, ColumnFamilyHandle cf)
328 | => Merge(key, klen, val, vlen, cf);
329 | IWriteBatch IWriteBatch.MergeCf(IntPtr columnFamily, byte[] key, ulong klen, byte[] val, ulong vlen)
330 | => MergeCf(columnFamily, key, klen, val, vlen);
331 | IWriteBatch IWriteBatch.Mergev(int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
332 | => Mergev(numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
333 | IWriteBatch IWriteBatch.MergevCf(IntPtr columnFamily, int numKeys, IntPtr keysList, IntPtr keysListSizes, int numValues, IntPtr valuesList, IntPtr valuesListSizes)
334 | => MergevCf(columnFamily, numKeys, keysList, keysListSizes, numValues, valuesList, valuesListSizes);
335 | IWriteBatch IWriteBatch.Delete(byte[] key, ColumnFamilyHandle cf)
336 | => Delete(key, cf);
337 | IWriteBatch IWriteBatch.Delete(byte[] key, ulong klen, ColumnFamilyHandle cf)
338 | => Delete(key, klen, cf);
339 | IWriteBatch IWriteBatch.DeleteRange(byte[] startKey, ulong sklen, byte[] endKey, ulong eklen, ColumnFamilyHandle cf)
340 | => DeleteRange(startKey, sklen, endKey, eklen, cf);
341 | IWriteBatch IWriteBatch.PutLogData(byte[] blob, ulong len)
342 | => PutLogData(blob, len);
343 | IWriteBatch IWriteBatch.Iterate(IntPtr state, PutDelegate put, DeletedDelegate deleted)
344 | => Iterate(state, put, deleted);
345 | }
346 | }
347 |
--------------------------------------------------------------------------------
/RocksDbSharp/WriteOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace RocksDbSharp
4 | {
5 | public class WriteOptions
6 | {
7 | public WriteOptions()
8 | {
9 | Handle = Native.Instance.rocksdb_writeoptions_create();
10 | }
11 |
12 | public IntPtr Handle { get; protected set; }
13 |
14 | ~WriteOptions()
15 | {
16 | if (Handle != IntPtr.Zero)
17 | {
18 | #if !NODESTROY
19 | Native.Instance.rocksdb_writeoptions_destroy(Handle);
20 | #endif
21 | Handle = IntPtr.Zero;
22 | }
23 | }
24 |
25 | public WriteOptions SetSync(bool value)
26 | {
27 | Native.Instance.rocksdb_writeoptions_set_sync(Handle, value);
28 | return this;
29 | }
30 |
31 | public WriteOptions DisableWal(int disable)
32 | {
33 | Native.Instance.rocksdb_writeoptions_disable_WAL(Handle, disable);
34 | return this;
35 | }
36 |
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Versions.targets.include:
--------------------------------------------------------------------------------
1 |
2 |
3 | 6.2.2
4 | 0
5 | 0
6 |
7 |
--------------------------------------------------------------------------------
/examples/ColumnFamilyExample/ColumnFamilyExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net45
4 | Exe
5 | x64
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/ColumnFamilyExample/Program.cs:
--------------------------------------------------------------------------------
1 | using RocksDbSharp;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ColumnFamilyExample
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | string temp = Path.GetTempPath();
16 | string path = Environment.ExpandEnvironmentVariables(Path.Combine(temp, "rocksdb_cf_example"));
17 |
18 | var options = new DbOptions()
19 | .SetCreateIfMissing(true)
20 | .SetCreateMissingColumnFamilies(true);
21 |
22 | var columnFamilies = new ColumnFamilies
23 | {
24 | { "reverse", new ColumnFamilyOptions() },
25 | };
26 |
27 | using (var db = RocksDb.Open(options, path, columnFamilies))
28 | {
29 | var reverse = db.GetColumnFamily("reverse");
30 |
31 | db.Put("one", "uno");
32 | db.Put("two", "dos");
33 | db.Put("three", "tres");
34 |
35 | db.Put("uno", "one", cf: reverse);
36 | db.Put("dos", "two", cf: reverse);
37 | db.Put("tres", "three", cf: reverse);
38 | }
39 |
40 | using (var db = RocksDb.Open(options, path, columnFamilies))
41 | {
42 | var reverse = db.GetColumnFamily("reverse");
43 |
44 | string uno = db.Get("one");
45 | string one = db.Get("uno", cf: reverse);
46 | string nada;
47 | nada = db.Get("uno");
48 | nada = db.Get("one", cf: reverse);
49 | }
50 |
51 | using (var db = RocksDb.Open(options, path, columnFamilies))
52 | {
53 | db.DropColumnFamily("reverse");
54 | var reverse = db.CreateColumnFamily(new ColumnFamilyOptions(), "reverse");
55 | var nada = db.Get("uno", cf: reverse);
56 | db.Put("red", "rouge", cf: reverse);
57 | }
58 |
59 | using (var db = RocksDb.Open(options, path, columnFamilies))
60 | {
61 | var reverse = db.GetColumnFamily("reverse");
62 | var nada = db.Get("uno", cf: reverse);
63 | var rouge = db.Get("red", cf: reverse);
64 | }
65 |
66 | using (var db = RocksDb.OpenReadOnly(options, path, columnFamilies, false))
67 | {
68 | string uno = db.Get("one");
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/examples/PrefixExample/PrefixExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net45
4 | Exe
5 | x64
6 | 1.0.0
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/examples/PrefixExample/Program.cs:
--------------------------------------------------------------------------------
1 | using RocksDbSharp;
2 | using System;
3 | using System.Diagnostics;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace PrefixExample
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | string temp = Path.GetTempPath();
14 | string path = Environment.ExpandEnvironmentVariables(Path.Combine(temp, "rocksdb_prefix_example"));
15 | var bbto = new BlockBasedTableOptions()
16 | .SetFilterPolicy(BloomFilterPolicy.Create(10, false))
17 | .SetWholeKeyFiltering(false)
18 | ;
19 | var options = new DbOptions()
20 | .SetCreateIfMissing(true)
21 | .SetCreateMissingColumnFamilies(true)
22 | ;
23 | var columnFamilies = new ColumnFamilies
24 | {
25 | { "default", new ColumnFamilyOptions().OptimizeForPointLookup(256) },
26 | { "test", new ColumnFamilyOptions()
27 | //.SetWriteBufferSize(writeBufferSize)
28 | //.SetMaxWriteBufferNumber(maxWriteBufferNumber)
29 | //.SetMinWriteBufferNumberToMerge(minWriteBufferNumberToMerge)
30 | .SetMemtableHugePageSize(2 * 1024 * 1024)
31 | .SetPrefixExtractor(SliceTransform.CreateFixedPrefix((ulong)8))
32 | .SetBlockBasedTableFactory(bbto)
33 | },
34 | };
35 | using (var db = RocksDb.Open(options, path, columnFamilies))
36 | {
37 | var cf = db.GetColumnFamily("test");
38 |
39 | db.Put("00000000Zero", "", cf: cf);
40 | db.Put("00000000One", "", cf: cf);
41 | db.Put("00000000Two", "", cf: cf);
42 | db.Put("00000000Three", "", cf: cf);
43 | db.Put("00000001Red", "", cf: cf);
44 | db.Put("00000001Green", "", cf: cf);
45 | db.Put("00000001Black", "", cf: cf);
46 | db.Put("00000002Apple", "", cf: cf);
47 | db.Put("00000002Cranberry", "", cf: cf);
48 | db.Put("00000002Banana", "", cf: cf);
49 |
50 | var readOptions = new ReadOptions();
51 | using (var iter = db.NewIterator(readOptions: readOptions, cf: cf))
52 | {
53 | GC.Collect();
54 | GC.WaitForPendingFinalizers();
55 | var b = Encoding.UTF8.GetBytes("00000001");
56 | iter.Seek(b);
57 | while (iter.Valid())
58 | {
59 | Console.WriteLine(iter.StringKey());
60 | iter.Next();
61 | }
62 | }
63 | }
64 | Console.WriteLine("Done...");
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/examples/SimpleExampleHighLevel/Program.cs:
--------------------------------------------------------------------------------
1 | using RocksDbSharp;
2 | using System;
3 | using System.Diagnostics;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace SimpleExampleHighLevel
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | string temp = Path.GetTempPath();
14 | string path = Environment.ExpandEnvironmentVariables(Path.Combine(temp, "rocksdb_simple_hl_example"));
15 | // the Options class contains a set of configurable DB options
16 | // that determines the behavior of a database
17 | // Why is the syntax, SetXXX(), not very C#-like? See Options for an explanation
18 | var options = new DbOptions()
19 | .SetCreateIfMissing(true)
20 | .EnableStatistics();
21 | using (var db = RocksDb.Open(options, path))
22 | {
23 | try
24 | {
25 | {
26 | // With strings
27 | string value = db.Get("key");
28 | db.Put("key", "value");
29 | value = db.Get("key");
30 | string iWillBeNull = db.Get("non-existent-key");
31 | db.Remove("key");
32 | }
33 |
34 | {
35 | // With bytes
36 | var key = Encoding.UTF8.GetBytes("key");
37 | byte[] value = Encoding.UTF8.GetBytes("value");
38 | db.Put(key, value);
39 | value = db.Get(key);
40 | byte[] iWillBeNull = db.Get(new byte[] { 0, 1, 2 });
41 | db.Remove(key);
42 |
43 | db.Put(key, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 });
44 | }
45 |
46 | {
47 | // With buffers
48 | var key = Encoding.UTF8.GetBytes("key");
49 | var buffer = new byte[100];
50 | long length = db.Get(key, buffer, 0, buffer.Length);
51 | }
52 |
53 | {
54 | // Removal of non-existent keys
55 | db.Remove("I don't exist");
56 | }
57 |
58 | {
59 | // Write batches
60 | // With strings
61 | using (WriteBatch batch = new WriteBatch()
62 | .Put("one", "uno")
63 | .Put("two", "deuce")
64 | .Put("two", "dos")
65 | .Put("three", "tres"))
66 | {
67 | db.Write(batch);
68 | }
69 |
70 | // With bytes
71 | var utf8 = Encoding.UTF8;
72 | using (WriteBatch batch = new WriteBatch()
73 | .Put(utf8.GetBytes("four"), new byte[] { 4, 4, 4 } )
74 | .Put(utf8.GetBytes("five"), new byte[] { 5, 5, 5 } ))
75 | {
76 | db.Write(batch);
77 | }
78 | }
79 |
80 | {
81 | // Snapshots
82 | using (var snapshot = db.CreateSnapshot())
83 | {
84 | var before = db.Get("one");
85 | db.Put("one", "1");
86 |
87 | var useSnapshot = new ReadOptions()
88 | .SetSnapshot(snapshot);
89 |
90 | // the database value was written
91 | Debug.Assert(db.Get("one") == "1");
92 | // but the snapshot still sees the old version
93 | var after = db.Get("one", readOptions: useSnapshot);
94 | Debug.Assert(after == before);
95 | }
96 | }
97 |
98 | var two = db.Get("two");
99 | Debug.Assert(two == "dos");
100 |
101 | {
102 | // Iterators
103 | using (var iterator = db.NewIterator(
104 | readOptions: new ReadOptions()
105 | .SetIterateUpperBound("t")
106 | ))
107 | {
108 | iterator.Seek("k");
109 | Debug.Assert(iterator.Valid());
110 | Debug.Assert(iterator.StringKey() == "key");
111 | iterator.Next();
112 | Debug.Assert(iterator.Valid());
113 | Debug.Assert(iterator.StringKey() == "one");
114 | Debug.Assert(iterator.StringValue() == "1");
115 | iterator.Next();
116 | Debug.Assert(!iterator.Valid());
117 | }
118 | }
119 |
120 | }
121 | catch (RocksDbException)
122 | {
123 |
124 | }
125 | }
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/examples/SimpleExampleHighLevel/SimpleExampleHighLevel.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net45
4 | Exe
5 | x64
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/SimpleExampleLowLevel/Program.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Simple Low Level Example.
3 |
4 | The low level api has been ported from the rocksdb C API (see Native0.cls in RocksDbSharp project).
5 |
6 | This is therefore intended to be a direct port from the c_simple_example.c at
7 | https://github.com/facebook/rocksdb/blob/ccc8c10/examples/c_simple_example.c
8 |
9 | */
10 | using RocksDbSharp;
11 | using System;
12 | using System.Diagnostics;
13 | using System.IO;
14 | using System.Linq;
15 | using System.Runtime.InteropServices;
16 | using System.Text;
17 |
18 | namespace SimpleExampleLowLevel
19 | {
20 | class Program
21 | {
22 | static string temp = Path.GetTempPath();
23 | static string DBPath = Environment.ExpandEnvironmentVariables(Path.Combine(temp, "rocksdb_simple_example"));
24 | static string DBBackupPath = Environment.ExpandEnvironmentVariables(Path.Combine(temp, "rocksdb_simple_example_backup"));
25 |
26 | static void Main(string[] args)
27 | {
28 | IntPtr db;
29 | IntPtr be;
30 | IntPtr options = Native.Instance.rocksdb_options_create();
31 | // Optimize RocksDB. This is the easiest way to
32 | // get RocksDB to perform well
33 | int cpus = Environment.ProcessorCount;
34 | Native.Instance.rocksdb_options_increase_parallelism(options, cpus);
35 | Native.Instance.rocksdb_options_optimize_level_style_compaction(options, 0);
36 | // create the DB if it's not already present
37 | Native.Instance.rocksdb_options_set_create_if_missing(options, true);
38 |
39 | // open DB
40 | IntPtr err = IntPtr.Zero;
41 | db = Native.Instance.rocksdb_open(options, DBPath, out err);
42 | Debug.Assert(err == IntPtr.Zero);
43 |
44 | // open Backup Engine that we will use for backing up our database
45 | be = Native.Instance.rocksdb_backup_engine_open(options, DBBackupPath, out err);
46 | Debug.Assert(err == IntPtr.Zero);
47 |
48 | // Put key-value
49 | IntPtr writeoptions = Native.Instance.rocksdb_writeoptions_create();
50 | string key = "key";
51 | string value = "value";
52 | Native.Instance.rocksdb_put(db, writeoptions, key, value,
53 | out err);
54 | Debug.Assert(err == IntPtr.Zero);
55 | // Get value
56 | IntPtr readoptions = Native.Instance.rocksdb_readoptions_create();
57 | string returned_value =
58 | Native.Instance.rocksdb_get(db, readoptions, key, out err);
59 | Debug.Assert(err == IntPtr.Zero);
60 | Debug.Assert(returned_value == "value");
61 |
62 | // create new backup in a directory specified by DBBackupPath
63 | Native.Instance.rocksdb_backup_engine_create_new_backup(be, db, out err);
64 | Debug.Assert(err == IntPtr.Zero);
65 |
66 | Native.Instance.rocksdb_close(db);
67 |
68 | // If something is wrong, you might want to restore data from last backup
69 | IntPtr restore_options = Native.Instance.rocksdb_restore_options_create();
70 | Native.Instance.rocksdb_backup_engine_restore_db_from_latest_backup(be, DBPath, DBPath,
71 | restore_options, out err);
72 | Debug.Assert(err == IntPtr.Zero);
73 | Native.Instance.rocksdb_restore_options_destroy(restore_options);
74 |
75 | db = Native.Instance.rocksdb_open(options, DBPath, out err);
76 | Debug.Assert(err == IntPtr.Zero);
77 |
78 | // cleanup
79 | Native.Instance.rocksdb_writeoptions_destroy(writeoptions);
80 | Native.Instance.rocksdb_readoptions_destroy(readoptions);
81 | Native.Instance.rocksdb_options_destroy(options);
82 | Native.Instance.rocksdb_backup_engine_close(be);
83 | Native.Instance.rocksdb_close(db);
84 |
85 | OtherExamples();
86 | }
87 |
88 | static void OtherExamples()
89 | {
90 | MultiGetExample();
91 | }
92 |
93 | static void MultiGetExample()
94 | {
95 | // Multiget
96 | IntPtr db;
97 | IntPtr options = Native.Instance.rocksdb_options_create();
98 | int cpus = Environment.ProcessorCount;
99 | Native.Instance.rocksdb_options_increase_parallelism(options, cpus);
100 | Native.Instance.rocksdb_options_optimize_level_style_compaction(options, 0);
101 | // create the DB if it's not already present
102 | Native.Instance.rocksdb_options_set_create_if_missing(options, true);
103 |
104 | // open DB
105 | IntPtr err = IntPtr.Zero;
106 | db = Native.Instance.rocksdb_open(options, DBPath, out err);
107 | Debug.Assert(err == IntPtr.Zero);
108 |
109 | // Put key-value
110 | IntPtr writeoptions = Native.Instance.rocksdb_writeoptions_create();
111 | Native.Instance.rocksdb_put(db, writeoptions, "one", "uno", out err);
112 | Debug.Assert(err == IntPtr.Zero);
113 | Native.Instance.rocksdb_put(db, writeoptions, "two", "dos", out err);
114 | Debug.Assert(err == IntPtr.Zero);
115 | Native.Instance.rocksdb_put(db, writeoptions, "three", "tres", out err);
116 | Debug.Assert(err == IntPtr.Zero);
117 | Native.Instance.rocksdb_put(db, writeoptions, "five", "五", out err);
118 | Debug.Assert(err == IntPtr.Zero);
119 |
120 | // Get value
121 | IntPtr readoptions = Native.Instance.rocksdb_readoptions_create();
122 | var values = Native.Instance.rocksdb_multi_get(db, readoptions, new[] { "two", "four", "five" });
123 |
124 | Debug.Assert(values[2].Value == "五");
125 |
126 | string returned_value =
127 | Native.Instance.rocksdb_get(db, readoptions, "one", out err);
128 | Debug.Assert(err == IntPtr.Zero);
129 | Debug.Assert(returned_value == "uno");
130 |
131 | // cleanup
132 | Native.Instance.rocksdb_writeoptions_destroy(writeoptions);
133 | Native.Instance.rocksdb_readoptions_destroy(readoptions);
134 | Native.Instance.rocksdb_options_destroy(options);
135 | Native.Instance.rocksdb_close(db);
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/examples/SimpleExampleLowLevel/SimpleExampleLowLevel.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net45
4 | Exe
5 | x64
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/nuget/build-and-pack.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | pushd "%~dp0"
3 | pushd "%~dp0"
4 | where /q msbuild
5 | IF ERRORLEVEL 1 (
6 | call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsMSBuildCmd.bat"
7 | )
8 | popd
9 |
10 | cd ..
11 |
12 | REM echo "Downloading native..."
13 | REM call download-native.cmd
14 |
15 | @REM --------------------------------
16 | @echo Building RocksDbNative
17 | cd RocksDbNative
18 | @echo Restoring...
19 | msbuild /t:Restore
20 | @if %errorlevel% neq 0 goto oops
21 | @echo Building...
22 | msbuild /p:Configuration=Release /t:Rebuild,Pack
23 | @if %errorlevel% neq 0 goto oops
24 | @echo Installing...
25 | move /y bin\Release\*.nupkg ..\nuget\
26 | @if %errorlevel% neq 0 goto oops
27 | cd ..
28 |
29 | @REM --------------------------------
30 | @echo Building RocksDbSharp
31 | cd RocksDbSharp
32 | @echo Restoring...
33 | msbuild /t:Restore
34 | @if %errorlevel% neq 0 goto oops
35 | @echo Building...
36 | msbuild /p:Configuration=Release /t:Rebuild,Pack
37 | @if %errorlevel% neq 0 goto oops
38 | @echo Installing...
39 | move /y bin\Release\*.nupkg ..\nuget\
40 | @if %errorlevel% neq 0 goto oops
41 | cd ..
42 |
43 | :good
44 | popd
45 | exit /b 0
46 |
47 | :oops
48 | set rval=%errorlevel%
49 | echo "ERROR"
50 | popd
51 | exit /b %rval%
--------------------------------------------------------------------------------
/nuget/instructions.txt:
--------------------------------------------------------------------------------
1 | Make sure version number is propagated everywhere
2 | Check .csproj files and edit any release info
3 | Run build-and-pack.cmd
4 |
5 | Verify that both packs worked, if possible, by copying them to the local nuget source and then installing them in a test project
6 | Go to nuget and upload through the interface
--------------------------------------------------------------------------------
/tests/RocksDbSharpTest/FunctionalTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 | using System.IO;
4 | using RocksDbSharp;
5 | using System.Text;
6 | using System.Linq;
7 | using System.Collections.Generic;
8 | using System.Runtime.InteropServices;
9 |
10 | namespace RocksDbSharpTest
11 | {
12 | public class FunctionalTests
13 | {
14 | [Fact]
15 | public void FunctionalTest()
16 | {
17 | string temp = Path.GetTempPath();
18 | var testdir = Path.Combine(temp, "functional_test");
19 | var testdb = Path.Combine(testdir, "main");
20 | var testcp = Path.Combine(testdir, "cp");
21 | var path = Environment.ExpandEnvironmentVariables(testdb);
22 | var cppath = Environment.ExpandEnvironmentVariables(testcp);
23 |
24 | if (Directory.Exists(testdir))
25 | Directory.Delete(testdir, true);
26 | Directory.CreateDirectory(testdir);
27 |
28 | var options = new DbOptions()
29 | .SetCreateIfMissing(true)
30 | .EnableStatistics();
31 |
32 | // Using standard open
33 | using (var db = RocksDb.Open(options, path))
34 | {
35 | // With strings
36 | string value = db.Get("key");
37 | db.Put("key", "value");
38 | Assert.Equal("value", db.Get("key"));
39 | Assert.Null(db.Get("non-existent-key"));
40 | db.Remove("key");
41 | Assert.Null(db.Get("value"));
42 |
43 | // With bytes
44 | db.Put(Encoding.UTF8.GetBytes("key"), Encoding.UTF8.GetBytes("value"));
45 | Assert.True(BinaryComparer.Default.Equals(Encoding.UTF8.GetBytes("value"), db.Get(Encoding.UTF8.GetBytes("key"))));
46 | // non-existent kiey
47 | Assert.Null(db.Get(new byte[] { 0, 1, 2 }));
48 | db.Remove(Encoding.UTF8.GetBytes("key"));
49 | Assert.Null(db.Get(Encoding.UTF8.GetBytes("key")));
50 |
51 | db.Put(Encoding.UTF8.GetBytes("key"), new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 });
52 |
53 | // With buffers
54 | var buffer = new byte[100];
55 | long length = db.Get(Encoding.UTF8.GetBytes("key"), buffer, 0, buffer.Length);
56 | Assert.Equal(8, length);
57 | Assert.Equal(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, buffer.Take((int)length).ToList());
58 |
59 | buffer = new byte[5];
60 | length = db.Get(Encoding.UTF8.GetBytes("key"), buffer, 0, buffer.Length);
61 | Assert.Equal(8, length);
62 | Assert.Equal(new byte[] { 0, 1, 2, 3, 4 }, buffer.Take((int)Math.Min(buffer.Length, length)));
63 |
64 | length = db.Get(Encoding.UTF8.GetBytes("bogus"), buffer, 0, buffer.Length);
65 | Assert.Equal(-1, length);
66 |
67 | // Write batches
68 | // With strings
69 | using (WriteBatch batch = new WriteBatch()
70 | .Put("one", "uno")
71 | .Put("two", "deuce")
72 | .Put("two", "dos")
73 | .Put("three", "tres"))
74 | {
75 | db.Write(batch);
76 | }
77 | Assert.Equal("uno", db.Get("one"));
78 |
79 | // With save point
80 | using (WriteBatch batch = new WriteBatch())
81 | {
82 | batch
83 | .Put("hearts", "red")
84 | .Put("diamonds", "red");
85 | batch.SetSavePoint();
86 | batch
87 | .Put("clubs", "black");
88 | batch.SetSavePoint();
89 | batch
90 | .Put("spades", "black");
91 | batch.RollbackToSavePoint();
92 | db.Write(batch);
93 | }
94 | Assert.Equal("red", db.Get("diamonds"));
95 | Assert.Equal("black", db.Get("clubs"));
96 | Assert.Null(db.Get("spades"));
97 |
98 | // Save a checkpoint
99 | using (var cp = db.Checkpoint())
100 | {
101 | cp.Save(cppath);
102 | }
103 |
104 | // With bytes
105 | var utf8 = Encoding.UTF8;
106 | using (WriteBatch batch = new WriteBatch()
107 | .Put(utf8.GetBytes("four"), new byte[] { 4, 4, 4 })
108 | .Put(utf8.GetBytes("five"), new byte[] { 5, 5, 5 }))
109 | {
110 | db.Write(batch);
111 | }
112 | Assert.True(BinaryComparer.Default.Equals(new byte[] { 4, 4, 4 }, db.Get(utf8.GetBytes("four"))));
113 |
114 | // Snapshots
115 | using (var snapshot = db.CreateSnapshot())
116 | {
117 | var before = db.Get("one");
118 | db.Put("one", "1");
119 |
120 | var useSnapshot = new ReadOptions()
121 | .SetSnapshot(snapshot);
122 |
123 | // the database value was written
124 | Assert.Equal("1", db.Get("one"));
125 | // but the snapshot still sees the old version
126 | var after = db.Get("one", readOptions: useSnapshot);
127 | Assert.Equal(before, after);
128 | }
129 |
130 | var two = db.Get("two");
131 | Assert.Equal("dos", two);
132 |
133 | // Iterators
134 | using (var iterator = db.NewIterator(
135 | readOptions: new ReadOptions()
136 | .SetIterateUpperBound("t")
137 | ))
138 | {
139 | iterator.Seek("k");
140 | Assert.True(iterator.Valid());
141 | Assert.Equal("key", iterator.StringKey());
142 | iterator.Next();
143 | Assert.True(iterator.Valid());
144 | Assert.Equal("one", iterator.StringKey());
145 | Assert.Equal("1", iterator.StringValue());
146 | iterator.Next();
147 | Assert.False(iterator.Valid());
148 | }
149 |
150 | // MultiGet
151 | var multiGetResult = db.MultiGet(new[] { "two", "three", "nine" });
152 | Assert.Equal(
153 | expected: new[]
154 | {
155 | new KeyValuePair("two", "dos"),
156 | new KeyValuePair("three", "tres"),
157 | new KeyValuePair("nine", null)
158 | },
159 | actual: multiGetResult
160 | );
161 | }
162 |
163 | // Test reading checkpointed db
164 | using (var cpdb = RocksDb.Open(options, cppath))
165 | {
166 | Assert.Equal("red", cpdb.Get("diamonds"));
167 | Assert.Equal("black", cpdb.Get("clubs"));
168 | Assert.Null(cpdb.Get("spades"));
169 | // Checkpoint occurred before these changes:
170 | Assert.Null(cpdb.Get("four"));
171 | }
172 |
173 | // Test various operations
174 | using (var db = RocksDb.Open(options, path))
175 | {
176 | // Nulls should be allowed here
177 | db.CompactRange((byte[])null, (byte[])null);
178 | db.CompactRange((string)null, (string)null);
179 | }
180 |
181 | // Test with column families
182 | var optionsCf = new DbOptions()
183 | .SetCreateIfMissing(true)
184 | .SetCreateMissingColumnFamilies(true);
185 |
186 | var columnFamilies = new ColumnFamilies
187 | {
188 | { "reverse", new ColumnFamilyOptions() },
189 | };
190 |
191 | using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
192 | {
193 | var reverse = db.GetColumnFamily("reverse");
194 |
195 | db.Put("one", "uno");
196 | db.Put("two", "dos");
197 | db.Put("three", "tres");
198 |
199 | db.Put("uno", "one", cf: reverse);
200 | db.Put("dos", "two", cf: reverse);
201 | db.Put("tres", "three", cf: reverse);
202 | }
203 |
204 | // Test Cf Delete
205 | using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
206 | {
207 | var reverse = db.GetColumnFamily("reverse");
208 |
209 | db.Put("cuatro", "four", cf: reverse);
210 | db.Put("cinco", "five", cf: reverse);
211 |
212 | Assert.Equal("four", db.Get("cuatro", cf: reverse));
213 | Assert.Equal("five", db.Get("cinco", cf: reverse));
214 |
215 | byte[] keyBytes = Encoding.UTF8.GetBytes("cuatro");
216 | db.Remove(keyBytes, reverse);
217 | db.Remove("cinco", reverse);
218 |
219 | Assert.Null(db.Get("cuatro", cf: reverse));
220 | Assert.Null(db.Get("cinco", cf: reverse));
221 | }
222 |
223 | // Test list
224 | {
225 | var list = RocksDb.ListColumnFamilies(optionsCf, path);
226 | Assert.Equal(new[] { "default", "reverse" }, list.ToArray());
227 | }
228 |
229 | // Test reopen with column families
230 | using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
231 | {
232 | var reverse = db.GetColumnFamily("reverse");
233 |
234 | Assert.Equal("uno", db.Get("one"));
235 | Assert.Equal("one", db.Get("uno", cf: reverse));
236 | Assert.Null(db.Get("uno"));
237 | Assert.Null(db.Get("one", cf: reverse));
238 | }
239 |
240 | // Test dropping and creating column family
241 | using (var db = RocksDb.Open(options, path, columnFamilies))
242 | {
243 | db.DropColumnFamily("reverse");
244 | var reverse = db.CreateColumnFamily(new ColumnFamilyOptions(), "reverse");
245 | Assert.Null(db.Get("uno", cf: reverse));
246 | db.Put("red", "rouge", cf: reverse);
247 | Assert.Equal("rouge", db.Get("red", cf: reverse));
248 | }
249 |
250 | // Test reopen after drop and create
251 | using (var db = RocksDb.Open(options, path, columnFamilies))
252 | {
253 | var reverse = db.GetColumnFamily("reverse");
254 | Assert.Null(db.Get("uno", cf: reverse));
255 | Assert.Equal("rouge", db.Get("red", cf: reverse));
256 | }
257 |
258 | // Test read only
259 | using (var db = RocksDb.OpenReadOnly(options, path, columnFamilies, false))
260 | {
261 | Assert.Equal("uno", db.Get("one"));
262 | }
263 |
264 | // Test SstFileWriter
265 | {
266 | using (var writer = new SstFileWriter())
267 | {
268 | }
269 |
270 | var envOpts = new EnvOptions();
271 | var ioOpts = new ColumnFamilyOptions();
272 | using (var sst = new SstFileWriter(envOpts, ioOpts))
273 | {
274 | var filename = Path.Combine(temp, "test.sst");
275 | if (File.Exists(filename))
276 | File.Delete(filename);
277 | sst.Open(filename);
278 | sst.Add("four", "quatro");
279 | sst.Add("one", "uno");
280 | sst.Add("two", "dos");
281 | sst.Finish();
282 |
283 | using (var db = RocksDb.Open(options, path, columnFamilies))
284 | {
285 | Assert.NotEqual("four", db.Get("four"));
286 | var ingestOptions = new IngestExternalFileOptions()
287 | .SetMoveFiles(true);
288 | db.IngestExternalFiles(new string[] { filename }, ingestOptions);
289 | Assert.Equal("quatro", db.Get("four"));
290 | }
291 | }
292 | }
293 |
294 | // test comparator
295 | unsafe {
296 | var opts = new ColumnFamilyOptions()
297 | .SetComparator(new IntegerStringComparator());
298 |
299 | var filename = Path.Combine(temp, "test.sst");
300 | if (File.Exists(filename))
301 | File.Delete(filename);
302 | using (var sst = new SstFileWriter(ioOptions: opts))
303 | {
304 | sst.Open(filename);
305 | sst.Add("111", "111");
306 | sst.Add("1001", "1001"); // this order is only allowed using an integer comparator
307 | sst.Finish();
308 | }
309 | }
310 |
311 | // test write batch with index
312 | {
313 | var wbwi = new WriteBatchWithIndex(reservedBytes: 1024);
314 | wbwi.Put("one", "un");
315 | wbwi.Put("two", "deux");
316 | var oneValueIn = Encoding.UTF8.GetBytes("one");
317 | var oneValueOut = wbwi.Get("one");
318 | Assert.Equal("un", oneValueOut);
319 | using (var db = RocksDb.Open(options, path, columnFamilies))
320 | {
321 | var oneCombinedOut = wbwi.Get(db, "one");
322 | var threeCombinedOut = wbwi.Get(db, "three");
323 | Assert.Equal("un", oneCombinedOut);
324 | Assert.Equal("tres", threeCombinedOut);
325 |
326 | using (var wbIterator = wbwi.NewIterator(db.NewIterator()))
327 | {
328 | wbIterator.Seek("o");
329 | Assert.True(wbIterator.Valid());
330 | var itkey = wbIterator.StringKey();
331 | Assert.Equal("one", itkey);
332 | var itval = wbIterator.StringValue();
333 | Assert.Equal("un", itval);
334 |
335 | wbIterator.Next();
336 | Assert.True(wbIterator.Valid());
337 | itkey = wbIterator.StringKey();
338 | Assert.Equal("three", itkey);
339 | itval = wbIterator.StringValue();
340 | Assert.Equal("tres", itval);
341 |
342 | wbIterator.Next();
343 | Assert.True(wbIterator.Valid());
344 | itkey = wbIterator.StringKey();
345 | Assert.Equal("two", itkey);
346 | itval = wbIterator.StringValue();
347 | Assert.Equal("deux", itval);
348 |
349 | wbIterator.Next();
350 | Assert.False(wbIterator.Valid());
351 | }
352 |
353 | db.Write(wbwi);
354 |
355 | var oneDbOut = wbwi.Get("one");
356 | Assert.Equal("un", oneDbOut);
357 | }
358 | }
359 |
360 | // compact range
361 | {
362 | using (var db = RocksDb.Open(options, path, columnFamilies))
363 | {
364 | db.CompactRange("o", "tw");
365 | }
366 | }
367 |
368 | // Test that GC does not cause access violation on Comparers
369 | {
370 | if (Directory.Exists("test-av-error"))
371 | Directory.Delete("test-av-error", true);
372 | options = new RocksDbSharp.DbOptions()
373 | .SetCreateIfMissing(true)
374 | .SetCreateMissingColumnFamilies(true);
375 | var sc = new RocksDbSharp.StringComparator(StringComparer.InvariantCultureIgnoreCase);
376 | columnFamilies = new RocksDbSharp.ColumnFamilies
377 | {
378 | { "cf1", new RocksDbSharp.ColumnFamilyOptions()
379 | .SetComparator(sc)
380 | },
381 | };
382 | GC.Collect();
383 | using (var db = RocksDbSharp.RocksDb.Open(options, "test-av-error", columnFamilies))
384 | {
385 | }
386 | if (Directory.Exists("test-av-error"))
387 | Directory.Delete("test-av-error", true);
388 | }
389 |
390 | // Smoke test various options
391 | {
392 | var dbname = "test-options";
393 | if (Directory.Exists(dbname))
394 | Directory.Delete(dbname, true);
395 | var optsTest = (DbOptions)new RocksDbSharp.DbOptions()
396 | .SetCreateIfMissing(true)
397 | .SetCreateMissingColumnFamilies(true)
398 | .SetBlockBasedTableFactory(new BlockBasedTableOptions().SetBlockCache(Cache.CreateLru(1024 * 1024)));
399 | GC.Collect();
400 | using (var db = RocksDbSharp.RocksDb.Open(optsTest, dbname))
401 | {
402 | }
403 | if (Directory.Exists(dbname))
404 | Directory.Delete(dbname, true);
405 |
406 | }
407 |
408 | // Smoke test OpenWithTtl
409 | {
410 | var dbname = "test-with-ttl";
411 | if (Directory.Exists(dbname))
412 | Directory.Delete(dbname, true);
413 | var optsTest = (DbOptions)new RocksDbSharp.DbOptions()
414 | .SetCreateIfMissing(true)
415 | .SetCreateMissingColumnFamilies(true);
416 | using (var db = RocksDbSharp.RocksDb.OpenWithTtl(optsTest, dbname, 1))
417 | {
418 | }
419 | if (Directory.Exists(dbname))
420 | Directory.Delete(dbname, true);
421 | }
422 |
423 | // Smoke test MergeOperator
424 | {
425 | var dbname = "test-merge-operator";
426 | if (Directory.Exists(dbname))
427 | Directory.Delete(dbname, true);
428 | var optsTest = (DbOptions)new RocksDbSharp.DbOptions()
429 | .SetCreateIfMissing(true)
430 | .SetMergeOperator(MergeOperators.Create(
431 | name: "test-merge-operator",
432 | partialMerge: (key, keyLength, operandsList, operandsListLength, numOperands, success, newValueLength) => IntPtr.Zero,
433 | fullMerge: (key, keyLength, existingValue, existingValueLength, operandsList, operandsListLength, numOperands, success, newValueLength) => IntPtr.Zero,
434 | deleteValue: (value, valueLength) => { }
435 | ));
436 | GC.Collect();
437 | using (var db = RocksDbSharp.RocksDb.Open(optsTest, dbname))
438 | {
439 | }
440 | if (Directory.Exists(dbname))
441 | Directory.Delete(dbname, true);
442 |
443 | }
444 |
445 | // Test that GC does not cause access violation on Comparers
446 | {
447 | var dbname = "test-av-error";
448 | if (Directory.Exists(dbname))
449 | Directory.Delete(dbname, true);
450 | options = new RocksDbSharp.DbOptions()
451 | .SetCreateIfMissing(true)
452 | .SetCreateMissingColumnFamilies(true);
453 | var sc = new RocksDbSharp.StringComparator(StringComparer.InvariantCultureIgnoreCase);
454 | columnFamilies = new RocksDbSharp.ColumnFamilies
455 | {
456 | { "cf1", new RocksDbSharp.ColumnFamilyOptions()
457 | .SetComparator(sc)
458 | },
459 | };
460 | GC.Collect();
461 | using (var db = RocksDbSharp.RocksDb.Open(options, dbname, columnFamilies))
462 | {
463 | }
464 | if (Directory.Exists(dbname))
465 | Directory.Delete(dbname, true);
466 | }
467 |
468 | }
469 |
470 | class IntegerStringComparator : StringComparatorBase
471 | {
472 | Comparison Comparer { get; } = Comparer.Default.Compare;
473 |
474 | public override int Compare(string a, string b)
475 | => Comparer(long.TryParse(a, out long avalue) ? avalue : 0, long.TryParse(b, out long bvalue) ? bvalue : 0);
476 | }
477 | }
478 | }
479 |
--------------------------------------------------------------------------------
/tests/RocksDbSharpTest/RocksDbSharpTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.0
4 | True
5 | PackageReference
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/RocksDbSharpTest/TestBinaryComparer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 | using RocksDbSharp;
4 | using System.Text;
5 |
6 | namespace RocksDbSharpTest
7 | {
8 | public class TestBinaryComparer
9 | {
10 | [Fact]
11 | public void TestCompare()
12 | {
13 | var comparer = BinaryComparer.Default;
14 |
15 | var forward = StringComparer.OrdinalIgnoreCase.Compare("a", "b");
16 | var backward = -forward;
17 |
18 | AssertCompare(comparer, forward, "B", "b");
19 | AssertCompare(comparer, backward, "b", "B");
20 |
21 | AssertCompare(comparer, forward, "aB", "ab");
22 | AssertCompare(comparer, backward, "ab", "aB");
23 |
24 | AssertCompare(comparer, forward, "cB", "cb");
25 | AssertCompare(comparer, backward, "cb", "cB");
26 |
27 | AssertCompare(comparer, forward, "b", "bb");
28 | AssertCompare(comparer, backward, "bb", "b");
29 | }
30 |
31 | [Fact]
32 | public void TestPrefixEquals()
33 | {
34 | var comparer = BinaryComparer.Default;
35 |
36 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaa"), 1));
37 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaa"), 3));
38 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaa"), 5));
39 |
40 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaX"), 1));
41 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaX"), 2));
42 | Assert.False(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaX"), 3));
43 | Assert.False(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaX"), 5));
44 |
45 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaaX"), 1));
46 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaaX"), 3));
47 | Assert.False(comparer.PrefixEquals(AsciiBytes("aaa"), AsciiBytes("aaaX"), 4));
48 |
49 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaaX"), AsciiBytes("aaa"), 1));
50 | Assert.True(comparer.PrefixEquals(AsciiBytes("aaaX"), AsciiBytes("aaa"), 3));
51 | Assert.False(comparer.PrefixEquals(AsciiBytes("aaaX"), AsciiBytes("aaa"), 4));
52 | }
53 |
54 | private byte[] AsciiBytes(string v)
55 | {
56 | return Encoding.ASCII.GetBytes(v);
57 | }
58 |
59 | private void AssertCompare(BinaryComparer comparer, int expected, string v1, string v2)
60 | {
61 | Assert.Equal(expected, comparer.Compare(Encoding.UTF8.GetBytes(v1), Encoding.UTF8.GetBytes(v2)));
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------