├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── STSdb4.GettingStarted ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── STSdb4.GettingStarted.csproj ├── Tick.cs ├── TicksGenerator.cs └── app.config ├── STSdb4.Server ├── AboutBox.Designer.cs ├── AboutBox.cs ├── AboutBox.resx ├── App.config ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── STSdb4.Server.csproj ├── STSdb4Service.Designer.cs ├── STSdb4Service.cs └── UsersAndExceptionHandler.cs ├── STSdb4.sln └── STSdb4 ├── Data ├── CompareOption.cs ├── Comparer.cs ├── Data.cs ├── DataComparer.cs ├── DataEqualityComparer.cs ├── DataExtensions.cs ├── DataIndexerPersist.cs ├── DataPersist.cs ├── DataToObjects.cs ├── DataToString.cs ├── DataTransformer.cs ├── DataType.cs ├── DataTypeUtils.cs ├── EqualityComparer.cs ├── IData.cs ├── IToObjects.cs ├── IToString.cs ├── ITransformer.cs ├── IndexerPersist.cs ├── Persist.cs ├── Slots.cs ├── SlotsBuilder.cs ├── Transformer.cs ├── ValueToObjects.cs └── ValueToString.cs ├── Database ├── IStorageEngine.cs ├── ITable.cs ├── OperationCollection.cs ├── OperationCollectionFactory.cs ├── OperationCollectionPersist.cs ├── OperationPersist.cs ├── Operations │ ├── OperationCode.cs │ ├── OverallOperations.cs │ ├── PointOperations.cs │ ├── RangeOperations.cs │ └── ResultOperation.cs ├── OrderedSetFactory.cs ├── OrderedSetPersist.cs ├── STSdb.cs ├── StorageEngine.cs ├── StructureType.cs ├── XFile.cs ├── XStream.cs ├── XStreamApply.cs ├── XTable.cs ├── XTableApply.cs ├── XTablePortable.cs └── XTablePortableGeneric.cs ├── Doc ├── STSdb4.DevelopersGuide.docx └── STSdb4.GettingStarted.docx ├── General ├── Buffers │ └── BitUtils.cs ├── Collections │ ├── Cache.cs │ ├── IOrderedSet.cs │ ├── IOrderedSetFactory.cs │ ├── OrderedSet.cs │ └── SortedSetPatch.cs ├── Communication │ ├── ClientConnection.cs │ ├── Packet.cs │ ├── ServerConnection.cs │ └── TcpServer.cs ├── Comparers │ ├── BigEndianByteArrayComparer.cs │ ├── BigEndianByteArrayEqualityComparer.cs │ ├── ByteOrder.cs │ ├── CommonArray.cs │ ├── ComparerInvertor.cs │ ├── KeyValuePairComparer.cs │ ├── LittleEndianByteArrayComparer.cs │ ├── LittleEndianByteArrayEqualityComparer.cs │ └── SortOrder.cs ├── Compression │ ├── CountCompression.cs │ └── DeltaCompression.cs ├── Diagnostics │ └── MemoryMonitor.cs ├── Environment.cs ├── Extensions │ ├── ArrayExtensions.cs │ ├── ByteArrayExtensions.cs │ ├── DecimalExtensions.cs │ ├── ExpressionExtensions.cs │ ├── IEnumerableExtensions.cs │ ├── IListExtensions.cs │ ├── KeyValuePairExtensions.cs │ ├── ListExtensions.cs │ ├── SortedSetExtensions.cs │ ├── StopwatchExtensions.cs │ ├── StringExtensions.cs │ └── TypeExtensions.cs ├── IO │ ├── AtomicFile.cs │ ├── IOUtils.cs │ └── OptimizedFileStream.cs ├── Mathematics │ └── MathUtils.cs ├── Persist │ ├── BooleanIndexerPersist.cs │ ├── ByteArrayIndexerPersist.cs │ ├── DateTimeIndexerPersist.cs │ ├── FloatIndexerPersist.cs │ ├── IIndexerPersist.cs │ ├── IPersist.cs │ ├── IntegerIndexerPersist.cs │ ├── StringIndexerPersist.cs │ └── TimeSpanIndexerPersist.cs └── Threading │ └── Countdown.cs ├── Properties └── AssemblyInfo.cs ├── Remote ├── Commands │ ├── CommandCode.cs │ ├── CommandCollection.cs │ ├── CommandCollectionPersist.cs │ ├── CommandsPersist.Persist.cs │ ├── HeapCommands.cs │ ├── ICommand.cs │ ├── ICommandsPersist.cs │ ├── StorageEngineCommands.cs │ └── XTableCommands.cs ├── Descriptor.cs ├── Heap │ ├── HeapServer.cs │ ├── RemoteHeap.cs │ └── RemoteHeapCommands.cs ├── Message.cs ├── StorageEngineClient.cs ├── StorageEngineServer.cs └── XTableRemote.cs ├── STSdb4.csproj ├── Storage ├── AtomicHeader.cs ├── DirectoryHeap.cs ├── Heap.cs ├── Pointer.cs ├── Ptr.cs └── Space.cs └── WaterfallTree ├── IApply.cs ├── IDataContainer.cs ├── IDescriptor.cs ├── IHeap.cs ├── IOperation.cs ├── IOperationCollection.cs ├── IOperationCollectionFactory.cs ├── Locator.cs ├── Scheme.cs ├── SentinelPersistKey.cs ├── TypeCache.cs ├── TypeEngine.cs ├── WTree.Branch.Fall.cs ├── WTree.Branch.cs ├── WTree.BranchCache.cs ├── WTree.BranchCollection.cs ├── WTree.BranchesOptimizator.cs ├── WTree.FullKey.cs ├── WTree.Header.cs ├── WTree.InternalNode.Maintenance.cs ├── WTree.InternalNode.cs ├── WTree.LeafNode.cs ├── WTree.Node.cs └── WTree.cs /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment the next line if you want to checkin your web deploy settings 129 | # but database connection strings (with potential passwords) will be unencrypted 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages 134 | *.nupkg 135 | # The packages folder can be ignored because of Package Restore 136 | **/packages/* 137 | # except build/, which is used as an MSBuild target. 138 | !**/packages/build/ 139 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 140 | #!**/packages/repositories.config 141 | 142 | # Windows Azure Build Output 143 | csx/ 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | *.Cache 151 | ClientBin/ 152 | [Ss]tyle[Cc]op.* 153 | ~$* 154 | *~ 155 | *.dbmdl 156 | *.dbproj.schemaview 157 | *.pfx 158 | *.publishsettings 159 | node_modules/ 160 | 161 | # RIA/Silverlight projects 162 | Generated_Code/ 163 | 164 | # Backup & report files from converting an old project file 165 | # to a newer Visual Studio version. Backup files are not needed, 166 | # because we have git ;-) 167 | _UpgradeReport_Files/ 168 | Backup*/ 169 | UpgradeLog*.XML 170 | UpgradeLog*.htm 171 | 172 | # SQL Server files 173 | *.mdf 174 | *.ldf 175 | 176 | # Business Intelligence projects 177 | *.rdl.data 178 | *.bim.layout 179 | *.bim_*.settings 180 | 181 | # Microsoft Fakes 182 | FakesAssemblies/ 183 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STSSoft/STSdb4/490a6f8e75f7722c8725fadb57406626f68ed4e1/CHANGELOG.md -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # General rules 2 | 3 | 1. Make sure that there is a corresponding issue for your change first. If there is none, create one. 4 | 2. Create a fork in GitHub. 5 | 3. Create a branch of the master branch. Name it something that makes sense (for example: DatabaseConnectionIssue). This makes it easy for everyone to figure out what the branch is used for. 6 | 4. Log the changes you made in the CHANGELOG file, following the specified rules. 7 | 5. Commit your changes and push them to GitHub. 8 | 6. Create a pull request against the origin's master branch. 9 | 10 | # C# Coding Style 11 | 12 | The general rules we follow are "Visual Studio defaults". 13 | 14 | * We use Allman style braces, where each brace begins on a new line. A single line statement block can go without braces but the block must be properly indented on its own line and it must not be nested in other statement blocks that use. For example the following is allowed: 15 | ```C# 16 | foreach(var item in collection) 17 | Console.WriteLine(item.ToString()); 18 | ``` 19 | But this is not: 20 | ```C# 21 | foreach(var item in collection) Console.WriteLine(item.ToString()); 22 | ``` 23 | * We use four spaces of indentation (no tabs). 24 | * We use `camelCase` private members. We DO NOT use prefixes for instance fields. 25 | * We always specify the visibility, even if it's the default (i.e. `private string foo` not `string foo`). 26 | * Namespace imports should be specified at the top of the file, outside of namespace declarations and should be sorted alphabetically. Use Remove and Sort function of Visual Studio. 27 | * Avoid more than one empty line at any time. For example, do not have two blank lines between members of a type. 28 | * We only use `var `when it's obvious what the variable type is (i.e. `var stream = new MemoryStream()` not `var stream = GetStream()`). But we generally prefer using strongly typed variables. 29 | * We use language keywords instead of BCL types (i.e. `int, string, float` instead of `Int32, String, Single`, etc) for type references. For method calls we use the BCL types (i.e. `Int32.Parse instead of int.Parse`). 30 | * We use `PascalCasing` to name all our constant local variables and fields. 31 | * When writing comments, we follow a simple rule: every comment must begin with a capital letter and finish with a dot. Also, there is one interval between the `//` and the begining of the comment. Example: 32 | `// Insert comment here.` 33 | * If a file differs in style from these guidelines we will ask you to correct it. 34 | 35 | # Logging changes 36 | 37 | To make it easy tracking what has changed in every version of the application, we have included the CHANGELOG file. WE follow a small set of rules when logging the changes to the file. 38 | 39 | ## Keywords 40 | There are several keywords that we use to identify the type of the change that has been made: 41 | 42 | * ADDED - something has been added(a functionality, a new database implementation and etc.). Do not use this keyword just to indicate that a new file has been added. 43 | * CHANGED - something important has been changed (an implementation, an interface and etc.). 44 | * FIXED - an issue has been fixed. 45 | * IMPROVED - something has been improved (an implementation, a class architecture and etc.). 46 | * REMOVED - something has been removed. 47 | * UPDATED - something has been updated(usually a database binary). 48 | 49 | The keywords are in an alphabetical order and we use them in the CHANGELOG in the same way. 50 | 51 | ## File structure 52 | 53 | The changelog for a specific version beggins with the following header: 54 | 55 | `ver. X.X.X (unreleased/released)` 56 | 57 | After that follow the keywords indicating the changes (in alphabetical order). 58 | ``` 59 | ADDED 60 | CHANGED 61 | FIXED 62 | IMPROVED 63 | REMOVED 64 | UPDATED 65 | ``` 66 | 67 | It is not nessasary for every keyword to persist. Sometimes the changes do not include all of the specified types. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # STSdb 4.0 2 | 3 | STSdb 4.0 is a NoSQL key-value store open-source database with innovative indexing algorithm. The STSdb 4.0 engine is based on WaterfallTree technology which provides blazing performance in real-time indexing of both sequential and random keys, making STSdb 4.0 perfect for BigData and enterprise systems. 4 | 5 | # Key Features 6 | 7 | ## Innovative Technology 8 | The storage engine of STSdb 4.0 is based on an innovative data indexing structure called WaterfallTree. WaterfallTree is an algorithm that effectively solves one of the fundamental problems in the database world – speed degradation when indexing random keys. 9 | 10 | More about WaterfallTree: http://stssoft.com/technologies/waterfalltree/. 11 | 12 | ## Performance 13 | STSdb provides up to 100x increase in indexing speed and data procesing. 14 | 15 | * up to 6x increase compared to LSM-tree technology. 16 | * up to 10x increase compared to FractalTree technology. 17 | * up to 100x increase compared to B-tree technology. 18 | 19 | More about the performance: http://stssoft.com/products/stsdb-4-0/benchmark/. 20 | 21 | # Compression 22 | STSdb is not only faster, but more compact in size. In most of the cases it can achieve up to 4x better compression than competitive solutions thanks to fast parallel vertical compressions. 23 | 24 | ## BigData 25 | With its innovative WaterfallTree technology, STSdb 4.0 is the perfect choice for BigData. STSdb can be used as a scalable and versatile node for cloud computing and enterprise systems. 26 | 27 | More about STSdb and BigData: http://stssoft.com/products/stsdb-4-0/bigdata/. 28 | 29 | ## Simplicity 30 | STSdb 4.0 has the best designed API in the database world. Simplicity is beauty. 31 | 32 | Get started in fust a few minutes: http://docs.stsdb.com/display/stsdb404/Quick+Start. 33 | *** 34 | More about STSdb and our technologies: http://stssoft.com/ 35 | -------------------------------------------------------------------------------- /STSdb4.GettingStarted/Program.cs: -------------------------------------------------------------------------------- 1 | using DatabaseBenchmark; 2 | using STSdb4.Data; 3 | using STSdb4.Database; 4 | using STSdb4.General.Extensions; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Diagnostics; 9 | using System.IO; 10 | using System.Text; 11 | using STSdb4.Storage; 12 | using System.Globalization; 13 | using System.Threading; 14 | using STSdb4.WaterfallTree; 15 | using STSdb4.General.Collections; 16 | using STSdb4.General.Comparers; 17 | 18 | namespace STSdb4.GettingStarted 19 | { 20 | class Program 21 | { 22 | static void Main(string[] args) 23 | { 24 | Example(1000000, KeysType.Random); 25 | 26 | Console.ReadKey(); 27 | } 28 | 29 | private static void Example(int tickCount, KeysType keysType) 30 | { 31 | Stopwatch sw = new Stopwatch(); 32 | const string FILE_NAME = "test.stsdb4"; 33 | File.Delete(FILE_NAME); 34 | 35 | //insert 36 | Console.WriteLine("Inserting..."); 37 | sw.Reset(); 38 | sw.Start(); 39 | int c = 0; 40 | using (IStorageEngine engine = STSdb.FromFile(FILE_NAME)) 41 | { 42 | ITable table = engine.OpenXTable("table"); 43 | 44 | foreach (var kv in TicksGenerator.GetFlow(tickCount, keysType)) //generate random records 45 | { 46 | table[kv.Key] = kv.Value; 47 | 48 | c++; 49 | if (c % 100000 == 0) 50 | Console.WriteLine("Inserted {0} records", c); 51 | } 52 | 53 | engine.Commit(); 54 | } 55 | sw.Stop(); 56 | Console.WriteLine("Insert speed:{0} rec/sec", sw.GetSpeed(tickCount)); 57 | 58 | //read 59 | Console.WriteLine("Reading..."); 60 | sw.Reset(); 61 | sw.Start(); 62 | c = 0; 63 | using (IStorageEngine engine = STSdb.FromFile(FILE_NAME)) 64 | { 65 | ITable table = engine.OpenXTable("table"); 66 | 67 | foreach (var row in table) //table.Forward(), table.Backward() 68 | { 69 | //Console.WriteLine("{0} {1}", row.Key, row.Value); 70 | 71 | c++; 72 | if (c % 100000 == 0) 73 | Console.WriteLine("Read {0} records", c); 74 | } 75 | } 76 | sw.Stop(); 77 | Console.WriteLine("Read speed:{0} records", sw.GetSpeed(c)); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /STSdb4.GettingStarted/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("STSdb4.GettingStarted")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("STSdb4.GettingStarted")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f7c9c15b-650d-430a-a885-97906446fcd6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /STSdb4.GettingStarted/STSdb4.GettingStarted.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C796CD94-F2B4-4816-8525-3888C861096A} 8 | Exe 9 | Properties 10 | STSdb4.GettingStarted 11 | STSdb4.GettingStarted 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {be6c9ff2-7817-4ef4-bd8f-6f78126878d3} 55 | STSdb4 56 | 57 | 58 | 59 | 60 | 61 | 62 | 69 | -------------------------------------------------------------------------------- /STSdb4.GettingStarted/Tick.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace DatabaseBenchmark 7 | { 8 | public class Tick 9 | { 10 | public string Symbol { get; set; } 11 | public DateTime Timestamp { get; set; } 12 | public double Bid { get; set; } 13 | public double Ask { get; set; } 14 | public int BidSize { get; set; } 15 | public int AskSize { get; set; } 16 | public string Provider { get; set; } 17 | 18 | public Tick() 19 | { 20 | } 21 | 22 | public Tick(string symbol, DateTime time, double bid, double ask, int bidSize, int askSize, string provider) 23 | { 24 | Symbol = symbol; 25 | Timestamp = time; 26 | Bid = bid; 27 | Ask = ask; 28 | BidSize = bidSize; 29 | AskSize = askSize; 30 | Provider = provider; 31 | } 32 | 33 | public override string ToString() 34 | { 35 | return String.Format("{0};{1:yyyy-MM-dd HH:mm:ss};{2};{3};{4};{5};{6}", Symbol, Timestamp, Bid, Ask, BidSize, AskSize, Provider); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /STSdb4.GettingStarted/TicksGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace DatabaseBenchmark 8 | { 9 | public static class TicksGenerator 10 | { 11 | private static string[] symbols; 12 | private static int[] digits; 13 | private static double[] pipsizes; 14 | private static double[] prices; 15 | private static string[] providers; 16 | 17 | static TicksGenerator() 18 | { 19 | //2013-11-12 13:00 20 | var data = new string[] { "USDCHF;4;0.9197", "GBPUSD;4;1.5880", "EURUSD;4;1.3403", "USDJPY;2;99.73", "EURCHF;4;1.2324", "AUDBGN;4;1.3596", "AUDCHF;4;0.8567", "AUDJPY;2;92.96", 21 | "BGNJPY;2;68.31", "BGNUSD;4;0.6848", "CADBGN;4;1.3901", "CADCHF;4;0.8759", "CADUSD;4;0.9527", "CHFBGN;4;1.5862", "CHFJPY;2;108.44", "CHFUSD;4;1.0875", "EURAUD;4;1.4375", "EURCAD;4;1.4064", 22 | "EURGBP;4;0.8438", "EURJPY;4;133.66", "GBPAUD;4;1.7031", "GBPBGN;4;2.3169", "GBPCAD;4;1.6661", "GBPCHF;4;1.4603", "GBPJPY;2;158.37", "NZDUSD;4;0.8217", "USDBGN;4;1.4594", "USDCAD;4;1.0493", 23 | "XAUUSD;2;1281.15", "XAGUSD;2;21.21", "$DAX;2;9078.20","$FTSE;2;6707.49","$NASDAQ;2;3361.02","$SP500;2;1771.32"}; 24 | 25 | symbols = new string[data.Length]; 26 | digits = new int[data.Length]; 27 | pipsizes = new double[data.Length]; 28 | prices = new double[data.Length]; 29 | 30 | providers = new string[] { "eSignal", "Gain", "NYSE", "TSE", "NASDAQ", "Euronext", "LSE", "SSE", "ASE", "SE", "NSEI" }; 31 | 32 | var format = new NumberFormatInfo(); 33 | format.NumberDecimalSeparator = "."; 34 | 35 | for (int i = 0; i < data.Length; i++) 36 | { 37 | var tokens = data[i].Split(';'); //symbol;digits;price 38 | 39 | symbols[i] = tokens[0]; 40 | digits[i] = Int32.Parse(tokens[1]); 41 | pipsizes[i] = Math.Round(Math.Pow(10, -digits[i]), digits[i]); 42 | prices[i] = Math.Round(Double.Parse(tokens[2], format), digits[i]); 43 | } 44 | } 45 | 46 | public static IEnumerable> GetFlow(long number, KeysType keysType) 47 | { 48 | Random random = new Random((int)DateTime.Now.Ticks); 49 | 50 | //init startup prices 51 | var prices = TicksGenerator.prices.ToArray(); 52 | 53 | DateTime timestamp = DateTime.Now; 54 | 55 | //generate ticks 56 | for (long i = 0; i < number; i++) 57 | { 58 | int id = random.Next(symbols.Length); 59 | 60 | //random movement (Random Walk) 61 | int direction = random.Next() % 2 == 0 ? 1 : -1; 62 | int pips = random.Next(0, 10); 63 | int spread = random.Next(2, 30); 64 | int seconds = random.Next(1, 30); 65 | 66 | string symbol = symbols[id]; 67 | int d = digits[id]; 68 | double pipSize = pipsizes[id]; 69 | 70 | //generate values 71 | timestamp = timestamp.AddSeconds(seconds); 72 | double bid = Math.Round(prices[id] + direction * pips * pipSize, d); 73 | double ask = Math.Round(bid + spread * pipSize, d); 74 | int bidSize = random.Next(0, 10000); 75 | int askSize = random.Next(0, 10000); 76 | string provider = providers[random.Next(providers.Length)]; 77 | 78 | //create tick 79 | Tick tick = new Tick(symbol, timestamp, bid, ask, bidSize, askSize, provider); 80 | 81 | long key; 82 | if (keysType == KeysType.Sequential) 83 | key = i; 84 | else 85 | key = unchecked(random.Next() * (i + 1)); 86 | 87 | yield return new KeyValuePair(key, tick); 88 | 89 | prices[id] = bid; 90 | } 91 | } 92 | } 93 | 94 | public enum KeysType : byte 95 | { 96 | Sequential, 97 | Random 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /STSdb4.GettingStarted/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /STSdb4.Server/AboutBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Windows.Forms; 8 | 9 | namespace STSdb4.Server 10 | { 11 | partial class AboutBox : Form 12 | { 13 | public AboutBox() 14 | { 15 | InitializeComponent(); 16 | this.Text = String.Format("About {0}", AssemblyTitle); 17 | this.labelProductName.Text = AssemblyProduct; 18 | this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); 19 | this.labelCopyright.Text = AssemblyCopyright; 20 | this.labelCompanyName.Text = AssemblyCompany; 21 | this.textBoxDescription.Text = AssemblyDescription; 22 | } 23 | 24 | #region Assembly Attribute Accessors 25 | 26 | public string AssemblyTitle 27 | { 28 | get 29 | { 30 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); 31 | if (attributes.Length > 0) 32 | { 33 | AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; 34 | if (titleAttribute.Title != "") 35 | { 36 | return titleAttribute.Title; 37 | } 38 | } 39 | return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); 40 | } 41 | } 42 | 43 | public string AssemblyVersion 44 | { 45 | get 46 | { 47 | return Assembly.GetExecutingAssembly().GetName().Version.ToString(); 48 | } 49 | } 50 | 51 | public string AssemblyDescription 52 | { 53 | get 54 | { 55 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); 56 | if (attributes.Length == 0) 57 | { 58 | return ""; 59 | } 60 | return ((AssemblyDescriptionAttribute)attributes[0]).Description; 61 | } 62 | } 63 | 64 | public string AssemblyProduct 65 | { 66 | get 67 | { 68 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); 69 | if (attributes.Length == 0) 70 | { 71 | return ""; 72 | } 73 | return ((AssemblyProductAttribute)attributes[0]).Product; 74 | } 75 | } 76 | 77 | public string AssemblyCopyright 78 | { 79 | get 80 | { 81 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); 82 | if (attributes.Length == 0) 83 | { 84 | return ""; 85 | } 86 | return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; 87 | } 88 | } 89 | 90 | public string AssemblyCompany 91 | { 92 | get 93 | { 94 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); 95 | if (attributes.Length == 0) 96 | { 97 | return ""; 98 | } 99 | return ((AssemblyCompanyAttribute)attributes[0]).Company; 100 | } 101 | } 102 | #endregion 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /STSdb4.Server/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /STSdb4.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.ServiceProcess; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Threading; 8 | using STSdb4.Database; 9 | using STSdb4.Data; 10 | using STSdb4.Database.Operations; 11 | using STSdb4.WaterfallTree; 12 | using System.IO; 13 | using System.Configuration; 14 | using STSdb4.Remote; 15 | 16 | namespace STSdb4.Server 17 | { 18 | static class Program 19 | { 20 | internal static StorageEngineServer StorageEngineServer; 21 | /// 22 | /// The main entry point for the application. 23 | /// 24 | 25 | static void Main() 26 | { 27 | string serviceMode = ConfigurationSettings.AppSettings["ServiceMode"]; 28 | bool isService = bool.Parse(serviceMode); 29 | 30 | if (!isService) 31 | new STSdb4Service().Start(); 32 | else 33 | { 34 | ServiceBase[] ServicesToRun; 35 | ServicesToRun = new ServiceBase[] 36 | { 37 | new STSdb4Service() 38 | }; 39 | ServiceBase.Run(ServicesToRun); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /STSdb4.Server/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("STSdb4.Server")] 9 | [assembly: AssemblyDescription("STSdb 4.0 Server")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("STS Soft SC")] 12 | [assembly: AssemblyProduct("STSdb4.Server")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2d0a7af8-121a-4516-af81-745e1b61260b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /STSdb4.Server/STSdb4.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {110B1211-42C0-42DE-8D6D-3D0542130FAE} 8 | WinExe 9 | Properties 10 | STSdb4.Server 11 | STSdb4.Server 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Form 54 | 55 | 56 | AboutBox.cs 57 | 58 | 59 | Form 60 | 61 | 62 | MainForm.cs 63 | 64 | 65 | Component 66 | 67 | 68 | STSdb4Service.cs 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Designer 77 | 78 | 79 | 80 | 81 | {be6c9ff2-7817-4ef4-bd8f-6f78126878d3} 82 | STSdb4 83 | 84 | 85 | 86 | 87 | AboutBox.cs 88 | 89 | 90 | MainForm.cs 91 | Designer 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 106 | -------------------------------------------------------------------------------- /STSdb4.Server/STSdb4Service.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace STSdb4.Server 2 | { 3 | partial class STSdb4Service 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | components = new System.ComponentModel.Container(); 32 | this.ServiceName = "Service1"; 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /STSdb4.Server/STSdb4Service.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Database; 2 | using STSdb4.General.Communication; 3 | using STSdb4.Remote; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Configuration; 8 | using System.Data; 9 | using System.Diagnostics; 10 | using System.Linq; 11 | using System.ServiceProcess; 12 | using System.Text; 13 | using System.Threading; 14 | using System.Threading.Tasks; 15 | using System.Windows.Forms; 16 | 17 | namespace STSdb4.Server 18 | { 19 | public partial class STSdb4Service : ServiceBase 20 | { 21 | internal static STSdb4Service Service { get; private set; } 22 | private MainForm Form; 23 | private IStorageEngine StorageEngine; 24 | private TcpServer TcpServer; 25 | 26 | public STSdb4Service() 27 | { 28 | InitializeComponent(); 29 | } 30 | 31 | public void Start() 32 | { 33 | OnStart(new string[] { }); 34 | } 35 | 36 | protected override void OnStart(string[] args) 37 | { 38 | string FileName = ConfigurationSettings.AppSettings["FileName"]; 39 | int port = int.Parse(ConfigurationSettings.AppSettings["Port"]); 40 | int boundedCapacity = int.Parse(ConfigurationSettings.AppSettings["BoundedCapacity"]); 41 | Service = this; 42 | 43 | StorageEngine = STSdb.FromFile(FileName); 44 | TcpServer = new TcpServer(port); 45 | Program.StorageEngineServer = new StorageEngineServer(StorageEngine, TcpServer); 46 | Program.StorageEngineServer.Start(); 47 | 48 | Form = new MainForm(); 49 | Application.Run(Form); 50 | Program.StorageEngineServer.Stop(); 51 | StorageEngine.Close(); 52 | } 53 | 54 | protected override void OnStop() 55 | { 56 | if (Form != null) 57 | Form.Close(); 58 | if (StorageEngine != null) 59 | StorageEngine.Close(); 60 | if (Program.StorageEngineServer != null) 61 | Program.StorageEngineServer.Stop(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /STSdb4.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STSdb4.GettingStarted", "STSdb4.GettingStarted\STSdb4.GettingStarted.csproj", "{C796CD94-F2B4-4816-8525-3888C861096A}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STSdb4", "STSdb4\STSdb4.csproj", "{BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STSdb4.Server", "STSdb4.Server\STSdb4.Server.csproj", "{110B1211-42C0-42DE-8D6D-3D0542130FAE}" 9 | EndProject 10 | Global 11 | GlobalSection(SubversionScc) = preSolution 12 | Svn-Managed = True 13 | Manager = AnkhSVN - Subversion Support for Visual Studio 14 | EndGlobalSection 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {C796CD94-F2B4-4816-8525-3888C861096A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {C796CD94-F2B4-4816-8525-3888C861096A}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {C796CD94-F2B4-4816-8525-3888C861096A}.Debug|x64.ActiveCfg = Debug|Any CPU 27 | {C796CD94-F2B4-4816-8525-3888C861096A}.Debug|x86.ActiveCfg = Debug|Any CPU 28 | {C796CD94-F2B4-4816-8525-3888C861096A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C796CD94-F2B4-4816-8525-3888C861096A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {C796CD94-F2B4-4816-8525-3888C861096A}.Release|x64.ActiveCfg = Release|Any CPU 31 | {C796CD94-F2B4-4816-8525-3888C861096A}.Release|x86.ActiveCfg = Release|Any CPU 32 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Debug|x64.ActiveCfg = Debug|x64 35 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Debug|x64.Build.0 = Debug|x64 36 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Debug|x86.ActiveCfg = Debug|x86 37 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Debug|x86.Build.0 = Debug|x86 38 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Release|x64.ActiveCfg = Release|x64 41 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Release|x64.Build.0 = Release|x64 42 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Release|x86.ActiveCfg = Release|x86 43 | {BE6C9FF2-7817-4EF4-BD8F-6F78126878D3}.Release|x86.Build.0 = Release|x86 44 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Debug|x64.ActiveCfg = Debug|Any CPU 47 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Debug|x86.ActiveCfg = Debug|Any CPU 48 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Release|x64.ActiveCfg = Release|Any CPU 51 | {110B1211-42C0-42DE-8D6D-3D0542130FAE}.Release|x86.ActiveCfg = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | EndGlobal 57 | -------------------------------------------------------------------------------- /STSdb4/Data/Data.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.Data 7 | { 8 | public class Data : IData 9 | { 10 | public T Value; 11 | 12 | public Data() 13 | { 14 | } 15 | 16 | public Data(T value) 17 | { 18 | Value = value; 19 | } 20 | 21 | public override string ToString() 22 | { 23 | return Value.ToString(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /STSdb4/Data/DataComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Text; 7 | 8 | namespace STSdb4.Data 9 | { 10 | public class DataComparer : IComparer 11 | { 12 | public readonly Func compare; 13 | 14 | public readonly Type Type; 15 | public readonly Type DataType; 16 | public readonly CompareOption[] CompareOptions; 17 | public readonly Func MembersOrder; 18 | 19 | public DataComparer(Type type, CompareOption[] compareOptions, Func membersOrder = null) 20 | { 21 | Type = type; 22 | DataType = typeof(Data<>).MakeGenericType(type); 23 | 24 | CompareOption.CheckCompareOptions(type, compareOptions, membersOrder); 25 | CompareOptions = compareOptions; 26 | MembersOrder = membersOrder; 27 | 28 | compare = CreateCompareMethod().Compile(); 29 | } 30 | 31 | public DataComparer(Type type, Func membersOrder = null) 32 | : this(type, CompareOption.GetDefaultCompareOptions(type, membersOrder), membersOrder) 33 | { 34 | } 35 | 36 | public Expression> CreateCompareMethod() 37 | { 38 | var x = Expression.Parameter(typeof(IData)); 39 | var y = Expression.Parameter(typeof(IData)); 40 | 41 | List list = new List(); 42 | List parameters = new List(); 43 | 44 | var value1 = Expression.Variable(Type, "value1"); 45 | parameters.Add(value1); 46 | list.Add(Expression.Assign(value1, Expression.Convert(x, DataType).Value())); 47 | 48 | var value2 = Expression.Variable(Type, "value2"); 49 | parameters.Add(value2); 50 | list.Add(Expression.Assign(value2, Expression.Convert(y, DataType).Value())); 51 | 52 | return Expression.Lambda>(ComparerHelper.CreateComparerBody(list, parameters, value1, value2, CompareOptions, MembersOrder), x, y); 53 | } 54 | 55 | public int Compare(IData x, IData y) 56 | { 57 | return compare(x, y); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /STSdb4/Data/DataEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Text; 7 | using STSdb4.General.Extensions; 8 | using STSdb4.General.Comparers; 9 | 10 | namespace STSdb4.Data 11 | { 12 | public class DataEqualityComparer : IEqualityComparer 13 | { 14 | public readonly Func equals; 15 | public readonly Func getHashCode; 16 | 17 | public readonly Type Type; 18 | public readonly Func MembersOrder; 19 | public readonly CompareOption[] CompareOptions; 20 | 21 | public DataEqualityComparer(Type type, CompareOption[] compareOptions, Func membersOrder = null) 22 | { 23 | Type = type; 24 | CompareOption.CheckCompareOptions(type, compareOptions, membersOrder); 25 | CompareOptions = compareOptions; 26 | MembersOrder = membersOrder; 27 | 28 | equals = CreateEqualsMethod().Compile(); 29 | getHashCode = CreateGetHashCodeMethod().Compile(); 30 | } 31 | 32 | public DataEqualityComparer(Type type, Func membersOrder = null) 33 | : this(type, CompareOption.GetDefaultCompareOptions(type, membersOrder), membersOrder) 34 | { 35 | } 36 | 37 | public Expression> CreateEqualsMethod() 38 | { 39 | var x = Expression.Parameter(typeof(IData)); 40 | var y = Expression.Parameter(typeof(IData)); 41 | var xValue = Expression.Variable(Type); 42 | var yValue = Expression.Variable(Type); 43 | 44 | var dataType = typeof(Data<>).MakeGenericType(Type); 45 | 46 | var body = Expression.Block(typeof(bool), new ParameterExpression[] { xValue, yValue }, 47 | Expression.Assign(xValue, Expression.Convert(x, dataType).Value()), 48 | Expression.Assign(yValue, Expression.Convert(y, dataType).Value()), 49 | EqualityComparerHelper.CreateEqualsBody(xValue, yValue, CompareOptions, MembersOrder) 50 | ); 51 | var lambda = Expression.Lambda>(body, x, y); 52 | 53 | return lambda; 54 | } 55 | 56 | public Expression> CreateGetHashCodeMethod() 57 | { 58 | var obj = Expression.Parameter(typeof(IData)); 59 | var objValue = Expression.Variable(Type); 60 | 61 | var dataType = typeof(Data<>).MakeGenericType(Type); 62 | 63 | var body = Expression.Block(typeof(int), new ParameterExpression[] { objValue }, 64 | Expression.Assign(objValue, Expression.Convert(obj, dataType).Value()), 65 | EqualityComparerHelper.CreateGetHashCodeBody(objValue, MembersOrder) 66 | ); 67 | var lambda = Expression.Lambda>(body, obj); 68 | 69 | return lambda; 70 | } 71 | 72 | public bool Equals(IData x, IData y) 73 | { 74 | return equals(x, y); 75 | } 76 | 77 | public int GetHashCode(IData obj) 78 | { 79 | return getHashCode(obj); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /STSdb4/Data/DataExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | 7 | namespace STSdb4.Data 8 | { 9 | public static class DataExtensions 10 | { 11 | public static Expression Value(this Expression data) 12 | { 13 | return Expression.Field(data, "Value"); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /STSdb4/Data/DataPersist.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Persist; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Reflection; 10 | 11 | namespace STSdb4.Data 12 | { 13 | public class DataPersist : IPersist 14 | { 15 | public readonly Action write; 16 | public readonly Func read; 17 | 18 | public readonly Type Type; 19 | public readonly Func MembersOrder; 20 | public readonly AllowNull AllowNull; 21 | 22 | public DataPersist(Type type, Func membersOrder = null, AllowNull allowNull = AllowNull.None) 23 | { 24 | Type = type; 25 | MembersOrder = membersOrder; 26 | AllowNull = allowNull; 27 | 28 | write = CreateWriteMethod().Compile(); 29 | read = CreateReadMethod().Compile(); 30 | } 31 | 32 | public void Write(BinaryWriter writer, IData item) 33 | { 34 | write(writer, item); 35 | } 36 | 37 | public IData Read(BinaryReader reader) 38 | { 39 | return read(reader); 40 | } 41 | 42 | public Expression> CreateWriteMethod() 43 | { 44 | var writer = Expression.Parameter(typeof(BinaryWriter), "writer"); 45 | var idata = Expression.Parameter(typeof(IData), "idata"); 46 | 47 | var dataType = typeof(Data<>).MakeGenericType(Type); 48 | var dataValue = Expression.Variable(Type, "dataValue"); 49 | 50 | var assign = Expression.Assign(dataValue, Expression.Convert(idata, dataType).Value()); 51 | 52 | return Expression.Lambda>(Expression.Block(new ParameterExpression[] { dataValue }, assign, PersistHelper.CreateWriteBody(dataValue, writer, MembersOrder, AllowNull)), writer, idata); 53 | } 54 | 55 | public Expression> CreateReadMethod() 56 | { 57 | var reader = Expression.Parameter(typeof(BinaryReader), "reader"); 58 | 59 | var dataType = typeof(Data<>).MakeGenericType(Type); 60 | 61 | return Expression.Lambda>( 62 | Expression.Label(Expression.Label(dataType), Expression.New(dataType.GetConstructor(new Type[] { Type }), PersistHelper.CreateReadBody(reader, Type, MembersOrder, AllowNull))), 63 | reader 64 | ); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /STSdb4/Data/DataToObjects.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Text; 7 | using STSdb4.General.Extensions; 8 | 9 | namespace STSdb4.Data 10 | { 11 | public class DataToObjects : IToObjects 12 | { 13 | public readonly Func to; 14 | public readonly Func from; 15 | 16 | public readonly Type Type; 17 | public readonly Func MembersOrder; 18 | 19 | public DataToObjects(Type type, Func membersOrder = null) 20 | { 21 | if (!DataType.IsPrimitiveType(type) && !type.HasDefaultConstructor()) 22 | throw new NotSupportedException("No default constructor."); 23 | 24 | bool isSupported = DataTypeUtils.IsAllPrimitive(type); 25 | if (!isSupported) 26 | throw new NotSupportedException("Not all types are primitive."); 27 | 28 | Type = type; 29 | MembersOrder = membersOrder; 30 | 31 | to = CreateToMethod().Compile(); 32 | from = CreateFromMethod().Compile(); 33 | } 34 | 35 | public Expression> CreateToMethod() 36 | { 37 | var data = Expression.Parameter(typeof(IData), "data"); 38 | 39 | var d = Expression.Variable(typeof(Data<>).MakeGenericType(Type), "d"); 40 | var body = Expression.Block(new ParameterExpression[] { d }, Expression.Assign(d, Expression.Convert(data, d.Type)), ValueToObjectsHelper.ToObjects(d.Value(), MembersOrder)); 41 | 42 | return Expression.Lambda>(body, data); 43 | } 44 | 45 | public Expression> CreateFromMethod() 46 | { 47 | var objectArray = Expression.Parameter(typeof(object[]), "item"); 48 | var data = Expression.Variable(typeof(Data<>).MakeGenericType(Type)); 49 | 50 | List list = new List(); 51 | list.Add(Expression.Assign(data, Expression.New(data.Type.GetConstructor(new Type[] { })))); 52 | 53 | if (!DataType.IsPrimitiveType(Type)) 54 | list.Add(Expression.Assign(data.Value(), Expression.New(data.Value().Type.GetConstructor(new Type[] { })))); 55 | 56 | list.Add(ValueToObjectsHelper.FromObjects(data.Value(), objectArray, MembersOrder)); 57 | list.Add(Expression.Label(Expression.Label(typeof(IData)), data)); 58 | 59 | var body = Expression.Block(typeof(IData), new ParameterExpression[] { data }, list); 60 | 61 | return Expression.Lambda>(body, objectArray); 62 | } 63 | 64 | public object[] To(IData value1) 65 | { 66 | return to(value1); 67 | } 68 | 69 | public IData From(object[] value2) 70 | { 71 | return from(value2); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /STSdb4/Data/DataToString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | using STSdb4.General.Extensions; 7 | using System.Reflection; 8 | 9 | namespace STSdb4.Data 10 | { 11 | public class DataToString : IToString 12 | { 13 | public readonly Func to; 14 | public readonly Func from; 15 | 16 | public readonly Type Type; 17 | public readonly int StringBuilderCapacity; 18 | public readonly IFormatProvider[] Providers; 19 | public readonly char[] Delimiters; 20 | public readonly Func MembersOrder; 21 | 22 | public DataToString(Type type, int stringBuilderCapacity, IFormatProvider[] providers, char[] delimiters, Func membersOrder = null) 23 | { 24 | Type = type; 25 | StringBuilderCapacity = stringBuilderCapacity; 26 | var typeCount = DataType.IsPrimitiveType(type) ? 1 : DataTypeUtils.GetPublicMembers(type, membersOrder).Count(); 27 | if (providers.Length != typeCount) 28 | throw new ArgumentException("providers.Length != dataType.Length"); 29 | 30 | Providers = providers; 31 | Delimiters = delimiters; 32 | MembersOrder = membersOrder; 33 | 34 | to = CreateToMethod().Compile(); 35 | from = CreateFromMethod().Compile(); 36 | } 37 | 38 | public DataToString(Type type, int stringBuilderCapacity, char[] delimiters, Func membersOrder = null) 39 | : this(type, stringBuilderCapacity, ValueToStringHelper.GetDefaultProviders(type, membersOrder), delimiters, membersOrder) 40 | { 41 | } 42 | 43 | public DataToString(Type type, Func membersOrder = null) 44 | : this(type, 16, new char[] { ';' }, membersOrder) 45 | { 46 | } 47 | 48 | public Expression> CreateToMethod() 49 | { 50 | var data = Expression.Parameter(typeof(IData), "data"); 51 | var d = Expression.Variable(typeof(Data<>).MakeGenericType(Type), "d"); 52 | 53 | List list = new List(); 54 | list.Add(Expression.Assign(d, Expression.Convert(data, typeof(Data<>).MakeGenericType(Type)))); 55 | list.Add(ValueToStringHelper.CreateToStringBody(d.Value(), StringBuilderCapacity, Providers, Delimiters[0], MembersOrder)); 56 | 57 | var body = Expression.Block(new ParameterExpression[] { d }, list); 58 | 59 | return Expression.Lambda>(body, data); 60 | } 61 | 62 | public Expression> CreateFromMethod() 63 | { 64 | var stringParam = Expression.Parameter(typeof(string), "item"); 65 | List list = new List(); 66 | 67 | var data = Expression.Variable(typeof(Data<>).MakeGenericType(Type), "d"); 68 | 69 | list.Add(Expression.Assign(data, Expression.New(data.Type.GetConstructor(new Type[] { })))); 70 | 71 | if (!DataType.IsPrimitiveType(Type)) 72 | list.Add(Expression.Assign(data.Value(), Expression.New(Type.GetConstructor(new Type[] { })))); 73 | 74 | list.Add(ValueToStringHelper.CreateParseBody(data.Value(), stringParam, Providers, Delimiters, MembersOrder)); 75 | list.Add(Expression.Label(Expression.Label(typeof(Data<>).MakeGenericType(Type)), data)); 76 | 77 | var body = Expression.Block(new ParameterExpression[] { data }, list); 78 | 79 | return Expression.Lambda>(body, new ParameterExpression[] { stringParam }); 80 | } 81 | 82 | public string To(IData value1) 83 | { 84 | return to(value1); 85 | } 86 | 87 | public IData From(string value2) 88 | { 89 | return from(value2); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /STSdb4/Data/IData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.Data 7 | { 8 | public interface IData 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /STSdb4/Data/IToObjects.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.Data 7 | { 8 | public interface IToObjects : ITransformer 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /STSdb4/Data/IToString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.Data 7 | { 8 | public interface IToString : ITransformer 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /STSdb4/Data/ITransformer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.Data 7 | { 8 | public interface ITransformer 9 | { 10 | T2 To(T1 value1); 11 | T1 From(T2 value2); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /STSdb4/Data/ValueToObjects.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | using STSdb4.General.Extensions; 7 | using System.Reflection; 8 | 9 | namespace STSdb4.Data 10 | { 11 | public class ValueToObjects : IToObjects 12 | { 13 | public readonly Func from; 14 | public readonly Func to; 15 | 16 | public readonly Type Type; 17 | public readonly Func MembersOrder; 18 | 19 | public ValueToObjects(Func membersOrder = null) 20 | { 21 | if (!DataType.IsPrimitiveType(typeof(T)) && !typeof(T).HasDefaultConstructor()) 22 | throw new NotSupportedException("No default constructor."); 23 | 24 | bool isSupported = DataTypeUtils.IsAllPrimitive(typeof(T)); 25 | if (!isSupported) 26 | throw new NotSupportedException("Not all types are primitive."); 27 | 28 | Type = typeof(T); 29 | MembersOrder = membersOrder; 30 | 31 | to = CreateToMethod().Compile(); 32 | from = CreateFromMethod().Compile(); 33 | } 34 | 35 | public Expression> CreateToMethod() 36 | { 37 | var item = Expression.Parameter(Type); 38 | 39 | return Expression.Lambda>(ValueToObjectsHelper.ToObjects(item, MembersOrder), item); 40 | } 41 | 42 | public Expression> CreateFromMethod() 43 | { 44 | var objectArray = Expression.Parameter(typeof(object[]), "item"); 45 | var item = Expression.Variable(Type); 46 | List list = new List(); 47 | 48 | if (!DataType.IsPrimitiveType(Type)) 49 | list.Add(Expression.Assign(item, Expression.New(item.Type.GetConstructor(new Type[] { })))); 50 | 51 | list.Add(ValueToObjectsHelper.FromObjects(item, objectArray, MembersOrder)); 52 | list.Add(Expression.Label(Expression.Label(typeof(T)), item)); 53 | 54 | var body = Expression.Block(typeof(T), new ParameterExpression[] { item }, list); 55 | 56 | return Expression.Lambda>(body, objectArray); 57 | } 58 | 59 | public object[] To(T value1) 60 | { 61 | return to(value1); 62 | } 63 | 64 | public T From(object[] value2) 65 | { 66 | return from(value2); 67 | } 68 | } 69 | 70 | public static class ValueToObjectsHelper 71 | { 72 | public static Expression ToObjects(Expression item, Func membersOrder) 73 | { 74 | Type[] types = DataType.IsPrimitiveType(item.Type) ? new Type[] { item.Type } : DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Select(x => x.GetPropertyOrFieldType()).ToArray(); 75 | 76 | if (types.Length == 1) 77 | return Expression.NewArrayInit(typeof(object), Expression.Convert(item, typeof(object))); 78 | 79 | Expression[] values = new Expression[types.Length]; 80 | int i = 0; 81 | 82 | foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder)) 83 | values[i++] = Expression.Convert(Expression.PropertyOrField(item, member.Name), typeof(object)); 84 | 85 | return Expression.NewArrayInit(typeof(object), values); 86 | } 87 | 88 | public static Expression FromObjects(Expression item, ParameterExpression objectArray, Func membersOrder) 89 | { 90 | Type[] types = DataType.IsPrimitiveType(item.Type) ? new Type[] { item.Type } : DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Select(x => x.GetPropertyOrFieldType()).ToArray(); 91 | 92 | if (types.Length == 1) 93 | return Expression.Assign(item, Expression.Convert(Expression.ArrayAccess(objectArray, Expression.Constant(0, typeof(int))), types[0])); 94 | 95 | List list = new List(); 96 | int i = 0; 97 | foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder)) 98 | list.Add(Expression.Assign(Expression.PropertyOrField(item, member.Name), Expression.Convert(Expression.ArrayAccess(objectArray, Expression.Constant(i, typeof(int))), types[i++]))); 99 | 100 | return Expression.Block(list); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /STSdb4/Database/IStorageEngine.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.WaterfallTree; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace STSdb4.Database 10 | { 11 | public interface IStorageEngine : IEnumerable, IDisposable 12 | { 13 | /// 14 | /// Works with anonymous types. 15 | /// 16 | ITable OpenXTablePortable(string name, DataType keyDataType, DataType recordDataType); 17 | 18 | /// 19 | /// Works with portable types via custom transformers. 20 | /// 21 | ITable OpenXTablePortable(string name, DataType keyDataType, DataType recordDataType, ITransformer keyTransformer, ITransformer recordTransformer); 22 | 23 | /// 24 | /// Works with anonymous types via default transformers. 25 | /// 26 | ITable OpenXTablePortable(string name); 27 | 28 | /// 29 | /// Works with the user types directly. 30 | /// 31 | ITable OpenXTable(string name); 32 | 33 | /// 34 | /// 35 | /// 36 | XFile OpenXFile(string name); 37 | 38 | IDescriptor this[string name] { get; } 39 | IDescriptor Find(long id); 40 | 41 | void Delete(string name); 42 | void Rename(string name, string newName); 43 | bool Exists(string name); 44 | 45 | /// 46 | /// The number of tables & virtual files into the storage engine. 47 | /// 48 | int Count { get; } 49 | 50 | /// 51 | /// The number of nodes that are kept in memory. 52 | /// 53 | int CacheSize { get; set; } 54 | 55 | /// 56 | /// Heap assigned to the StorageEngine instance. 57 | /// 58 | IHeap Heap { get; } 59 | 60 | void Commit(); 61 | void Close(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /STSdb4/Database/ITable.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.WaterfallTree; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.Database 8 | { 9 | public interface ITable 10 | { 11 | } 12 | 13 | public interface ITable : ITable, IEnumerable> 14 | { 15 | TRecord this[TKey key] { get; set; } 16 | 17 | void Replace(TKey key, TRecord record); 18 | void InsertOrIgnore(TKey key, TRecord record); 19 | void Delete(TKey key); 20 | void Delete(TKey fromKey, TKey toKey); 21 | void Clear(); 22 | 23 | bool Exists(TKey key); 24 | bool TryGet(TKey key, out TRecord record); 25 | TRecord Find(TKey key); 26 | TRecord TryGetOrDefault(TKey key, TRecord defaultRecord); 27 | 28 | KeyValuePair? FindNext(TKey key); 29 | KeyValuePair? FindAfter(TKey key); 30 | KeyValuePair? FindPrev(TKey key); 31 | KeyValuePair? FindBefore(TKey key); 32 | 33 | IEnumerable> Forward(); 34 | IEnumerable> Forward(TKey from, bool hasFrom, TKey to, bool hasTo); 35 | IEnumerable> Backward(); 36 | IEnumerable> Backward(TKey to, bool hasTo, TKey from, bool hasFrom); 37 | 38 | KeyValuePair FirstRow { get; } 39 | KeyValuePair LastRow { get; } 40 | 41 | IDescriptor Descriptor { get; } 42 | 43 | long Count(); 44 | } 45 | } -------------------------------------------------------------------------------- /STSdb4/Database/OperationCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.Database.Operations; 6 | using STSdb4.WaterfallTree; 7 | using System.Collections; 8 | using STSdb4.Data; 9 | using System.Diagnostics; 10 | using STSdb4.General.Extensions; 11 | 12 | namespace STSdb4.Database 13 | { 14 | public class OperationCollection : List, IOperationCollection 15 | { 16 | public IOperation[] Array 17 | { 18 | get { return this.GetArray(); } 19 | } 20 | 21 | public OperationCollection(Locator locator, IOperation[] operations, int commonAction, bool areAllMonotoneAndPoint) 22 | { 23 | this.SetArray(operations); 24 | this.SetCount(operations.Length); 25 | 26 | Locator = locator; 27 | CommonAction = commonAction; 28 | AreAllMonotoneAndPoint = areAllMonotoneAndPoint; 29 | } 30 | 31 | public OperationCollection(Locator locator, int capacity) 32 | : base(capacity) 33 | { 34 | Locator = locator; 35 | CommonAction = OperationCode.UNDEFINED; 36 | AreAllMonotoneAndPoint = true; 37 | } 38 | 39 | public new void Add(IOperation operation) 40 | { 41 | if (AreAllMonotoneAndPoint) 42 | { 43 | if (Count == 0) 44 | { 45 | AreAllMonotoneAndPoint = operation.Scope == OperationScope.Point; 46 | CommonAction = operation.Code; 47 | } 48 | else 49 | { 50 | if (operation.Scope != OperationScope.Point || Locator.KeyComparer.Compare(operation.FromKey, this[Count - 1].FromKey) <= 0) 51 | AreAllMonotoneAndPoint = false; 52 | } 53 | } 54 | 55 | if (CommonAction != OperationCode.UNDEFINED && CommonAction != operation.Code) 56 | CommonAction = OperationCode.UNDEFINED; 57 | 58 | base.Add(operation); 59 | } 60 | 61 | public void AddRange(IOperationCollection operations) 62 | { 63 | if (!operations.AreAllMonotoneAndPoint) 64 | AreAllMonotoneAndPoint = false; 65 | else 66 | { 67 | if (AreAllMonotoneAndPoint && this.Count > 0 && operations.Count > 0 && Locator.KeyComparer.Compare(this[Count - 1].FromKey, operations[0].FromKey) >= 0) 68 | AreAllMonotoneAndPoint = false; 69 | } 70 | 71 | if (operations.CommonAction != this.CommonAction) 72 | { 73 | if (this.Count == 0) 74 | this.CommonAction = operations.CommonAction; 75 | else if (operations.Count > 0) 76 | this.CommonAction = OperationCode.UNDEFINED; 77 | } 78 | 79 | var oprs = operations as OperationCollection; 80 | 81 | if (oprs != null) 82 | this.AddRange(oprs.Array, 0, oprs.Count); 83 | else 84 | { 85 | foreach (var o in operations) 86 | Add(o); 87 | } 88 | } 89 | 90 | public new void Clear() 91 | { 92 | base.Clear(); 93 | CommonAction = OperationCode.UNDEFINED; 94 | AreAllMonotoneAndPoint = true; 95 | } 96 | 97 | public IOperationCollection Midlle(int index, int count) 98 | { 99 | IOperation[] array = new IOperation[count]; 100 | System.Array.Copy(Array, index, array, 0, count); 101 | 102 | return new OperationCollection(Locator, array, CommonAction, AreAllMonotoneAndPoint); 103 | } 104 | 105 | public int BinarySearch(IData key, int index, int count) 106 | { 107 | Debug.Assert(AreAllMonotoneAndPoint); 108 | 109 | int low = index; 110 | int high = index + count - 1; 111 | 112 | var comparer = Locator.KeyComparer; 113 | 114 | while (low <= high) 115 | { 116 | int mid = (low + high) >> 1; 117 | int cmp = comparer.Compare(this[mid].FromKey, key); 118 | 119 | if (cmp == 0) 120 | return mid; 121 | if (cmp < 0) 122 | low = mid + 1; 123 | else 124 | high = mid - 1; 125 | } 126 | 127 | return ~low; 128 | } 129 | 130 | public int CommonAction { get; private set; } 131 | public bool AreAllMonotoneAndPoint { get; private set; } 132 | 133 | public Locator Locator { get; private set; } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /STSdb4/Database/OperationCollectionFactory.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.WaterfallTree; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.Database 8 | { 9 | public class OperationCollectionFactory : IOperationCollectionFactory 10 | { 11 | public readonly Locator Locator; 12 | 13 | public OperationCollectionFactory(Locator locator) 14 | { 15 | Locator = locator; 16 | } 17 | 18 | public IOperationCollection Create(int capacity) 19 | { 20 | return new OperationCollection(Locator, capacity); 21 | } 22 | 23 | public IOperationCollection Create(IOperation[] operations, int commonAction, bool areAllMonotoneAndPoint) 24 | { 25 | return new OperationCollection(Locator, operations, commonAction, areAllMonotoneAndPoint); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /STSdb4/Database/Operations/OperationCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.WaterfallTree; 6 | using STSdb4.Data; 7 | 8 | namespace STSdb4.Database.Operations 9 | { 10 | public static class OperationCode 11 | { 12 | public const int UNDEFINED = 0; 13 | 14 | //XIndex 15 | public const int REPLACE = 1; 16 | public const int INSERT_OR_IGNORE = 2; 17 | public const int DELETE = 3; 18 | public const int DELETE_RANGE = 4; 19 | public const int CLEAR = 5; 20 | 21 | public const int MAX = 256; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /STSdb4/Database/Operations/OverallOperations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.WaterfallTree; 6 | using STSdb4.Data; 7 | 8 | namespace STSdb4.Database.Operations 9 | { 10 | public abstract class OverallOperation : IOperation 11 | { 12 | public OverallOperation(int action) 13 | { 14 | Code = action; 15 | } 16 | 17 | public int Code { get; private set; } 18 | 19 | public OperationScope Scope 20 | { 21 | get { return OperationScope.Overall; } 22 | } 23 | 24 | public IData FromKey 25 | { 26 | get { return null; } 27 | } 28 | 29 | public IData ToKey 30 | { 31 | get { return null; } 32 | } 33 | } 34 | 35 | public class ClearOperation : OverallOperation 36 | { 37 | public ClearOperation() 38 | : base(OperationCode.CLEAR) 39 | { 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /STSdb4/Database/Operations/PointOperations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.WaterfallTree; 6 | using System.Threading; 7 | using STSdb4.Data; 8 | 9 | namespace STSdb4.Database.Operations 10 | { 11 | public abstract class PointOperation : IOperation 12 | { 13 | private readonly IData key; 14 | 15 | protected PointOperation(int action, IData key) 16 | { 17 | Code = action; 18 | this.key = key; 19 | } 20 | 21 | public int Code { get; private set; } 22 | 23 | public OperationScope Scope 24 | { 25 | get { return OperationScope.Point; } 26 | } 27 | 28 | public IData FromKey 29 | { 30 | get { return key; } 31 | } 32 | 33 | public IData ToKey 34 | { 35 | get { return key; } 36 | } 37 | 38 | public override string ToString() 39 | { 40 | return ToKey.ToString(); 41 | } 42 | } 43 | 44 | public class DeleteOperation : PointOperation 45 | { 46 | public DeleteOperation(IData key) 47 | : base(OperationCode.DELETE, key) 48 | { 49 | } 50 | } 51 | 52 | public abstract class ValueOperation : PointOperation 53 | { 54 | public IData Record; 55 | 56 | public ValueOperation(int action, IData key, IData record) 57 | : base(action, key) 58 | { 59 | Record = record; 60 | } 61 | } 62 | 63 | public class ReplaceOperation : ValueOperation 64 | { 65 | public ReplaceOperation(IData key, IData record) 66 | : base(OperationCode.REPLACE, key, record) 67 | { 68 | } 69 | } 70 | 71 | public class InsertOrIgnoreOperation : ValueOperation 72 | { 73 | public InsertOrIgnoreOperation(IData key, IData record) 74 | : base(OperationCode.INSERT_OR_IGNORE, key, record) 75 | { 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /STSdb4/Database/Operations/RangeOperations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.WaterfallTree; 6 | using STSdb4.Data; 7 | using STSdb4.General.Collections; 8 | 9 | namespace STSdb4.Database.Operations 10 | { 11 | public abstract class RangeOperation : IOperation 12 | { 13 | private readonly IData from; 14 | private readonly IData to; 15 | 16 | protected RangeOperation(int action, IData from, IData to) 17 | { 18 | Code = action; 19 | this.from = from; 20 | this.to = to; 21 | } 22 | 23 | protected RangeOperation(int action) 24 | { 25 | Code = action; 26 | } 27 | 28 | public int Code { get; private set; } 29 | 30 | public OperationScope Scope 31 | { 32 | get { return OperationScope.Range; } 33 | } 34 | 35 | public IData FromKey 36 | { 37 | get { return from; } 38 | } 39 | 40 | public IData ToKey 41 | { 42 | get { return to; } 43 | } 44 | } 45 | 46 | public class DeleteRangeOperation : RangeOperation 47 | { 48 | public DeleteRangeOperation(IData from, IData to) 49 | : base(OperationCode.DELETE_RANGE, from, to) 50 | { 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /STSdb4/Database/Operations/ResultOperation.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.General.Collections; 3 | using STSdb4.WaterfallTree; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace STSdb4.Database.Operations 10 | { 11 | 12 | public class TryGet_Result : PointOperation 13 | { 14 | public readonly IData Record; 15 | public readonly bool Exist; 16 | 17 | public TryGet_Result(IData key, IData record, bool exist) 18 | : base(OperationAction.TRY_GET_RESULT, key) 19 | { 20 | Record = record; 21 | Exist = exist; 22 | } 23 | } 24 | 25 | public class ForwardOperation_Result : RangeOperation 26 | { 27 | public readonly IEnumerable> Set; 28 | public readonly int Count; 29 | 30 | public ForwardOperation_Result(IData from, int count, IEnumerable> set) 31 | : base(OperationAction.FORWARD_RESULT, from, from) 32 | { 33 | Count = count; 34 | Set = set; 35 | } 36 | } 37 | 38 | public class BackwardOperation_Result : RangeOperation 39 | { 40 | public readonly IEnumerable> Set; 41 | public readonly int Count; 42 | 43 | public BackwardOperation_Result(IData from, int count, IEnumerable> set) 44 | : base(OperationAction.BACKWARD_RESULT, from, from) 45 | { 46 | Count = count; 47 | Set = set; 48 | } 49 | } 50 | 51 | public class CountOperation_Result : OverallOperation 52 | { 53 | public readonly long Count; 54 | 55 | public CountOperation_Result(long count) 56 | : base(OperationAction.COUNT_RESULT) 57 | { 58 | Count = count; 59 | } 60 | } 61 | 62 | public class ExceptionOperation_Result : OverallOperation 63 | { 64 | public readonly string Excetion; 65 | 66 | public ExceptionOperation_Result(string exception) 67 | : base(OperationAction.EXCETION_RESULT) 68 | { 69 | Excetion = exception; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /STSdb4/Database/OrderedSetFactory.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.General.Collections; 3 | using STSdb4.WaterfallTree; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace STSdb4.Database 10 | { 11 | public class OrderedSetFactory : IOrderedSetFactory 12 | { 13 | public Locator Locator { get; private set; } 14 | 15 | public OrderedSetFactory(Locator locator) 16 | { 17 | Locator = locator; 18 | } 19 | 20 | public IOrderedSet Create() 21 | { 22 | var data = new OrderedSet(Locator.KeyComparer, Locator.KeyEqualityComparer); 23 | 24 | return data; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /STSdb4/Database/STSdb.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Communication; 2 | using STSdb4.General.IO; 3 | using STSdb4.Remote; 4 | using STSdb4.Storage; 5 | using STSdb4.WaterfallTree; 6 | using System; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | 11 | namespace STSdb4.Database 12 | { 13 | public static class STSdb 14 | { 15 | public static IStorageEngine FromHeap(IHeap heap) 16 | { 17 | return new StorageEngine(heap); 18 | } 19 | 20 | public static IStorageEngine FromStream(Stream stream) 21 | { 22 | IHeap heap = new Heap(stream, false, AllocationStrategy.FromTheCurrentBlock); 23 | 24 | return FromHeap(heap); 25 | } 26 | 27 | public static IStorageEngine FromMemory() 28 | { 29 | var stream = new MemoryStream(); 30 | 31 | return FromStream(stream); 32 | } 33 | 34 | public static IStorageEngine FromFile(string fileName) 35 | { 36 | var stream = new OptimizedFileStream(fileName, FileMode.OpenOrCreate); 37 | 38 | return STSdb.FromStream(stream); 39 | } 40 | 41 | public static IStorageEngine FromNetwork(string host, int port = 7182) 42 | { 43 | return new StorageEngineClient(host, port); 44 | } 45 | 46 | public static StorageEngineServer CreateServer(IStorageEngine engine, int port = 7182) 47 | { 48 | TcpServer server = new TcpServer(port); 49 | StorageEngineServer engineServer = new StorageEngineServer(engine, server); 50 | 51 | return engineServer; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /STSdb4/Database/StructureType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.Database 7 | { 8 | public static class StructureType 9 | { 10 | //do not change 11 | public const int RESERVED = 0; 12 | 13 | public const int XTABLE = 1; 14 | public const int XFILE = 2; 15 | 16 | public static bool IsValid(int type) 17 | { 18 | if (type == XTABLE || type == XFILE) 19 | return true; 20 | 21 | return false; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /STSdb4/Database/XFile.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using System; 3 | 4 | namespace STSdb4.Database 5 | { 6 | public class XFile : XStream 7 | { 8 | internal XFile(ITable table) 9 | : base(table) 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /STSdb4/Doc/STSdb4.DevelopersGuide.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STSSoft/STSdb4/490a6f8e75f7722c8725fadb57406626f68ed4e1/STSdb4/Doc/STSdb4.DevelopersGuide.docx -------------------------------------------------------------------------------- /STSdb4/Doc/STSdb4.GettingStarted.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STSSoft/STSdb4/490a6f8e75f7722c8725fadb57406626f68ed4e1/STSdb4/Doc/STSdb4.GettingStarted.docx -------------------------------------------------------------------------------- /STSdb4/General/Buffers/BitUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | namespace STSdb4.General.Buffers 9 | { 10 | public static class BitUtils 11 | { 12 | private const int CACHE_SIZE = 2048; //2^11 13 | 14 | private static int[] cache = new int[CACHE_SIZE]; 15 | 16 | static BitUtils() 17 | { 18 | for (int i = 0; i < CACHE_SIZE; i++) 19 | cache[i] = GetBitBoundsClassic((ulong)i); 20 | } 21 | 22 | private static int GetBitBoundsClassic(ulong value) 23 | { 24 | return (value > 0) ? (int)Math.Ceiling(Math.Log(value + 1.0, 2)) : 1; 25 | } 26 | 27 | public static int GetBitBounds(ulong value) 28 | { 29 | int bits = 0; 30 | 31 | while (value >= CACHE_SIZE) //2^11 32 | { 33 | value = value >> 11; 34 | bits += 11; 35 | } 36 | 37 | return bits + cache[value]; 38 | } 39 | 40 | public static int GetBit(byte map, int bitIndex) 41 | { 42 | return (map >> (bitIndex & 7)) & 1; 43 | } 44 | 45 | public static byte SetBit(byte map, int bitIndex, int value) 46 | { 47 | int bitMask = 1 << (bitIndex & 7); 48 | if (value != 0) 49 | return map |= (byte)bitMask; 50 | else 51 | return map &= (byte)(~bitMask); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /STSdb4/General/Collections/IOrderedSet.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Persist; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace STSdb4.General.Collections 9 | { 10 | public interface IOrderedSet : IEnumerable> 11 | { 12 | IComparer Comparer { get; } 13 | IEqualityComparer EqualityComparer { get; } 14 | 15 | void Add(KeyValuePair kv); 16 | void Add(TKey key, TValue value); 17 | 18 | void UnsafeAdd(TKey key, TValue value); 19 | 20 | bool Remove(TKey key); 21 | bool Remove(TKey from, bool hasFrom, TKey to, bool hasTo); 22 | 23 | bool ContainsKey(TKey key); 24 | bool TryGetValue(TKey key, out TValue value); 25 | 26 | TValue this[TKey key] { get; set; } 27 | 28 | void Clear(); 29 | 30 | bool IsInternallyOrdered { get; } 31 | IEnumerable> InternalEnumerate(); 32 | 33 | IOrderedSet Split(int count); 34 | void Merge(IOrderedSet set); 35 | 36 | void LoadFrom(KeyValuePair[] array, int count, bool isOrdered); 37 | 38 | IEnumerable> Forward(TKey from, bool hasFrom, TKey to, bool hasTo); 39 | IEnumerable> Backward(TKey to, bool hasTo, TKey from, bool hasFrom); 40 | 41 | KeyValuePair First { get; } 42 | KeyValuePair Last { get; } 43 | 44 | int Count { get; } 45 | } 46 | } -------------------------------------------------------------------------------- /STSdb4/General/Collections/IOrderedSetFactory.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Collections 8 | { 9 | public interface IOrderedSetFactory 10 | { 11 | IOrderedSet Create(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /STSdb4/General/Communication/Packet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | 8 | namespace STSdb4.General.Communication 9 | { 10 | ///--------------------- Packet Exchange Protocol 11 | /// 12 | ///--------------------- Comments----------------------------------- 13 | ///format : binary 14 | ///byte style : LittleEndian 15 | ///ID : Unique ID's per Connection and Unique ID per Packet. 16 | /// 17 | ///------------------------------------------------------------------ 18 | ///Packet : long ID, int Size, byte[] buffer 19 | /// 20 | 21 | public class Packet 22 | { 23 | internal long ID; 24 | 25 | public readonly MemoryStream Request; // Request Message 26 | public MemoryStream Response; // Response Message 27 | 28 | public readonly ManualResetEventSlim ResultEvent; 29 | public Exception Exception; 30 | 31 | public Packet(MemoryStream request) 32 | { 33 | if (request == null) 34 | throw new ArgumentNullException("request == null"); 35 | 36 | Request = request; 37 | 38 | ResultEvent = new ManualResetEventSlim(false); 39 | } 40 | 41 | public void Wait() 42 | { 43 | ResultEvent.Wait(); 44 | 45 | if (Exception != null) 46 | throw Exception; 47 | } 48 | 49 | public void Write(BinaryWriter writer, MemoryStream memoryStream) 50 | { 51 | int size = (int)memoryStream.Length; 52 | 53 | writer.Write(ID); 54 | writer.Write(size); 55 | writer.Write(memoryStream.GetBuffer(), 0, size); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /STSdb4/General/Communication/ServerConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Threading; 9 | 10 | namespace STSdb4.General.Communication 11 | { 12 | public class ServerConnection 13 | { 14 | private Thread Receiver; 15 | private Thread Sender; 16 | private volatile bool Shutdown = false; 17 | 18 | public BlockingCollection PendingPackets; 19 | 20 | public readonly TcpServer TcpServer; 21 | public readonly TcpClient TcpClient; 22 | 23 | public ServerConnection(TcpServer tcpServer, TcpClient tcpClient) 24 | { 25 | if (tcpServer == null) 26 | throw new ArgumentNullException("tcpServer == null"); 27 | if (tcpClient == null) 28 | throw new ArgumentNullException("tcpClient == null"); 29 | 30 | TcpServer = tcpServer; 31 | TcpClient = tcpClient; 32 | } 33 | 34 | public void Connect() 35 | { 36 | Disconnect(); 37 | 38 | TcpServer.ServerConnections.TryAdd(this, this); 39 | PendingPackets = new BlockingCollection(); 40 | 41 | Shutdown = false; 42 | 43 | Receiver = new Thread(DoReceive); 44 | Receiver.Start(); 45 | 46 | Sender = new Thread(DoSend); 47 | Sender.Start(); 48 | } 49 | 50 | public void Disconnect() 51 | { 52 | if (!IsConnected) 53 | return; 54 | 55 | Shutdown = true; 56 | 57 | if (TcpClient != null) 58 | TcpClient.Close(); 59 | 60 | Thread thread = Sender; 61 | if (thread != null && thread.ThreadState == ThreadState.Running) 62 | { 63 | if (!thread.Join(5000)) 64 | thread.Abort(); 65 | } 66 | 67 | Sender = null; 68 | 69 | thread = Receiver; 70 | if (thread != null && thread.ThreadState == ThreadState.Running) 71 | { 72 | if (!thread.Join(5000)) 73 | thread.Abort(); 74 | } 75 | 76 | Receiver = null; 77 | 78 | PendingPackets.Dispose(); 79 | 80 | ServerConnection reference; 81 | TcpServer.ServerConnections.TryRemove(this, out reference); 82 | } 83 | 84 | public bool IsConnected 85 | { 86 | get { return Receiver != null || Sender != null; } 87 | } 88 | 89 | private void DoReceive() 90 | { 91 | try 92 | { 93 | while (!TcpServer.ShutdownTokenSource.Token.IsCancellationRequested && !Shutdown && TcpClient.Connected) 94 | ReceivePacket(); 95 | } 96 | catch (Exception exc) 97 | { 98 | TcpServer.LogError(exc); 99 | } 100 | finally 101 | { 102 | Disconnect(); 103 | } 104 | } 105 | 106 | private void ReceivePacket() 107 | { 108 | BinaryReader reader = new BinaryReader(TcpClient.GetStream()); 109 | 110 | long id = reader.ReadInt64(); 111 | int size = reader.ReadInt32(); 112 | TcpServer.BytesReceive += size; 113 | 114 | Packet packet = new Packet(new MemoryStream(reader.ReadBytes(size))); 115 | packet.ID = id; 116 | 117 | TcpServer.RecievedPackets.Add(new KeyValuePair(this, packet)); 118 | } 119 | 120 | private void DoSend() 121 | { 122 | try 123 | { 124 | while (!TcpServer.ShutdownTokenSource.Token.IsCancellationRequested && !Shutdown && TcpClient.Connected) 125 | SendPacket(); 126 | } 127 | catch (OperationCanceledException exc) 128 | { 129 | } 130 | catch (Exception exc) 131 | { 132 | TcpServer.LogError(exc); 133 | } 134 | finally 135 | { 136 | } 137 | } 138 | 139 | private void SendPacket() 140 | { 141 | CancellationToken token = TcpServer.ShutdownTokenSource.Token; 142 | Packet packet = PendingPackets.Take(token); 143 | TcpServer.BytesSent += packet.Response.Length; 144 | 145 | BinaryWriter writer = new BinaryWriter(TcpClient.GetStream()); 146 | packet.Write(writer, packet.Response); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /STSdb4/General/Communication/TcpServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Concurrent; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Threading; 9 | 10 | namespace STSdb4.General.Communication 11 | { 12 | public class TcpServer 13 | { 14 | private Thread Worker; 15 | 16 | public BlockingCollection> RecievedPackets; 17 | public CancellationTokenSource ShutdownTokenSource { get; private set; } 18 | 19 | public readonly ConcurrentQueue> Errors = new ConcurrentQueue>(); 20 | public readonly ConcurrentDictionary ServerConnections = new ConcurrentDictionary(); 21 | 22 | public int Port { get; private set; } 23 | 24 | public long BytesReceive { get; internal set; } 25 | public long BytesSent { get; internal set; } 26 | 27 | public TcpServer(int port = 7182) 28 | { 29 | Port = port; 30 | } 31 | 32 | public void Start(int boundedCapacity = 64) 33 | { 34 | Stop(); 35 | 36 | RecievedPackets = new BlockingCollection>(boundedCapacity); 37 | ServerConnections.Clear(); 38 | 39 | ShutdownTokenSource = new CancellationTokenSource(); 40 | 41 | Worker = new Thread(DoWork); 42 | Worker.Start(); 43 | } 44 | 45 | public void Stop() 46 | { 47 | if (!IsWorking) 48 | return; 49 | 50 | if (ShutdownTokenSource != null) 51 | ShutdownTokenSource.Cancel(false); 52 | 53 | DisconnectConnections(); 54 | 55 | Thread thread = Worker; 56 | if (thread != null) 57 | { 58 | if (!thread.Join(5000)) 59 | thread.Abort(); 60 | } 61 | } 62 | 63 | public bool IsWorking 64 | { 65 | get { return Worker != null; } 66 | } 67 | 68 | private void DoWork() 69 | { 70 | TcpListener listener = null; 71 | try 72 | { 73 | listener = new TcpListener(IPAddress.Any, Port); 74 | listener.Start(); 75 | 76 | while (!ShutdownTokenSource.Token.IsCancellationRequested) 77 | { 78 | if (listener.Pending()) 79 | { 80 | try 81 | { 82 | TcpClient client = listener.AcceptTcpClient(); 83 | ServerConnection serverConnection = new ServerConnection(this, client); 84 | serverConnection.Connect(); 85 | } 86 | catch (Exception exc) 87 | { 88 | LogError(exc); 89 | } 90 | } 91 | 92 | Thread.Sleep(10); 93 | } 94 | } 95 | catch (Exception exc) 96 | { 97 | LogError(exc); 98 | } 99 | finally 100 | { 101 | if (listener != null) 102 | listener.Stop(); 103 | 104 | Worker = null; 105 | } 106 | } 107 | 108 | public void LogError(Exception exc) 109 | { 110 | while (Errors.Count > 100) 111 | { 112 | KeyValuePair err; 113 | Errors.TryDequeue(out err); 114 | } 115 | 116 | Errors.Enqueue(new KeyValuePair(DateTime.Now, exc)); 117 | } 118 | 119 | private void DisconnectConnections() 120 | { 121 | foreach (var connection in ServerConnections) 122 | connection.Key.Disconnect(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/BigEndianByteArrayComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.General.Extensions; 6 | 7 | namespace STSdb4.General.Comparers 8 | { 9 | public class BigEndianByteArrayComparer : IComparer 10 | { 11 | public static readonly BigEndianByteArrayComparer Instance = new BigEndianByteArrayComparer(); 12 | 13 | public int Compare(byte[] x, byte[] y, int length) 14 | { 15 | CommonArray common = new CommonArray(); 16 | common.ByteArray = x; 17 | ulong[] array1 = common.UInt64Array; 18 | common.ByteArray = y; 19 | ulong[] array2 = common.UInt64Array; 20 | 21 | int len = length >> 3; 22 | 23 | for (int i = 0; i < len; i++) 24 | { 25 | var v1 = array1[i]; 26 | var v2 = array2[i]; 27 | 28 | if (v1 != v2) 29 | { 30 | for (int j = i << 3; ; j++) 31 | { 32 | byte b1 = x[j]; 33 | byte b2 = y[j]; 34 | if (b1 < b2) 35 | return -1; 36 | if (b1 > b2) 37 | return 1; 38 | } 39 | } 40 | } 41 | 42 | int index = len << 3; 43 | 44 | switch (length & 7) 45 | { 46 | case 7: 47 | { 48 | var b1 = x[index]; 49 | var b2 = y[index]; 50 | if (b1 < b2) 51 | return -1; 52 | if (b1 > b2) 53 | return 1; 54 | index++; 55 | goto case 6; 56 | } 57 | case 6: 58 | { 59 | var b1 = x[index]; 60 | var b2 = y[index]; 61 | if (b1 < b2) 62 | return -1; 63 | if (b1 > b2) 64 | return 1; 65 | index++; 66 | goto case 5; 67 | } 68 | case 5: 69 | { 70 | var b1 = x[index]; 71 | var b2 = y[index]; 72 | if (b1 < b2) 73 | return -1; 74 | if (b1 > b2) 75 | return 1; 76 | index++; 77 | goto case 4; 78 | } 79 | case 4: 80 | { 81 | var b1 = x[index]; 82 | var b2 = y[index]; 83 | if (b1 < b2) 84 | return -1; 85 | if (b1 > b2) 86 | return 1; 87 | index++; 88 | goto case 3; 89 | } 90 | case 3: 91 | { 92 | var b1 = x[index]; 93 | var b2 = y[index]; 94 | if (b1 < b2) 95 | return -1; 96 | if (b1 > b2) 97 | return 1; 98 | index++; 99 | goto case 2; 100 | } 101 | case 2: 102 | { 103 | var b1 = x[index]; 104 | var b2 = y[index]; 105 | if (b1 < b2) 106 | return -1; 107 | if (b1 > b2) 108 | return 1; 109 | index++; 110 | goto case 1; 111 | } 112 | case 1: 113 | { 114 | var b1 = x[index]; 115 | var b2 = y[index]; 116 | if (b1 < b2) 117 | return -1; 118 | if (b1 > b2) 119 | return 1; 120 | 121 | break; 122 | } 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | public int Compare(byte[] x, byte[] y) 129 | { 130 | int cmp = Compare(x, y, Math.Min(x.Length, y.Length)); 131 | if (cmp != 0) 132 | return cmp; 133 | 134 | if (x.Length < y.Length) 135 | return -1; 136 | if (x.Length > y.Length) 137 | return 1; 138 | 139 | return 0; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/BigEndianByteArrayEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.General.Extensions; 6 | 7 | namespace STSdb4.General.Comparers 8 | { 9 | public class BigEndianByteArrayEqualityComparer : IEqualityComparer 10 | { 11 | public static readonly BigEndianByteArrayEqualityComparer Instance = new BigEndianByteArrayEqualityComparer(); 12 | 13 | public bool Equals(byte[] x, byte[] y) 14 | { 15 | if (x.Length != y.Length) 16 | return false; 17 | 18 | CommonArray common = new CommonArray(); 19 | common.ByteArray = x; 20 | ulong[] array1 = common.UInt64Array; 21 | common.ByteArray = y; 22 | ulong[] array2 = common.UInt64Array; 23 | 24 | int length = x.Length; 25 | int len = length >> 3; 26 | int remainder = length & 7; 27 | 28 | int i = len; 29 | 30 | if (remainder > 0) 31 | { 32 | int shift = sizeof(ulong) - remainder; 33 | if ((array1[i] << shift) >> shift != (array2[i] << shift) >> shift) 34 | return false; 35 | } 36 | 37 | i--; 38 | 39 | while (i >= 7) 40 | { 41 | if (array1[i] != array2[i] || 42 | array1[i - 1] != array2[i - 1] || 43 | array1[i - 2] != array2[i - 2] || 44 | array1[i - 3] != array2[i - 3] || 45 | array1[i - 4] != array2[i - 4] || 46 | array1[i - 5] != array2[i - 5] || 47 | array1[i - 6] != array2[i - 6] || 48 | array1[i - 7] != array2[i - 7]) 49 | return false; 50 | 51 | i -= 8; 52 | } 53 | 54 | if (i >= 3) 55 | { 56 | if (array1[i] != array2[i] || 57 | array1[i - 1] != array2[i - 1] || 58 | array1[i - 2] != array2[i - 2] || 59 | array1[i - 3] != array2[i - 3]) 60 | return false; 61 | 62 | i -= 4; 63 | } 64 | 65 | if (i >= 1) 66 | { 67 | if (array1[i] != array2[i] || 68 | array1[i - 1] != array2[i - 1]) 69 | return false; 70 | 71 | i -= 2; 72 | } 73 | 74 | if (i >= 0) 75 | { 76 | if (array1[i] != array2[i]) 77 | return false; 78 | 79 | //i -= 1; 80 | } 81 | 82 | return true; 83 | } 84 | 85 | public int GetHashCode(byte[] obj) 86 | { 87 | return obj.GetHashCodeEx(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/ByteOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.General.Comparers 7 | { 8 | public enum ByteOrder : byte 9 | { 10 | Unspecified = 0, 11 | LittleEndian = 1, 12 | BigEndian = 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/CommonArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Comparers 8 | { 9 | [StructLayout(LayoutKind.Explicit)] 10 | public struct CommonArray 11 | { 12 | [FieldOffset(0)] 13 | public byte[] ByteArray; 14 | 15 | [FieldOffset(0)] 16 | public short[] Int16Array; 17 | 18 | [FieldOffset(0)] 19 | public ushort[] UInt16Array; 20 | 21 | [FieldOffset(0)] 22 | public int[] Int32Array; 23 | 24 | [FieldOffset(0)] 25 | public uint[] UInt32Array; 26 | 27 | [FieldOffset(0)] 28 | public long[] Int64Array; 29 | 30 | [FieldOffset(0)] 31 | public ulong[] UInt64Array; 32 | 33 | [FieldOffset(0)] 34 | public float[] SingleArray; 35 | 36 | [FieldOffset(0)] 37 | public double[] DoubleArray; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/ComparerInvertor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.General.Comparers 7 | { 8 | public class ComparerInvertor : IComparer 9 | { 10 | public readonly IComparer Comparer; 11 | 12 | public ComparerInvertor(IComparer comparer) 13 | { 14 | Comparer = comparer; 15 | } 16 | 17 | public int Compare(T x, T y) 18 | { 19 | return -Comparer.Compare(x, y); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/KeyValuePairComparer.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Collections; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Comparers 8 | { 9 | public class KeyValuePairComparer : IComparer> 10 | { 11 | public static readonly KeyValuePairComparer Instance = new KeyValuePairComparer(Comparer.Default); 12 | 13 | public IComparer Comparer { get; private set; } 14 | 15 | public KeyValuePairComparer(IComparer comparer) 16 | { 17 | Comparer = comparer; 18 | } 19 | 20 | public int Compare(KeyValuePair x, KeyValuePair y) 21 | { 22 | return Comparer.Compare(x.Key, y.Key); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/LittleEndianByteArrayComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.General.Extensions; 6 | 7 | namespace STSdb4.General.Comparers 8 | { 9 | public class LittleEndianByteArrayComparer : IComparer 10 | { 11 | public static readonly LittleEndianByteArrayComparer Instance = new LittleEndianByteArrayComparer(); 12 | 13 | public int Compare(byte[] x, byte[] y, int length) 14 | { 15 | CommonArray common = new CommonArray(); 16 | common.ByteArray = x; 17 | ulong[] array1 = common.UInt64Array; 18 | common.ByteArray = y; 19 | ulong[] array2 = common.UInt64Array; 20 | 21 | int len = length >> 3; 22 | int remainder = length & 7; 23 | 24 | int i = len; 25 | 26 | if (remainder > 0) 27 | { 28 | int shift = sizeof(ulong) - remainder; 29 | var v1 = (array1[i] << shift) >> shift; 30 | var v2 = (array2[i] << shift) >> shift; 31 | if (v1 < v2) 32 | return -1; 33 | if (v1 > v2) 34 | return 1; 35 | } 36 | 37 | i--; 38 | 39 | while (i >= 0) 40 | { 41 | var v1 = array1[i]; 42 | var v2 = array2[i]; 43 | if (v1 < v2) 44 | return -1; 45 | if (v1 > v2) 46 | return 1; 47 | 48 | i--; 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | public int Compare(byte[] x, byte[] y) 55 | { 56 | if (x.Length == y.Length) 57 | return Compare(x, y, x.Length); 58 | 59 | for (int i = x.Length - 1, j = y.Length - 1, len = Math.Min(x.Length, y.Length); len > 0; i--, j--, len--) 60 | { 61 | if (x[i] < y[j]) 62 | return -1; 63 | if (x[i] > y[j]) 64 | return 1; 65 | } 66 | 67 | if (x.Length < y.Length) 68 | return -1; 69 | if (y.Length > y.Length) 70 | return 1; 71 | 72 | return 0; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/LittleEndianByteArrayEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.General.Extensions; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace STSdb4.General.Comparers 9 | { 10 | public class LittleEndianByteArrayEqualityComparer : IEqualityComparer 11 | { 12 | public static readonly LittleEndianByteArrayEqualityComparer Instance = new LittleEndianByteArrayEqualityComparer(); 13 | 14 | public bool Equals(byte[] x, byte[] y) 15 | { 16 | if (x.Length != y.Length) 17 | return false; 18 | 19 | CommonArray common = new CommonArray(); 20 | common.ByteArray = x; 21 | ulong[] array1 = common.UInt64Array; 22 | common.ByteArray = y; 23 | ulong[] array2 = common.UInt64Array; 24 | 25 | int length = x.Length; 26 | int remainder = length & 7; 27 | int len = length >> 3; 28 | 29 | int i = 0; 30 | 31 | while (i + 7 < len) 32 | { 33 | if (array1[i] != array2[i] || 34 | array1[i + 1] != array2[i + 1] || 35 | array1[i + 2] != array2[i + 2] || 36 | array1[i + 3] != array2[i + 3] || 37 | array1[i + 4] != array2[i + 4] || 38 | array1[i + 5] != array2[i + 5] || 39 | array1[i + 6] != array2[i + 6] || 40 | array1[i + 7] != array2[i + 7]) 41 | return false; 42 | 43 | i += 8; 44 | } 45 | 46 | if (i + 3 < len) 47 | { 48 | if (array1[i] != array2[i] || 49 | array1[i + 1] != array2[i + 1] || 50 | array1[i + 2] != array2[i + 2] || 51 | array1[i + 3] != array2[i + 3]) 52 | return false; 53 | 54 | i += 4; 55 | } 56 | 57 | if (i + 1 < len) 58 | { 59 | if (array1[i] != array2[i] || 60 | array1[i + 1] != array2[i + 1]) 61 | return false; 62 | 63 | i += 2; 64 | } 65 | 66 | if (i < len) 67 | { 68 | if (array1[i] != array2[i]) 69 | return false; 70 | 71 | i += 1; 72 | } 73 | 74 | if (remainder > 0) 75 | { 76 | int shift = sizeof(ulong) - remainder; 77 | if ((array1[i] << shift) >> shift != (array2[i] << shift) >> shift) 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | 84 | public int GetHashCode(byte[] obj) 85 | { 86 | return obj.GetHashCodeEx(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /STSdb4/General/Comparers/SortOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.General.Comparers 7 | { 8 | public enum SortOrder : byte 9 | { 10 | Unspecified = 0, 11 | Ascending = 1, 12 | Descending = 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /STSdb4/General/Compression/CountCompression.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Diagnostics; 4 | using System.Collections.Generic; 5 | 6 | namespace STSdb4.General.Compression 7 | { 8 | public static class CountCompression 9 | { 10 | private const ulong CACHE_SIZE = 1024 + 1; 11 | 12 | private static byte[][] cache; 13 | 14 | static CountCompression() 15 | { 16 | cache = new byte[CACHE_SIZE][]; 17 | 18 | using (MemoryStream ms = new MemoryStream()) 19 | { 20 | BinaryWriter writer = new BinaryWriter(ms); 21 | 22 | for (int i = 0; i < cache.Length; i++) 23 | { 24 | writer.Seek(0, SeekOrigin.Begin); 25 | InternalSerialize(writer, (ulong)i); 26 | cache[i] = ms.ToArray(); 27 | } 28 | } 29 | } 30 | 31 | private static void InternalSerialize(BinaryWriter writer, ulong number) 32 | { 33 | byte[] buffer = new byte[10]; 34 | int index = 0; 35 | 36 | while (number >= 0x80) 37 | { 38 | buffer[index] = (byte)(number | 0x80); 39 | number = number >> 7; 40 | index++; 41 | } 42 | 43 | buffer[index] = (byte)number; 44 | index++; 45 | 46 | writer.Write(buffer, 0, index); 47 | } 48 | 49 | /// 50 | /// Compress value of count by CountCompression, and stores result in BinaryWriter 51 | /// 52 | /// Value for compression. 53 | public static void Serialize(BinaryWriter writer, ulong number) 54 | { 55 | if (number < CACHE_SIZE) 56 | writer.Write(cache[number]); 57 | else 58 | InternalSerialize(writer, number); 59 | } 60 | 61 | /// 62 | /// Decompress a value compressed with CountCompression by successively reading bytes from BinaryReader. 63 | /// 64 | public static ulong Deserialize(BinaryReader reader) 65 | { 66 | ulong value = 0; 67 | int shift = 0; 68 | byte b; 69 | 70 | do 71 | { 72 | b = reader.ReadByte(); 73 | var temp = (ulong)(b & 0x7F); 74 | temp <<= shift; 75 | value |= temp; 76 | shift += 7; 77 | } 78 | while (b > 0x7F); 79 | 80 | return value; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /STSdb4/General/Diagnostics/MemoryMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace STSdb4.General.Diagnostics 10 | { 11 | public class MemoryMonitor 12 | { 13 | private Process process; 14 | private Task worker; 15 | private bool shutDown; 16 | 17 | private long peakPagedMemorySize64; 18 | private long peakWorkingSet64; 19 | private long peakVirtualMemorySize64; 20 | 21 | public bool MonitorPagedMemorySize64; 22 | public bool MonitorWorkingSet64; 23 | public bool MonitorVirtualMemorySize64; 24 | public int MonitorPeriodInMilliseconds; 25 | 26 | public MemoryMonitor(bool monitorPagedMemorySize64, bool monitorWorkingSet64, bool monitorVirtualMemorySize64, int monitorPeriodInMilliseconds = 500) 27 | { 28 | if (!monitorPagedMemorySize64 && !monitorWorkingSet64 && !monitorVirtualMemorySize64) 29 | throw new ArgumentException("At least one flag has to be true."); 30 | 31 | process = Process.GetCurrentProcess(); 32 | 33 | MonitorPagedMemorySize64 = monitorPagedMemorySize64; 34 | MonitorWorkingSet64 = monitorWorkingSet64; 35 | MonitorVirtualMemorySize64 = monitorVirtualMemorySize64; 36 | MonitorPeriodInMilliseconds = monitorPeriodInMilliseconds; 37 | } 38 | 39 | public MemoryMonitor(int monitorPeriodInMilliseconds = 500) 40 | : this(true, true, true, monitorPeriodInMilliseconds) 41 | { 42 | } 43 | 44 | ~MemoryMonitor() 45 | { 46 | Stop(); 47 | } 48 | 49 | private void DoUpate() 50 | { 51 | process.Refresh(); 52 | 53 | if (MonitorPagedMemorySize64) 54 | { 55 | var pagedMemorySize64 = process.PagedMemorySize64; 56 | if (pagedMemorySize64 > PeakPagedMemorySize64) 57 | PeakPagedMemorySize64 = pagedMemorySize64; 58 | } 59 | 60 | if (MonitorWorkingSet64) 61 | { 62 | var workingSet64 = process.WorkingSet64; 63 | if (workingSet64 > PeakWorkingSet64) 64 | PeakWorkingSet64 = workingSet64; 65 | } 66 | 67 | if (MonitorVirtualMemorySize64) 68 | { 69 | var virtualMemorySize64 = process.VirtualMemorySize64; 70 | if (virtualMemorySize64 > PeakVirtualMemorySize64) 71 | PeakVirtualMemorySize64 = virtualMemorySize64; 72 | } 73 | } 74 | 75 | private void DoMonitor() 76 | { 77 | while (!shutDown) 78 | { 79 | DoUpate(); 80 | 81 | SpinWait.SpinUntil(() => shutDown, MonitorPeriodInMilliseconds); 82 | } 83 | } 84 | 85 | public void Start() 86 | { 87 | if (worker != null) 88 | Stop(); 89 | 90 | DoUpate(); 91 | 92 | worker = Task.Factory.StartNew(DoMonitor, TaskCreationOptions.LongRunning); 93 | } 94 | 95 | public void Stop() 96 | { 97 | if (worker == null) 98 | return; 99 | 100 | try 101 | { 102 | shutDown = true; 103 | worker.Wait(); 104 | } 105 | finally 106 | { 107 | shutDown = false; 108 | worker = null; 109 | } 110 | } 111 | 112 | public void Reset() 113 | { 114 | PeakPagedMemorySize64 = 0; 115 | PeakWorkingSet64 = 0; 116 | PeakVirtualMemorySize64 = 0; 117 | } 118 | 119 | public long PeakPagedMemorySize64 120 | { 121 | get { return Interlocked.Read(ref peakPagedMemorySize64); } 122 | private set { Interlocked.Exchange(ref peakPagedMemorySize64, value); } 123 | } 124 | 125 | public long PeakWorkingSet64 126 | { 127 | get { return Interlocked.Read(ref peakWorkingSet64); } 128 | private set { Interlocked.Exchange(ref peakWorkingSet64, value); } 129 | } 130 | 131 | public long PeakVirtualMemorySize64 132 | { 133 | get { return Interlocked.Read(ref peakVirtualMemorySize64); } 134 | private set { Interlocked.Exchange(ref peakVirtualMemorySize64, value); } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /STSdb4/General/Environment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.General 7 | { 8 | public static class Environment 9 | { 10 | public static readonly bool RunningOnMono = Type.GetType("Mono.Runtime") != null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /STSdb4/General/Extensions/ArrayExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.General.Extensions 7 | { 8 | public static class ArrayExtensions 9 | { 10 | public static T[] Copy(this T[] array) 11 | { 12 | T[] array2 = new T[array.Length]; 13 | Array.Copy(array, array2, array.Length); 14 | 15 | return array2; 16 | } 17 | 18 | public static void InsertionSort(this T[] array, int index, int count, IComparer comparer) 19 | { 20 | int limit = index + count; 21 | for (int i = index + 1; i < limit; i++) 22 | { 23 | var item = array[i]; 24 | 25 | int j = i - 1; 26 | while (comparer.Compare(array[j], item) > 0) 27 | { 28 | array[j + 1] = array[j]; 29 | j--; 30 | if (j < index) 31 | break; 32 | } 33 | 34 | array[j + 1] = item; 35 | } 36 | } 37 | 38 | public static void InsertionSort(this T[] array, IComparer comparer) 39 | { 40 | InsertionSort(array, 0, array.Length, comparer); 41 | } 42 | 43 | public static T[] Middle(this T[] buffer, int offset, int length) 44 | { 45 | T[] middle = new T[length]; 46 | Array.Copy(buffer, offset, middle, 0, length); 47 | return middle; 48 | } 49 | 50 | public static T[] Left(this T[] buffer, int length) 51 | { 52 | return buffer.Middle(0, length); 53 | } 54 | 55 | public static T[] Right(this T[] buffer, int length) 56 | { 57 | return buffer.Middle(buffer.Length - length, length); 58 | } 59 | 60 | public static string ToString(this T[] array, string separator) 61 | { 62 | return "{" + String.Join(separator, array) + "}"; 63 | } 64 | 65 | public static List CreateList(this T[] array, int count) 66 | { 67 | List list = new List(); 68 | 69 | list.SetArray(array); 70 | list.SetCount(count); 71 | //list.IncrementVersion(); 72 | 73 | return list; 74 | } 75 | 76 | public static int RemoveAll(this T[] array, Predicate match) 77 | { 78 | if (match == null) 79 | throw new ArgumentException("match"); 80 | 81 | int index = 0; 82 | int count = array.Length; 83 | 84 | while (index < count && !match(array[index])) 85 | index++; 86 | 87 | if (index >= count) 88 | return 0; 89 | 90 | int idx = index + 1; 91 | 92 | while (idx < count) 93 | { 94 | while (idx < count && match(array[idx])) 95 | idx++; 96 | 97 | if (idx < count) 98 | array[index++] = array[idx++]; 99 | } 100 | 101 | int removed = count - index; 102 | 103 | Array.Clear(array, index, removed); 104 | 105 | return removed; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /STSdb4/General/Extensions/ByteArrayExtensions.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Comparers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Extensions 8 | { 9 | public static class ByteArrayExtensions 10 | { 11 | private static readonly string[] hexValues = BitConverter.ToString(Enumerable.Range(0, 256).Select(x => (byte)x).ToArray()).Split('-'); 12 | 13 | public static int GetHashCodeEx(this byte[] buffer) 14 | { 15 | const int CONSTANT = 17; 16 | int hashCode = 37; 17 | 18 | CommonArray common = new CommonArray(); 19 | common.ByteArray = buffer; 20 | int[] array = common.Int32Array; 21 | 22 | int length = buffer.Length; 23 | int remainder = length & 3; 24 | int len = length >> 2; 25 | 26 | int i = 0; 27 | 28 | while (i < len) 29 | { 30 | hashCode = CONSTANT * hashCode + array[i]; 31 | i++; 32 | } 33 | 34 | if (remainder > 0) 35 | { 36 | int shift = sizeof(uint) - remainder; 37 | hashCode = CONSTANT * hashCode + ((array[i] << shift) >> shift); 38 | } 39 | 40 | return hashCode; 41 | } 42 | 43 | /// 44 | /// http://en.wikipedia.org/wiki/MurmurHash 45 | /// 46 | /// 47 | /// 48 | /// 49 | public static int MurMurHash3(this byte[] buffer, int seed = 37) 50 | { 51 | const uint c1 = 0xcc9e2d51; 52 | const uint c2 = 0x1b873593; 53 | const int r1 = 15; 54 | const int r2 = 13; 55 | const uint m = 5; 56 | const uint n = 0xe6546b64; 57 | 58 | uint hash = (uint)seed; 59 | 60 | CommonArray common = new CommonArray(); 61 | common.ByteArray = buffer; 62 | uint[] array = common.UInt32Array; 63 | 64 | int length = buffer.Length; 65 | int remainder = length & 3; 66 | int len = length >> 2; 67 | 68 | int i = 0; 69 | 70 | while (i < len) 71 | { 72 | uint k = array[i]; 73 | 74 | k *= c1; 75 | k = (k << r1) | (k >> (32 - r1)); //k = rotl32(k, r1); 76 | k *= c2; 77 | 78 | hash ^= k; 79 | hash = (hash << r2) | (hash >> (32 - r2)); //hash = rotl32(hash, r2); 80 | hash = hash * m + n; 81 | 82 | i++; 83 | } 84 | 85 | if (remainder > 0) 86 | { 87 | int shift = sizeof(uint) - remainder; 88 | uint k = (array[i] << shift) >> shift; 89 | 90 | k *= c1; 91 | k = (k << r1) | (k >> (32 - r1)); //k = rotl32(k, r1); 92 | k *= c2; 93 | 94 | hash ^= k; 95 | } 96 | 97 | hash ^= (uint)length; 98 | 99 | //hash = fmix(hash); 100 | hash ^= hash >> 16; 101 | hash *= 0x85ebca6b; 102 | hash ^= hash >> 13; 103 | hash *= 0xc2b2ae35; 104 | hash ^= hash >> 16; 105 | 106 | return (int)hash; 107 | } 108 | 109 | public static byte[] Middle(this byte[] buffer, int offset, int length) 110 | { 111 | byte[] middle = new byte[length]; 112 | Buffer.BlockCopy(buffer, offset, middle, 0, length); 113 | return middle; 114 | } 115 | 116 | public static byte[] Left(this byte[] buffer, int length) 117 | { 118 | return buffer.Middle(0, length); 119 | } 120 | 121 | public static byte[] Right(this byte[] buffer, int length) 122 | { 123 | return buffer.Middle(buffer.Length - length, length); 124 | } 125 | 126 | /// 127 | /// Convert byte array to hex string 128 | /// 129 | /// 130 | /// 131 | public static string ToHex(this byte[] buffer) 132 | { 133 | StringBuilder sb = new StringBuilder(2 * buffer.Length); 134 | 135 | for (int i = 0; i < buffer.Length; i++) 136 | sb.Append(hexValues[buffer[i]]); 137 | 138 | return sb.ToString(); 139 | } 140 | 141 | public static int GetBit(this byte[] map, int bitIndex) 142 | { 143 | return (map[bitIndex >> 3] >> (bitIndex & 7)) & 1; 144 | } 145 | 146 | public static void SetBit(this byte[] map, int bitIndex, int value) 147 | { 148 | int bitMask = 1 << (bitIndex & 7); 149 | if (value != 0) 150 | map[bitIndex >> 3] |= (byte)bitMask; 151 | else 152 | map[bitIndex >> 3] &= (byte)(~bitMask); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /STSdb4/General/Extensions/DecimalExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace STSdb4.General.Extensions 10 | { 11 | public delegate int DecimalGetDigitsDelegate(ref Decimal value); 12 | public delegate void DecimalWriteDelegate(ref Decimal value, int[] buffer, int index); 13 | 14 | public class DecimalHelper 15 | { 16 | public static readonly DecimalHelper Instance = new DecimalHelper(); 17 | 18 | public readonly DecimalGetDigitsDelegate GetDigits; 19 | 20 | /// 21 | /// Writes a decimal value into an int[] array in the same order as a BinaryWriter - d.lo, d.mid, d.hi, d.flags. 22 | /// 23 | public readonly DecimalWriteDelegate Write; 24 | 25 | /// 26 | /// Create decimal from lo,mid,hi,flags 27 | /// 28 | public readonly Func Constructor; 29 | 30 | public DecimalHelper() 31 | { 32 | var lambda = CreateGetDigitsMethod(); 33 | GetDigits = lambda.Compile(); 34 | 35 | Write = CreateWriteMethod().Compile(); 36 | Constructor = CreateConstructorMethod().Compile(); 37 | } 38 | 39 | public Expression CreateWriteMethod() 40 | { 41 | var value = Expression.Parameter(typeof(Decimal).MakeByRefType(), "value"); 42 | var buffer = Expression.Parameter(typeof(int[]), "buffer"); 43 | var index = Expression.Parameter(typeof(int), "index"); 44 | 45 | var lo = Expression.Field(value, "lo"); 46 | var mid = Expression.Field(value, "mid"); 47 | var hi = Expression.Field(value, "hi"); 48 | var flags = Expression.Field(value, "flags"); 49 | 50 | Expression block = Expression.Block( 51 | Expression.Assign(Expression.ArrayAccess(buffer, Expression.PostIncrementAssign(index)), lo), 52 | Expression.Assign(Expression.ArrayAccess(buffer, Expression.PostIncrementAssign(index)), mid), 53 | Expression.Assign(Expression.ArrayAccess(buffer, Expression.PostIncrementAssign(index)), hi), 54 | Expression.Assign(Expression.ArrayAccess(buffer, Expression.PostIncrementAssign(index)), flags) 55 | ); 56 | 57 | var lambda = Expression.Lambda(block, value, buffer, index); 58 | 59 | //private void Write(ref Decimal value, int[] buffer, int index) 60 | //{ 61 | // buffer[index++] = value.lo; 62 | // buffer[index++] = value.mid; 63 | // buffer[index++] = value.hi; 64 | // buffer[index++] = value.flags; 65 | //} 66 | 67 | return lambda; 68 | } 69 | 70 | private Expression> CreateConstructorMethod() 71 | { 72 | var lo = Expression.Parameter(typeof(int), "lo"); 73 | var mid = Expression.Parameter(typeof(int), "mid"); 74 | var hi = Expression.Parameter(typeof(int), "hi"); 75 | var flags = Expression.Parameter(typeof(int), "flags"); 76 | 77 | ConstructorInfo decimalConstructor; 78 | 79 | #if NETFX_CORE 80 | decimalConstructor = typeof(decimal).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) }); 81 | #else 82 | decimalConstructor = typeof(decimal).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) }, null); 83 | #endif 84 | 85 | var constructor = Expression.New(decimalConstructor, lo, mid, hi, flags); 86 | 87 | //return new Decimal(lo, mid, hi, flags); 88 | 89 | return Expression.Lambda>(Expression.Label(Expression.Label(typeof(decimal)), constructor), lo, mid, hi, flags); 90 | } 91 | 92 | private Expression CreateGetDigitsMethod() 93 | { 94 | var value = Expression.Parameter(typeof(Decimal).MakeByRefType(), "value"); 95 | 96 | var digits = Expression.RightShift( 97 | Expression.And(Expression.Field(value, "flags"), Expression.Constant(~Int32.MinValue, typeof(int))), 98 | Expression.Constant(16, typeof(int))); 99 | 100 | //return (value.flags & ~Int32.MinValue) >> 16 101 | 102 | return Expression.Lambda(digits, value); 103 | } 104 | } 105 | 106 | public static class DecimalExtensions 107 | { 108 | public static int GetDigits(this Decimal value) 109 | { 110 | return DecimalHelper.Instance.GetDigits(ref value); 111 | } 112 | 113 | public static void Write(this Decimal value, int[] buffer, int index) 114 | { 115 | DecimalHelper.Instance.Write(ref value, buffer, index); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /STSdb4/General/Extensions/IListExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Extensions 8 | { 9 | public static class IListExtensions 10 | { 11 | public static int BinarySearch(this IList array, int index, int length, T value, IComparer comparer) 12 | { 13 | if (comparer == null) 14 | throw new ArgumentNullException("comparer"); 15 | 16 | int low = index; 17 | int high = index + length - 1; 18 | 19 | while (low <= high) 20 | { 21 | int mid = (low + high) >> 1; 22 | int cmp = comparer.Compare(array[mid], value); 23 | 24 | if (cmp == 0) 25 | return mid; 26 | if (cmp < 0) 27 | low = mid + 1; 28 | else 29 | high = mid - 1; 30 | } 31 | 32 | return ~low; 33 | } 34 | 35 | public static int BinarySearch(this IList array, int index, int length, T value) 36 | { 37 | return BinarySearch(array, index, length, value, Comparer.Default); 38 | } 39 | 40 | public static int BinarySearch(this IList array, int index, int length, object value, IComparer comparer) 41 | { 42 | if (comparer == null) 43 | throw new ArgumentNullException("comparer"); 44 | 45 | int low = index; 46 | int high = index + length - 1; 47 | 48 | while (low <= high) 49 | { 50 | int mid = (low + high) >> 1; 51 | int cmp = comparer.Compare(array[mid], value); 52 | 53 | if (cmp == 0) 54 | return mid; 55 | if (cmp < 0) 56 | low = mid + 1; 57 | else 58 | high = mid - 1; 59 | } 60 | 61 | return ~low; 62 | } 63 | 64 | public static int BinarySearch(this IList array, int index, int length, object value) 65 | { 66 | return BinarySearch(array, index, length, Comparer.Default); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /STSdb4/General/Extensions/KeyValuePairExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Extensions 8 | { 9 | public delegate void SetKeyDelegate(ref KeyValuePair kv, TKey key); 10 | public delegate void SetValueDelegate(ref KeyValuePair kv, TValue value); 11 | public delegate void SetKeyValueDelegate(ref KeyValuePair kv, TKey key, TValue value); 12 | 13 | public class KeyValuePairHelper 14 | { 15 | public static readonly KeyValuePairHelper Instance = new KeyValuePairHelper(); 16 | 17 | public readonly SetKeyDelegate SetKey; 18 | public readonly SetValueDelegate SetValue; 19 | public readonly SetKeyValueDelegate SetKeyValue; 20 | 21 | public KeyValuePairHelper() 22 | { 23 | var setKeyLambda = CreateSetKeyMethod(); 24 | SetKey = setKeyLambda.Compile(); 25 | 26 | var setValueLambda = CreateSetValueMethod(); 27 | SetValue = setValueLambda.Compile(); 28 | 29 | var setKeyValueLambda = CreateSetKeyValueMethod(); 30 | SetKeyValue = setKeyValueLambda.Compile(); 31 | } 32 | 33 | public Expression> CreateSetKeyMethod() 34 | { 35 | var kv = Expression.Parameter(typeof(KeyValuePair).MakeByRefType(), "kv"); 36 | var key = Expression.Parameter(typeof(TKey), "key"); 37 | 38 | var assign = Expression.Assign(Expression.Field(kv, "key"), key); 39 | 40 | return Expression.Lambda>(assign, kv, key); 41 | } 42 | 43 | public Expression> CreateSetValueMethod() 44 | { 45 | var kv = Expression.Parameter(typeof(KeyValuePair).MakeByRefType(), "kv"); 46 | var value = Expression.Parameter(typeof(TValue), "value"); 47 | 48 | var assign = Expression.Assign(Expression.Field(kv, "value"), value); 49 | 50 | return Expression.Lambda>(assign, kv, value); 51 | } 52 | 53 | public Expression> CreateSetKeyValueMethod() 54 | { 55 | var kv = Expression.Parameter(typeof(KeyValuePair).MakeByRefType(), "kv"); 56 | 57 | var key = Expression.Parameter(typeof(TKey), "key"); 58 | var value = Expression.Parameter(typeof(TValue), "value"); 59 | 60 | var body = Expression.Block( 61 | Expression.Assign(Expression.Field(kv, "key"), key), 62 | Expression.Assign(Expression.Field(kv, "value"), value) 63 | ); 64 | 65 | return Expression.Lambda>(body, kv, key, value); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /STSdb4/General/Extensions/StopwatchExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Extensions 8 | { 9 | public static class StopwatchExtensions 10 | { 11 | public static double GetSpeed(this Stopwatch sw, long count) 12 | { 13 | return count / (sw.ElapsedMilliseconds / 1000.0); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /STSdb4/General/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.General.Extensions 7 | { 8 | public static class StringExtensions 9 | { 10 | /// 11 | /// Convert string to byte array 12 | /// 13 | /// 14 | /// 15 | public static byte[] ParseHex(this string hex) 16 | { 17 | if ((hex.Length & 1) != 0) 18 | throw new ArgumentException("Input must have even number of characters"); 19 | 20 | byte[] result = new byte[hex.Length / 2]; 21 | 22 | for (int i = 0; i < result.Length; i++) 23 | { 24 | int high = hex[i * 2]; 25 | int low = hex[i * 2 + 1]; 26 | high = (high & 0xf) + ((high & 0x40) >> 6) * 9; 27 | low = (low & 0xf) + ((low & 0x40) >> 6) * 9; 28 | 29 | result[i] = (byte)((high << 4) | low); 30 | } 31 | 32 | return result; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /STSdb4/General/Extensions/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Extensions 8 | { 9 | public static class TypeExtensions 10 | { 11 | public static bool IsStruct(this Type type) 12 | { 13 | return type.IsValueType && !type.IsPrimitive && !type.IsEnum; 14 | } 15 | 16 | public static bool IsInheritInterface(this Type type, Type @interface) 17 | { 18 | if (!@interface.IsInterface) 19 | throw new ArgumentException(String.Format("The type '{0}' has to be an interface.", @interface.Name)); 20 | 21 | return type.GetInterfaces().FirstOrDefault(x => x == @interface) != null; 22 | } 23 | 24 | public static IEnumerable GetPublicReadWritePropertiesAndFields(this Type type) 25 | { 26 | foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.Instance)) 27 | { 28 | if (member.MemberType == MemberTypes.Field) 29 | { 30 | FieldInfo field = (FieldInfo)member; 31 | if (field.IsInitOnly) 32 | continue; 33 | 34 | yield return member; 35 | } 36 | 37 | if (member.MemberType == MemberTypes.Property) 38 | { 39 | PropertyInfo property = (PropertyInfo)member; 40 | if (property.GetAccessors(false).Length != 2) 41 | continue; 42 | 43 | yield return member; 44 | } 45 | } 46 | } 47 | 48 | public static Type GetPropertyOrFieldType(this MemberInfo member) 49 | { 50 | switch (member.MemberType) 51 | { 52 | case MemberTypes.Property: return ((PropertyInfo)member).PropertyType; 53 | case MemberTypes.Field: return ((FieldInfo)member).FieldType; 54 | default: 55 | throw new NotSupportedException(member.MemberType.ToString()); 56 | } 57 | } 58 | 59 | public static bool HasDefaultConstructor(this Type type) 60 | { 61 | return type.GetConstructor(new Type[] { }) != null; 62 | } 63 | 64 | public static bool IsDictionary(this Type type) 65 | { 66 | return type.Name == typeof(Dictionary<,>).Name; 67 | } 68 | 69 | public static bool IsList(this Type type) 70 | { 71 | return type.Name == typeof(List<>).Name; 72 | } 73 | 74 | public static bool IsKeyValuePair(this Type type) 75 | { 76 | return type.Name == typeof(KeyValuePair<,>).Name; 77 | } 78 | 79 | public static bool IsNullable(this Type type) 80 | { 81 | return type.Name == typeof(Nullable<>).Name; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /STSdb4/General/IO/AtomicFile.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Comparers; 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 STSdb4.General.IO 10 | { 11 | public class AtomicFile 12 | { 13 | private byte[] HEADER = new byte[512]; 14 | private CommonArray commonArray = new CommonArray(); 15 | 16 | private Stream stream; 17 | public string FileName { get; private set; } 18 | 19 | public AtomicFile(string fileName) 20 | { 21 | commonArray.ByteArray = HEADER; 22 | 23 | stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); 24 | FileName = fileName; 25 | 26 | if (stream.Length < HEADER.Length) 27 | { 28 | Pos = HEADER.Length; 29 | Size = 0; 30 | stream.Write(HEADER, 0, HEADER.Length); 31 | } 32 | else 33 | stream.Read(HEADER, 0, HEADER.Length); 34 | } 35 | 36 | private long Pos 37 | { 38 | get { return commonArray.Int64Array[0]; } 39 | set { commonArray.Int64Array[0] = value; } 40 | } 41 | 42 | public int Size 43 | { 44 | get { return (int)commonArray.Int64Array[1]; } 45 | private set { commonArray.Int64Array[1] = value; } 46 | } 47 | 48 | public void Write(byte[] buffer, int index, int count) 49 | { 50 | if (Pos - 1 - HEADER.Length >= count) 51 | Pos = HEADER.Length; 52 | else 53 | Pos = Pos + Size; 54 | 55 | Size = count; 56 | 57 | stream.Seek(Pos, SeekOrigin.Begin); 58 | stream.Write(buffer, index, count); 59 | 60 | stream.Seek(0, SeekOrigin.Begin); 61 | stream.Write(HEADER, 0, 2 * sizeof(long)); //HEADER.Length 62 | stream.Flush(); 63 | } 64 | 65 | public void Write(byte[] buffer) 66 | { 67 | Write(buffer, 0, buffer.Length); 68 | } 69 | 70 | public byte[] Read() 71 | { 72 | stream.Seek(Pos, SeekOrigin.Begin); 73 | 74 | byte[] buffer = new byte[Size]; 75 | int readed = stream.Read(buffer, 0, buffer.Length); 76 | 77 | if (readed != buffer.Length) 78 | throw new IOException(); //should never happen 79 | 80 | return buffer; 81 | } 82 | 83 | public void Close() 84 | { 85 | if (Pos + Size < stream.Length) 86 | stream.SetLength(Pos + Size); 87 | 88 | stream.Close(); 89 | } 90 | 91 | public long Length 92 | { 93 | get { return stream.Length; } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /STSdb4/General/IO/IOUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.IO 8 | { 9 | public static class IOUtils 10 | { 11 | public static long GetTotalFreeSpace(string driveName) 12 | { 13 | driveName = driveName.ToUpper(); 14 | 15 | var drive = DriveInfo.GetDrives().Where(x => x.IsReady && x.Name == driveName).FirstOrDefault(); 16 | 17 | return drive != null ? drive.TotalFreeSpace : -1; 18 | } 19 | 20 | public static long GetTotalSpace(string driveName) 21 | { 22 | driveName = driveName.ToUpper(); 23 | 24 | var drive = new DriveInfo(driveName); 25 | 26 | return drive != null ? drive.TotalSize : -1; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /STSdb4/General/IO/OptimizedFileStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.IO; 5 | 6 | namespace STSdb4.General.IO 7 | { 8 | /// 9 | /// An optimized FileStram - optimizes calls to Seek & Size methods 10 | /// The requirement is if the file is opened for writing, it is an exclusive. 11 | /// 12 | public class OptimizedFileStream : FileStream 13 | { 14 | private long length = long.MinValue; 15 | 16 | public OptimizedFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize) 17 | : base(path, mode, access, share, bufferSize) 18 | { 19 | } 20 | 21 | public OptimizedFileStream(string fileName, FileMode mode, FileAccess access) 22 | : base(fileName, mode, access) 23 | { 24 | } 25 | 26 | public OptimizedFileStream(string fileName, FileMode mode) 27 | : base(fileName, mode) 28 | { 29 | } 30 | 31 | public override long Position 32 | { 33 | get { return base.Position; } 34 | set 35 | { 36 | if (base.Position != value) 37 | base.Position = value; 38 | } 39 | } 40 | 41 | public override void Write(byte[] array, int offset, int count) 42 | { 43 | try 44 | { 45 | base.Write(array, offset, count); 46 | 47 | if (Position > Length) 48 | length = Position; 49 | } 50 | catch (Exception exc) 51 | { 52 | length = long.MinValue; 53 | throw exc; 54 | } 55 | } 56 | 57 | public override void WriteByte(byte value) 58 | { 59 | try 60 | { 61 | base.WriteByte(value); 62 | 63 | if (Position > Length) 64 | length = Position; 65 | } 66 | catch (Exception exc) 67 | { 68 | length = long.MinValue; 69 | throw exc; 70 | } 71 | } 72 | 73 | public override long Length 74 | { 75 | get 76 | { 77 | if (length == long.MinValue) 78 | length = base.Length; 79 | 80 | return length; 81 | } 82 | } 83 | 84 | public override void SetLength(long value) 85 | { 86 | try 87 | { 88 | base.SetLength(value); 89 | 90 | length = value; 91 | } 92 | catch (Exception exc) 93 | { 94 | length = long.MinValue; 95 | 96 | throw exc; 97 | } 98 | } 99 | 100 | public override long Seek(long offset, SeekOrigin origin) 101 | { 102 | switch (origin) 103 | { 104 | case SeekOrigin.Begin: 105 | { 106 | if (offset != Position) 107 | return base.Seek(offset, origin); 108 | } 109 | break; 110 | case SeekOrigin.Current: 111 | { 112 | if (offset != 0) 113 | return base.Seek(offset, origin); 114 | } 115 | break; 116 | case SeekOrigin.End: 117 | { 118 | if (offset != Length - Position) 119 | return base.Seek(offset, origin); 120 | } 121 | break; 122 | } 123 | 124 | return Position; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /STSdb4/General/Mathematics/MathUtils.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Mathematics 8 | { 9 | public static class MathUtils 10 | { 11 | private const int SIGN_MASK = ~Int32.MinValue; 12 | 13 | /// 14 | /// Returns the number of digits after the decimal point. 15 | /// 16 | public static int GetDigits(decimal value) 17 | { 18 | return DecimalHelper.Instance.GetDigits(ref value); 19 | } 20 | 21 | /// 22 | /// Returns the number of digits after the decimal point; 23 | /// 24 | public static int GetDigits(double value) 25 | { 26 | decimal val = (decimal)value; 27 | double tmp = (double)val; 28 | if (tmp != value) 29 | return -1; 30 | 31 | return DecimalHelper.Instance.GetDigits(ref val); 32 | } 33 | 34 | /// 35 | /// Returns the number of digits after the decimal point; 36 | /// 37 | public static int GetDigits(float value) 38 | { 39 | return GetDigits((double)value); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /STSdb4/General/Persist/BooleanIndexerPersist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using STSdb4.General.Extensions; 4 | 5 | namespace STSdb4.General.Persist 6 | { 7 | public class BooleanIndexerPersist : IIndexerPersist 8 | { 9 | public const byte VERSION = 40; 10 | 11 | public void Store(BinaryWriter writer, Func values, int count) 12 | { 13 | writer.Write(VERSION); 14 | 15 | byte[] buffer = new byte[(int)Math.Ceiling(count / 8.0)]; 16 | 17 | for (int i = 0; i < count; i++) 18 | buffer.SetBit(i, values(i) ? 1 : 0); 19 | 20 | writer.Write(buffer); 21 | } 22 | 23 | public void Load(BinaryReader reader, Action values, int count) 24 | { 25 | if (reader.ReadByte() != VERSION) 26 | throw new Exception("Invalid BooleanIndexerPersist version."); 27 | 28 | byte[] buffer = reader.ReadBytes((int)Math.Ceiling(count / 8.0)); 29 | 30 | for (int i = 0; i < count; i++) 31 | values(i, buffer.GetBit(i) == 0 ? false : true); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /STSdb4/General/Persist/ByteArrayIndexerPersist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using STSdb4.General.Compression; 5 | 6 | namespace STSdb4.General.Persist 7 | { 8 | public class ByteArrayIndexerPersist : IIndexerPersist 9 | { 10 | public const byte VERSION = 40; 11 | 12 | public void Store(BinaryWriter writer, Func values, int count) 13 | { 14 | writer.Write(VERSION); 15 | 16 | int index = 0; 17 | byte[] value; 18 | 19 | if (writer.BaseStream is MemoryStream) 20 | { 21 | writer.Write((byte)1); 22 | if (count == 0) 23 | return; 24 | 25 | int c = 1; 26 | long pos = writer.BaseStream.Position; 27 | writer.Write(count); //writer.Write(c); 28 | 29 | int length; 30 | value = values(index); 31 | if (value == null) 32 | { 33 | length = -1; 34 | writer.Write(length); 35 | } 36 | else 37 | { 38 | length = value.Length; 39 | writer.Write(length); 40 | writer.Write(value); 41 | } 42 | index++; 43 | 44 | while (index < count) 45 | { 46 | value = values(index); 47 | 48 | if (value == null) 49 | { 50 | if (length != -1) 51 | break; 52 | } 53 | else 54 | { 55 | if (length != value.Length) 56 | break; 57 | 58 | writer.Write(value); 59 | } 60 | 61 | index++; 62 | c++; 63 | } 64 | 65 | if (c < count) 66 | { 67 | var pos2 = writer.BaseStream.Position; 68 | writer.BaseStream.Seek(pos, SeekOrigin.Begin); 69 | writer.Write(c); 70 | writer.BaseStream.Seek(pos2, SeekOrigin.Begin); 71 | } 72 | else 73 | return; 74 | } 75 | else 76 | writer.Write((byte)0); 77 | 78 | for (int i = index; i < count; i++) 79 | { 80 | value = values(i); 81 | 82 | if (value == null) 83 | CountCompression.Serialize(writer, 0); 84 | else 85 | { 86 | CountCompression.Serialize(writer, (ulong)(value.Length + 1)); 87 | writer.Write(value); 88 | } 89 | } 90 | } 91 | 92 | public void Load(BinaryReader reader, Action values, int count) 93 | { 94 | if (reader.ReadByte() != VERSION) 95 | throw new Exception("Invalid ByteArrayIndexerPersist version."); 96 | 97 | int index = 0; 98 | 99 | byte format = reader.ReadByte(); 100 | 101 | if (format == 1) 102 | { 103 | if (count == 0) 104 | return; 105 | 106 | int c = reader.ReadInt32(); 107 | int length = reader.ReadInt32(); 108 | 109 | if (length < 0) 110 | { 111 | for (int i = 0; i < c; i++) 112 | values(index++, null); 113 | } 114 | else 115 | { 116 | for (int i = 0; i < c; i++) 117 | values(index++, reader.ReadBytes(length)); 118 | } 119 | 120 | if (index == count) 121 | return; 122 | } 123 | 124 | for (int i = index; i < count; i++) 125 | { 126 | int length = (int)CountCompression.Deserialize(reader); 127 | 128 | if (length == 0) 129 | values(i, null); 130 | else 131 | values(i, reader.ReadBytes(length - 1)); 132 | } 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /STSdb4/General/Persist/DateTimeIndexerPersist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Diagnostics; 4 | 5 | namespace STSdb4.General.Persist 6 | { 7 | public class DateTimeIndexerPersist : IIndexerPersist 8 | { 9 | public const byte VERSION = 40; 10 | 11 | private static readonly long MILLISECOND = 10000; 12 | private static readonly long SECOND = 1000 * MILLISECOND; 13 | private static readonly long MINUTE = 60 * SECOND; 14 | private static readonly long HOUR = 60 * MINUTE; 15 | private static readonly long DAY = 24 * HOUR; 16 | 17 | private readonly Int64IndexerPersist persist = new Int64IndexerPersist(new long[] { MILLISECOND, SECOND, MINUTE, HOUR, DAY }); 18 | 19 | public void Store(BinaryWriter writer, Func values, int count) 20 | { 21 | writer.Write(VERSION); 22 | 23 | persist.Store(writer, (i) => { return values(i).Ticks; }, count); 24 | } 25 | 26 | public void Load(BinaryReader reader, Action values, int count) 27 | { 28 | if (reader.ReadByte() != VERSION) 29 | throw new Exception("Invalid DateTimeIndexerPersist version."); 30 | 31 | persist.Load(reader, (i, v) => { values(i, new DateTime(v)); }, count); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /STSdb4/General/Persist/IIndexerPersist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace STSdb4.General.Persist 5 | { 6 | public interface IIndexerPersist 7 | { 8 | } 9 | 10 | public interface IIndexerPersist : IIndexerPersist 11 | { 12 | void Store(BinaryWriter writer, Func values, int count); 13 | void Load(BinaryReader reader, Action values, int count); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /STSdb4/General/Persist/IPersist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | 7 | namespace STSdb4.General.Persist 8 | { 9 | public interface IPersist 10 | { 11 | } 12 | 13 | public interface IPersist : IPersist 14 | { 15 | void Write(BinaryWriter writer, T item); 16 | T Read(BinaryReader reader); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /STSdb4/General/Persist/TimeSpanIndexerPersist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.General.Persist 8 | { 9 | public class TimeSpanIndexerPersist : IIndexerPersist 10 | { 11 | public const byte VERSION = 40; 12 | 13 | private static readonly long MILLISECOND = 10000; 14 | private static readonly long SECOND = 1000 * MILLISECOND; 15 | private static readonly long MINUTE = 60 * SECOND; 16 | private static readonly long HOUR = 60 * MINUTE; 17 | private static readonly long DAY = 24 * HOUR; 18 | 19 | private readonly Int64IndexerPersist persist = new Int64IndexerPersist(new long[] { MILLISECOND, SECOND, MINUTE, HOUR, DAY }); 20 | 21 | public void Store(BinaryWriter writer, Func values, int count) 22 | { 23 | writer.Write(VERSION); 24 | 25 | persist.Store(writer, (i) => { return values(i).Ticks; }, count); 26 | } 27 | 28 | public void Load(BinaryReader reader, Action values, int count) 29 | { 30 | if (reader.ReadByte() != VERSION) 31 | throw new Exception("Invalid DateTimeIndexerPersist version."); 32 | 33 | persist.Load(reader, (i, v) => { values(i, new TimeSpan(v)); }, count); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /STSdb4/General/Threading/Countdown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | 7 | namespace STSdb4.General.Threading 8 | { 9 | public class Countdown 10 | { 11 | private long count; 12 | 13 | public void Increment() 14 | { 15 | Interlocked.Increment(ref count); 16 | } 17 | 18 | public void Decrement() 19 | { 20 | Interlocked.Decrement(ref count); 21 | } 22 | 23 | public void Wait() 24 | { 25 | SpinWait wait = new SpinWait(); 26 | 27 | wait.SpinOnce(); 28 | 29 | while (Count > 0) 30 | Thread.Sleep(1); 31 | } 32 | 33 | public long Count 34 | { 35 | get { return Interlocked.Read(ref count); } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /STSdb4/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("STSdb 4.0")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("STS Soft SC")] 12 | [assembly: AssemblyProduct("STSdb 4.0")] 13 | [assembly: AssemblyCopyright("© STS Soft SC 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fb2acc6f-a4b0-44e2-9034-19591ef35046")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("4.0.7.0")] 36 | [assembly: AssemblyFileVersion("4.0.7.0")] 37 | -------------------------------------------------------------------------------- /STSdb4/Remote/Commands/CommandCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.Remote.Commands 7 | { 8 | public class CommandCode 9 | { 10 | public const int UNDEFINED = 0; 11 | 12 | // XTable 13 | public const int REPLACE = 1; 14 | public const int DELETE = 2; 15 | public const int DELETE_RANGE = 3; 16 | public const int INSERT_OR_IGNORE = 4; 17 | public const int CLEAR = 5; 18 | 19 | public const int TRY_GET = 6; 20 | public const int FORWARD = 7; 21 | public const int BACKWARD = 8; 22 | public const int FIND_NEXT = 9; 23 | public const int FIND_AFTER = 10; 24 | public const int FIND_PREV = 11; 25 | public const int FIND_BEFORE = 12; 26 | public const int FIRST_ROW = 13; 27 | public const int LAST_ROW = 14; 28 | public const int COUNT = 15; 29 | 30 | public const int XTABLE_DESCRIPTOR_GET = 16; 31 | public const int XTABLE_DESCRIPTOR_SET = 17; 32 | 33 | // Storage engine 34 | public const int STORAGE_ENGINE_COMMIT = 22; 35 | public const int STORAGE_ENGINE_GET_ENUMERATOR = 23; 36 | public const int STORAGE_ENGINE_RENAME = 24; 37 | public const int STORAGE_ENGINE_EXISTS = 25; 38 | public const int STORAGE_ENGINE_FIND_BY_NAME = 26; 39 | public const int STORAGE_ENGINE_FIND_BY_ID = 27; 40 | public const int STORAGE_ENGINE_OPEN_XTABLE = 28; 41 | public const int STORAGE_ENGINE_OPEN_XFILE = 29; 42 | public const int STORAGE_ENGINE_DELETE = 30; 43 | public const int STORAGE_ENGINE_COUNT = 31; 44 | public const int STORAGE_ENGINE_DESCRIPTOR = 32; 45 | public const int STORAGE_ENGINE_GET_CACHE_SIZE = 33; 46 | public const int STORAGE_ENGINE_SET_CACHE_SIZE = 34; 47 | 48 | //Heap 49 | public const int HEAP_OBTAIN_NEW_HANDLE = 40; 50 | public const int HEAP_RELEASE_HANDLE = 41; 51 | public const int HEAP_EXISTS_HANDLE = 42; 52 | public const int HEAP_WRITE = 43; 53 | public const int HEAP_READ = 44; 54 | public const int HEAP_COMMIT = 45; 55 | public const int HEAP_CLOSE = 46; 56 | public const int HEAP_GET_TAG = 47; 57 | public const int HEAP_SET_TAG = 48; 58 | public const int HEAP_DATA_SIZE = 49; 59 | public const int HEAP_SIZE = 50; 60 | 61 | public const int EXCEPTION = 63; 62 | public const int MAX = 64; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /STSdb4/Remote/Commands/CommandCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.General.Extensions; 6 | 7 | namespace STSdb4.Remote.Commands 8 | { 9 | public class CommandCollection : List 10 | { 11 | public bool AreAllCommon { get; private set; } 12 | public int CommonAction { get; private set; } 13 | 14 | public CommandCollection(ICommand[] operations, bool areAllCommon, int commonCode) 15 | { 16 | this.SetArray(operations); 17 | 18 | AreAllCommon = areAllCommon; 19 | CommonAction = commonCode; 20 | } 21 | 22 | public CommandCollection(int capacity) 23 | : base(capacity) 24 | { 25 | AreAllCommon = true; 26 | CommonAction = CommandCode.UNDEFINED; 27 | } 28 | 29 | public new void Add(ICommand command) 30 | { 31 | if (AreAllCommon) 32 | { 33 | if (Count == 0) 34 | CommonAction = command.Code; 35 | 36 | if (command.Code != CommonAction) 37 | { 38 | AreAllCommon = false; 39 | CommonAction = CommandCode.UNDEFINED; 40 | } 41 | } 42 | 43 | base.Add(command); 44 | } 45 | 46 | public new ICommand this[int index] 47 | { 48 | get 49 | { 50 | return base[index]; 51 | } 52 | } 53 | 54 | public new void Clear() 55 | { 56 | base.Clear(); 57 | 58 | AreAllCommon = true; 59 | CommonAction = CommandCode.UNDEFINED; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /STSdb4/Remote/Commands/ICommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.WaterfallTree; 6 | 7 | namespace STSdb4.Remote.Commands 8 | { 9 | public interface ICommand 10 | { 11 | int Code { get; } 12 | bool IsSynchronous { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /STSdb4/Remote/Commands/ICommandsPersist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.Remote.Commands 8 | { 9 | public interface ICommandCollectionPersist 10 | { 11 | void Write(BinaryWriter writer, CommandCollection collection); 12 | CommandCollection Read(BinaryReader reader); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /STSdb4/Remote/Message.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text; 5 | using STSdb4.Data; 6 | using System.Collections.Generic; 7 | using STSdb4.WaterfallTree; 8 | using STSdb4.Database; 9 | using STSdb4.General.Persist; 10 | using STSdb4.Remote.Commands; 11 | 12 | namespace STSdb4.Remote 13 | { 14 | /// 15 | ///--------------------- Message Exchange Protocol 16 | /// 17 | ///--------------------- Comments----------------------------------- 18 | ///Format : binary 19 | ///Byte style : LittleEndian 20 | ///String Encoding : Unicode (UTF-8) 21 | ///String format : string int size compressed with 7-bit encoding, byte[] Unicode (UTF-8) 22 | /// 23 | ///------------------------------------------------------------------ 24 | ///ID : Long ID 25 | /// 26 | ///Commands : CommandCollection 27 | /// 28 | /// 29 | public class Message 30 | { 31 | public IDescriptor Description { get; private set; } 32 | public CommandCollection Commands { get; private set; } 33 | 34 | private static KeyValuePair PreviousRecord = new KeyValuePair(-1, null); 35 | 36 | public Message(IDescriptor description, CommandCollection commands) 37 | { 38 | Description = description; 39 | Commands = commands; 40 | } 41 | 42 | public void Serialize(BinaryWriter writer) 43 | { 44 | long ID = Description.ID; 45 | 46 | writer.Write(ID); 47 | 48 | CommandPersist persist = ID > 0 ? new CommandPersist(new DataPersist(Description.KeyType, null, AllowNull.OnlyMembers), new DataPersist(Description.RecordType, null, AllowNull.OnlyMembers)) : new CommandPersist(null, null); 49 | CommandCollectionPersist commandsPersist = new CommandCollectionPersist(persist); 50 | 51 | commandsPersist.Write(writer, Commands); 52 | } 53 | 54 | public static Message Deserialize(BinaryReader reader, Func find) 55 | { 56 | long ID = reader.ReadInt64(); 57 | 58 | IDescriptor description = null; 59 | CommandPersist persist = new CommandPersist(null, null); 60 | 61 | if (ID > 0) 62 | { 63 | try 64 | { 65 | description = PreviousRecord.Key == ID ? PreviousRecord.Value : find(ID); 66 | persist = new CommandPersist(new DataPersist(description.KeyType, null, AllowNull.OnlyMembers), new DataPersist(description.RecordType, null, AllowNull.OnlyMembers)); 67 | } 68 | catch (Exception exc) 69 | { 70 | throw new Exception("Cannot find description with the specified ID"); 71 | } 72 | 73 | if (PreviousRecord.Key != ID) 74 | PreviousRecord = new KeyValuePair(ID, description); 75 | } 76 | 77 | var commandsPersist = new CommandCollectionPersist(persist); 78 | CommandCollection commands = commandsPersist.Read(reader); 79 | 80 | return new Message(description, commands); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /STSdb4/Storage/AtomicHeader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.Storage 8 | { 9 | public class AtomicHeader 10 | { 11 | private const string TITLE = "STSdb 4.0"; 12 | /// 13 | /// http://en.wikipedia.org/wiki/Advanced_Format 14 | /// http://www.idema.org 15 | /// 16 | public const int SIZE = 4 * 1024; 17 | public const int MAX_TAG_DATA = 256; 18 | 19 | private byte[] tag; 20 | public int Version; 21 | public bool UseCompression; 22 | 23 | /// 24 | /// System data location. 25 | /// 26 | public Ptr SystemData; 27 | 28 | public void Serialize(Stream stream) 29 | { 30 | byte[] buffer = new byte[SIZE]; 31 | 32 | using (MemoryStream ms = new MemoryStream(buffer)) 33 | { 34 | BinaryWriter writer = new BinaryWriter(ms); 35 | writer.Write(TITLE); 36 | 37 | writer.Write(Version); 38 | writer.Write(UseCompression); 39 | 40 | //last flush location 41 | SystemData.Serialize(writer); 42 | 43 | //tag 44 | if (Tag == null) 45 | writer.Write((int)-1); 46 | else 47 | { 48 | writer.Write(Tag.Length); 49 | writer.Write(Tag); 50 | } 51 | } 52 | 53 | stream.Seek(0, SeekOrigin.Begin); 54 | stream.Write(buffer, 0, buffer.Length); 55 | } 56 | 57 | public static AtomicHeader Deserialize(Stream stream) 58 | { 59 | AtomicHeader header = new AtomicHeader(); 60 | 61 | stream.Seek(0, SeekOrigin.Begin); 62 | 63 | byte[] buffer = new byte[SIZE]; 64 | if (stream.Read(buffer, 0, SIZE) != SIZE) 65 | throw new Exception(String.Format("Invalid {0} header.", TITLE)); 66 | 67 | using (MemoryStream ms = new MemoryStream(buffer)) 68 | { 69 | BinaryReader reader = new BinaryReader(ms); 70 | 71 | string title = reader.ReadString(); 72 | if (title != TITLE) 73 | throw new Exception(String.Format("Invalid {0} header.", TITLE)); 74 | 75 | header.Version = reader.ReadInt32(); 76 | header.UseCompression = reader.ReadBoolean(); 77 | 78 | //last flush location 79 | header.SystemData = Ptr.Deserialize(reader); 80 | 81 | //tag 82 | int tagLength = reader.ReadInt32(); 83 | header.Tag = tagLength >= 0 ? reader.ReadBytes(tagLength) : null; 84 | } 85 | 86 | return header; 87 | } 88 | 89 | public byte[] Tag 90 | { 91 | get { return tag; } 92 | set 93 | { 94 | if (value != null && value.Length > MAX_TAG_DATA) 95 | throw new ArgumentException("Tag"); 96 | 97 | tag = value; 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /STSdb4/Storage/Pointer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.Storage 8 | { 9 | public class Pointer 10 | { 11 | public long Version; 12 | public Ptr Ptr; 13 | 14 | public bool IsReserved; 15 | public int RefCount; 16 | 17 | public Pointer(long version, Ptr ptr) 18 | { 19 | Version = version; 20 | Ptr = ptr; 21 | } 22 | 23 | public void Serialize(BinaryWriter writer) 24 | { 25 | writer.Write(Version); 26 | Ptr.Serialize(writer); 27 | } 28 | 29 | public static Pointer Deserialize(BinaryReader reader) 30 | { 31 | long version = reader.ReadInt64(); 32 | Ptr ptr = Ptr.Deserialize(reader); 33 | 34 | return new Pointer(version, ptr); 35 | } 36 | 37 | public override string ToString() 38 | { 39 | return String.Format("Version {0}, Ptr {1}", Version, Ptr); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /STSdb4/Storage/Ptr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | 9 | namespace STSdb4.Storage 10 | { 11 | [StructLayout(LayoutKind.Sequential)] 12 | public struct Ptr : IEquatable, IComparable 13 | { 14 | public static readonly Ptr NULL = new Ptr(0, 0); 15 | 16 | public long Position; 17 | public long Size; 18 | 19 | public const int SIZE = sizeof(long) + sizeof(long); 20 | 21 | [DebuggerStepThrough] 22 | public Ptr(long position, long size) 23 | { 24 | Position = position; 25 | Size = size; 26 | } 27 | 28 | #region IEquatable Members 29 | 30 | public bool Equals(Ptr other) 31 | { 32 | return Position == other.Position && 33 | Size == other.Size; 34 | } 35 | 36 | #endregion 37 | 38 | #region IComparable Members 39 | 40 | public int CompareTo(Ptr other) 41 | { 42 | return Position.CompareTo(other.Position); 43 | } 44 | 45 | #endregion 46 | 47 | public override bool Equals(object obj) 48 | { 49 | if (obj is Ptr) 50 | return this.Equals((Ptr)obj); 51 | 52 | return false; 53 | } 54 | 55 | public override int GetHashCode() 56 | { 57 | return Position.GetHashCode() ^ Size.GetHashCode(); 58 | } 59 | 60 | public override string ToString() 61 | { 62 | return String.Format("({0}, {1})", Position, Size); 63 | } 64 | 65 | public static bool operator ==(Ptr ptr1, Ptr ptr2) 66 | { 67 | return ptr1.Equals(ptr2); 68 | } 69 | 70 | public static bool operator !=(Ptr ptr1, Ptr ptr2) 71 | { 72 | return !(ptr1 == ptr2); 73 | } 74 | 75 | public static Ptr operator +(Ptr ptr, long offset) 76 | { 77 | return new Ptr(ptr.Position + offset, ptr.Size); 78 | } 79 | 80 | /// 81 | /// Checking whether the pointer is invalid. 82 | /// 83 | public bool IsNull 84 | { 85 | get { return this.Equals(NULL); } 86 | } 87 | 88 | /// 89 | /// Returns index of the block after fragment. 90 | /// 91 | public long PositionPlusSize 92 | { 93 | get { return checked(Position + Size); } 94 | } 95 | 96 | #region Serialize/Deserialize 97 | 98 | public void Serialize(BinaryWriter writer) 99 | { 100 | writer.Write(Position); 101 | writer.Write(Size); 102 | } 103 | 104 | public static Ptr Deserialize(BinaryReader reader) 105 | { 106 | long position = reader.ReadInt64(); 107 | long size = reader.ReadInt64(); 108 | 109 | return new Ptr(position, size); 110 | } 111 | 112 | #endregion 113 | 114 | public bool Contains(long position) 115 | { 116 | return Position <= position && position < PositionPlusSize; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/IApply.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.Database; 3 | using STSdb4.General.Collections; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace STSdb4.WaterfallTree 10 | { 11 | public interface IApply 12 | { 13 | /// 14 | /// Compact the operations and returns true, if the collection was modified. 15 | /// 16 | bool Internal(IOperationCollection operations); 17 | 18 | bool Leaf(IOperationCollection operations, IOrderedSet data); 19 | 20 | Locator Locator { get; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/IDataContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections; 6 | using STSdb4.Data; 7 | using STSdb4.General.Collections; 8 | 9 | namespace STSdb4.WaterfallTree 10 | { 11 | public interface IDataContainer : IOrderedSet 12 | { 13 | double FillPercentage { get; } 14 | 15 | bool IsEmpty { get; } 16 | /// 17 | /// Exclude and returns the right half part of the ordered set. 18 | /// 19 | IDataContainer Split(double percentage); 20 | 21 | /// 22 | /// Merge the specified set to the current set. The engine ensures, that all keys from the one set are less/greater than all keys from the other set. 23 | /// 24 | void Merge(IDataContainer data); 25 | 26 | IData FirstKey { get; } 27 | IData LastKey { get; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/IDescriptor.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.General.Persist; 2 | using STSdb4.Data; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace STSdb4.WaterfallTree 9 | { 10 | //[Flags] 11 | //public enum CustomData : byte 12 | //{ 13 | // None = 0, 14 | // KeyType = 1, 15 | // RecordType = 2, 16 | // KeyComparer = 4, 17 | // KeyEqualityComparer = 8, 18 | // KeyPersist = 16, 19 | // RecordPersist = 32, 20 | // KeyIndexerPersist = 64, 21 | // RecordIndexerPersist = 128, 22 | 23 | // All = KeyType | RecordType | KeyComparer | KeyEqualityComparer | KeyPersist | RecordPersist | KeyIndexerPersist | RecordIndexerPersist 24 | //} 25 | 26 | public interface IDescriptor 27 | { 28 | long ID { get; } 29 | string Name { get; } 30 | int StructureType { get; } 31 | 32 | /// 33 | /// Describes the KeyType 34 | /// 35 | DataType KeyDataType { get; } 36 | 37 | /// 38 | /// Describes the RecordType 39 | /// 40 | DataType RecordDataType { get; } 41 | 42 | /// 43 | /// Can be anonymous or user type 44 | /// 45 | Type KeyType { get; set; } 46 | 47 | /// 48 | /// Can be anonymous or user type 49 | /// 50 | Type RecordType { get; set; } 51 | 52 | IComparer KeyComparer { get; set; } 53 | IEqualityComparer KeyEqualityComparer { get; set; } 54 | IPersist KeyPersist { get; set; } 55 | IPersist RecordPersist { get; set; } 56 | IIndexerPersist KeyIndexerPersist { get; set; } 57 | IIndexerPersist RecordIndexerPersist { get; set; } 58 | 59 | DateTime CreateTime { get; } 60 | DateTime ModifiedTime { get; } 61 | DateTime AccessTime { get; } 62 | 63 | byte[] Tag { get; set; } 64 | } 65 | } -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/IHeap.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Storage; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.WaterfallTree 8 | { 9 | /// 10 | /// Gives opportunity to write and read blocks referenced by logical keys (handles). The heap implementations must provide atomic commit of all writes (all or nothing) and must be thread-safe. 11 | /// The heap implementation can rely on the fact that the majority of the created by the engine blocks are with relatively large size (> 2MB). 12 | /// 13 | public interface IHeap 14 | { 15 | /// 16 | /// Register new handle. The returned handle must be always unique. 17 | /// 18 | long ObtainNewHandle(); 19 | 20 | /// 21 | /// Release the allocated space behind the handle. 22 | /// 23 | void Release(long handle); 24 | 25 | /// 26 | /// Is there such handle in the heap 27 | /// 28 | bool Exists(long handle); 29 | 30 | /// 31 | /// Write data with the specified handle 32 | /// 33 | void Write(long handle, byte[] buffer, int index, int count); 34 | 35 | /// 36 | /// Read the current data behind the handle 37 | /// 38 | byte[] Read(long handle); 39 | 40 | /// 41 | /// Atomic commit ALL changes in the heap (all or nothing). 42 | /// 43 | void Commit(); 44 | 45 | /// 46 | /// Close the heap and release any resources 47 | /// 48 | void Close(); 49 | 50 | /// 51 | /// Small user data (usually less than one physical sector), atomic written with the Commit() 52 | /// 53 | byte[] Tag { get; set; } 54 | 55 | /// 56 | /// Total size in bytes of the user data 57 | /// 58 | long DataSize { get; } 59 | 60 | /// 61 | /// Total size in bytes of the heap. 62 | /// 63 | long Size { get; } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/IOperation.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.WaterfallTree 8 | { 9 | public enum OperationScope : byte 10 | { 11 | Point, 12 | Range, 13 | Overall 14 | } 15 | 16 | public interface IOperation 17 | { 18 | int Code { get; } 19 | OperationScope Scope { get; } 20 | 21 | IData FromKey { get; } 22 | IData ToKey { get; } 23 | } 24 | } -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/IOperationCollection.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.Database; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace STSdb4.WaterfallTree 9 | { 10 | public interface IOperationCollection : IEnumerable 11 | { 12 | void Add(IOperation operation); 13 | void AddRange(IOperationCollection operations); 14 | void Clear(); 15 | 16 | IOperation this[int index] { get; } 17 | int Count { get; } 18 | int Capacity { get; } 19 | 20 | IOperationCollection Midlle(int index, int count); 21 | int BinarySearch(IData key, int index, int count); 22 | 23 | int CommonAction { get; } 24 | bool AreAllMonotoneAndPoint { get; } 25 | 26 | Locator Locator { get; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/IOperationCollectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STSdb4.WaterfallTree 7 | { 8 | public interface IOperationCollectionFactory 9 | { 10 | IOperationCollection Create(int capacity); 11 | IOperationCollection Create(IOperation[] operations, int commonAction, bool areAllMonotoneAndPoint); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/Scheme.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.Database; 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Concurrent; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading; 11 | 12 | namespace STSdb4.WaterfallTree 13 | { 14 | public class Scheme : IEnumerable> 15 | { 16 | public const byte VERSION = 40; 17 | 18 | private long locatorID = Locator.MIN.ID; 19 | 20 | private ConcurrentDictionary map = new ConcurrentDictionary(); 21 | 22 | private long ObtainPathID() 23 | { 24 | return Interlocked.Increment(ref locatorID); 25 | } 26 | 27 | public void Serialize(BinaryWriter writer) 28 | { 29 | writer.Write(VERSION); 30 | 31 | writer.Write(locatorID); 32 | writer.Write(map.Count); 33 | 34 | foreach (var kv in map) 35 | { 36 | Locator locator = (Locator)kv.Value; 37 | locator.Serialize(writer); 38 | } 39 | } 40 | 41 | public static Scheme Deserialize(BinaryReader reader) 42 | { 43 | if (reader.ReadByte() != VERSION) 44 | throw new Exception("Invalid Scheme version."); 45 | 46 | Scheme scheme = new Scheme(); 47 | 48 | scheme.locatorID = reader.ReadInt64(); 49 | int count = reader.ReadInt32(); 50 | 51 | for (int i = 0; i < count; i++) 52 | { 53 | var locator = Locator.Deserialize(reader); 54 | 55 | scheme.map[locator.ID] = locator; 56 | 57 | //Do not prepare the locator yet 58 | } 59 | 60 | return scheme; 61 | } 62 | 63 | public Locator this[long id] 64 | { 65 | get { return map[id]; } 66 | } 67 | 68 | public Locator Create(string name, int structureType, DataType keyDataType, DataType recordDataType, Type keyType, Type recordType) 69 | { 70 | var id = ObtainPathID(); 71 | 72 | var locator = new Locator(id, name, structureType, keyDataType, recordDataType, keyType, recordType); 73 | 74 | map[id] = locator; 75 | 76 | return locator; 77 | } 78 | 79 | public int Count 80 | { 81 | get { return map.Count; } 82 | } 83 | 84 | public IEnumerator> GetEnumerator() 85 | { 86 | return map.GetEnumerator(); 87 | } 88 | 89 | IEnumerator IEnumerable.GetEnumerator() 90 | { 91 | return GetEnumerator(); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/SentinelPersistKey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using STSdb4.General.Persist; 7 | using STSdb4.Data; 8 | using STSdb4.WaterfallTree; 9 | 10 | namespace STSdb4.WaterfallTree 11 | { 12 | public class SentinelPersistKey : IPersist 13 | { 14 | public static readonly SentinelPersistKey Instance = new SentinelPersistKey(); 15 | 16 | public void Write(BinaryWriter writer, IData item) 17 | { 18 | } 19 | 20 | public IData Read(BinaryReader reader) 21 | { 22 | return null; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/TypeCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | 8 | namespace STSdb4.WaterfallTree 9 | { 10 | public class TypeCache 11 | { 12 | private static readonly ConcurrentDictionary cache = new ConcurrentDictionary(); 13 | 14 | public static Type GetType(string fullName) 15 | { 16 | var type = Type.GetType(fullName, false); 17 | if (type != null) 18 | return type; 19 | 20 | return cache.GetOrAdd(fullName, (x) => 21 | { 22 | foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 23 | { 24 | type = assembly.GetType(fullName); 25 | if (type != null) 26 | return type; 27 | } 28 | 29 | return null; //once return null - always return null 30 | }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/TypeEngine.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.General.Persist; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace STSdb4.WaterfallTree 10 | { 11 | public class TypeEngine 12 | { 13 | private static readonly ConcurrentDictionary map = new ConcurrentDictionary(); 14 | 15 | public IComparer Comparer { get; set; } 16 | public IEqualityComparer EqualityComparer { get; set; } 17 | public IPersist Persist { get; set; } 18 | public IIndexerPersist IndexerPersist { get; set; } 19 | 20 | public TypeEngine() 21 | { 22 | } 23 | 24 | private static TypeEngine Create(Type type) 25 | { 26 | TypeEngine descriptor = new TypeEngine(); 27 | 28 | descriptor.Persist = new DataPersist(type, null, AllowNull.OnlyMembers); 29 | 30 | if (DataTypeUtils.IsAllPrimitive(type) || type == typeof(Guid)) 31 | { 32 | descriptor.Comparer = new DataComparer(type); 33 | descriptor.EqualityComparer = new DataEqualityComparer(type); 34 | 35 | if (type != typeof(Guid)) 36 | descriptor.IndexerPersist = new DataIndexerPersist(type); 37 | } 38 | 39 | return descriptor; 40 | } 41 | 42 | public static TypeEngine Default(Type type) 43 | { 44 | return map.GetOrAdd(type, Create(type)); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/WTree.Branch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | using STSdb4.Database; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using System.Collections; 10 | using System.IO; 11 | 12 | namespace STSdb4.WaterfallTree 13 | { 14 | public partial class WTree 15 | { 16 | private partial class Branch 17 | { 18 | public readonly WTree Tree; 19 | public BranchCache Cache = new BranchCache(); 20 | 21 | /// 22 | /// on load 23 | /// 24 | public Branch(WTree tree, NodeType nodeType, long nodeHandle) 25 | { 26 | Tree = tree; 27 | NodeType = nodeType; 28 | NodeHandle = nodeHandle; 29 | } 30 | 31 | /// 32 | /// on brand new branch 33 | /// 34 | public Branch(WTree tree, NodeType nodeType) 35 | : this(tree, nodeType, tree.heap.ObtainNewHandle()) 36 | { 37 | node = WTree.Node.Create(this); 38 | } 39 | 40 | public override string ToString() 41 | { 42 | return String.Format("NodeType = {0}, Handle = {1}, IsNodeLoaded = {2}, Cache.OperationCount = {3}", NodeType, NodeHandle, IsNodeLoaded, Cache.OperationCount); 43 | } 44 | 45 | #region Node 46 | 47 | public NodeType NodeType; 48 | 49 | /// 50 | /// permanent and unique node handle 51 | /// 52 | public long NodeHandle { get; set; } 53 | 54 | public volatile NodeState NodeState; 55 | 56 | public bool IsNodeLoaded 57 | { 58 | get { return node != null; } 59 | } 60 | 61 | private Node node; 62 | 63 | public Node Node 64 | { 65 | get 66 | { 67 | if (node != null) 68 | return node; 69 | 70 | node = Tree.Retrieve(NodeHandle); 71 | 72 | if (node != null) 73 | { 74 | node.Branch.WaitFall(); 75 | node.Branch = this; 76 | Tree.Packet(NodeHandle, node); 77 | } 78 | else 79 | { 80 | node = WTree.Node.Create(this); 81 | node.Load(); 82 | } 83 | 84 | return node; 85 | } 86 | set 87 | { 88 | node = value; 89 | } 90 | } 91 | 92 | #endregion 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/WTree.BranchCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Threading; 8 | using STSdb4.General.Compression; 9 | using STSdb4.General.Collections; 10 | using STSdb4.General.Comparers; 11 | using STSdb4.General.Extensions; 12 | 13 | namespace STSdb4.WaterfallTree 14 | { 15 | public partial class WTree 16 | { 17 | [DebuggerDisplay("Count = {Count}")] 18 | private class BranchCollection : List> 19 | { 20 | public static readonly KeyValuePairComparer Comparer = new KeyValuePairComparer(Comparer.Default); 21 | 22 | public BranchCollection() 23 | { 24 | } 25 | 26 | public BranchCollection(int capacity) 27 | : base(capacity) 28 | { 29 | } 30 | 31 | 32 | public BranchCollection(params KeyValuePair[] array) 33 | : base(array) 34 | { 35 | } 36 | 37 | public BranchCollection(IEnumerable> collection) 38 | : base(collection) 39 | { 40 | } 41 | 42 | public int BinarySearch(FullKey locator, int index, int length, IComparer> comparer) 43 | { 44 | return this.BinarySearch(index, length, new KeyValuePair(locator, null), comparer); 45 | } 46 | 47 | public int BinarySearch(FullKey locator, int index, int length) 48 | { 49 | return BinarySearch(locator, index, length, BranchCollection.Comparer); 50 | } 51 | 52 | public int BinarySearch(FullKey locator) 53 | { 54 | return BinarySearch(locator, 0, Count); 55 | } 56 | 57 | public void Add(FullKey locator, Branch branch) 58 | { 59 | Add(new KeyValuePair(locator, branch)); 60 | } 61 | 62 | public IEnumerable> Range(int fromIndex, int toIndex) 63 | { 64 | for (int i = fromIndex; i <= toIndex; i++) 65 | yield return this[i]; 66 | } 67 | 68 | public void Store(WTree tree, BinaryWriter writer) 69 | { 70 | CountCompression.Serialize(writer, checked((ulong)Count)); 71 | 72 | Debug.Assert(Count > 0); 73 | writer.Write((byte)this[0].Value.NodeType); 74 | 75 | for (int i = 0; i < Count; i++) 76 | { 77 | var kv = this[i]; 78 | FullKey fullkey = kv.Key; 79 | Branch branch = kv.Value; 80 | //lock (branch) 81 | //{ 82 | //} 83 | 84 | //write locator 85 | tree.SerializeLocator(writer, fullkey.Locator); 86 | fullkey.Locator.KeyPersist.Write(writer, fullkey.Key); 87 | 88 | //write branch info 89 | writer.Write(branch.NodeHandle); 90 | writer.Write((int)branch.NodeState); 91 | 92 | branch.Cache.Store(tree, writer); 93 | } 94 | } 95 | 96 | public void Load(WTree tree, BinaryReader reader) 97 | { 98 | int count = (int)CountCompression.Deserialize(reader); 99 | Capacity = count; 100 | 101 | NodeType nodeType = (NodeType)reader.ReadByte(); 102 | 103 | for (int i = 0; i < count; i++) 104 | { 105 | //read fullKey 106 | var locator = tree.DeserializeLocator(reader); 107 | var key = locator.KeyPersist.Read(reader); 108 | var fullKey = new FullKey(locator, key); 109 | 110 | //read branch info 111 | long nodeID = reader.ReadInt64(); 112 | NodeState nodeState = (NodeState)reader.ReadInt32(); 113 | 114 | Branch branch = new Branch(tree, nodeType, nodeID); 115 | branch.NodeState = nodeState; 116 | 117 | branch.Cache.Load(tree, reader); 118 | 119 | Add(new KeyValuePair(fullKey, branch)); 120 | } 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/WTree.BranchesOptimizator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | using System.Collections.Concurrent; 7 | using STSdb4.Data; 8 | using STSdb4.Database; 9 | 10 | namespace STSdb4.WaterfallTree 11 | { 12 | public partial class WTree 13 | { 14 | private class BranchesOptimizator 15 | { 16 | private const int MAP_CAPACITY = 131072; 17 | private ConcurrentDictionary Map = new ConcurrentDictionary(); 18 | private BranchCollection Branches; 19 | 20 | public BranchesOptimizator() 21 | { 22 | } 23 | 24 | public void Rebuild(BranchCollection branches) 25 | { 26 | Branches = branches; 27 | Map = BuildRanges(); 28 | } 29 | 30 | private ConcurrentDictionary BuildRanges() 31 | { 32 | ConcurrentDictionary map = new ConcurrentDictionary(); 33 | var locator = Branches[0].Key.Locator; 34 | Range range = new Range(0, true); 35 | map[locator] = range; 36 | 37 | for (int i = 1; i < Branches.Count; i++) 38 | { 39 | var newLocator = Branches[i].Key.Locator; 40 | 41 | if (newLocator.Equals(locator)) 42 | { 43 | range.LastIndex = i; 44 | continue; 45 | } 46 | 47 | locator = newLocator; 48 | map[locator] = range = new Range(i, true); 49 | } 50 | 51 | return map; 52 | } 53 | 54 | public Range FindRange(Locator locator) 55 | { 56 | Range range; 57 | 58 | if (Map.TryGetValue(locator, out range)) 59 | return range; 60 | 61 | int idx = Branches.BinarySearch(new FullKey(locator, null)); 62 | Debug.Assert(idx < 0); 63 | idx = ~idx - 1; 64 | Debug.Assert(idx >= 0); 65 | 66 | Map[locator] = range = new Range(idx, false); 67 | 68 | if (Map.Count > MAP_CAPACITY) 69 | Map = BuildRanges(); //TODO: background rebuild 70 | 71 | return range; 72 | } 73 | 74 | public int FindIndex(Range range, Locator locator, IData key) 75 | { 76 | if (!range.IsBaseLocator) 77 | return range.LastIndex; 78 | 79 | int cmp = locator.KeyComparer.Compare(key, Branches[range.LastIndex].Key.Key); 80 | if (cmp >= 0) 81 | return range.LastIndex; 82 | 83 | if (range.FirstIndex == range.LastIndex) 84 | return range.LastIndex - 1; 85 | 86 | int idx = Branches.BinarySearch(new FullKey(locator, key), range.FirstIndex, range.LastIndex - range.FirstIndex, LightComparer.Instance); 87 | if (idx < 0) 88 | idx = ~idx - 1; 89 | 90 | return idx; 91 | } 92 | 93 | private class LightComparer : IComparer> 94 | { 95 | public readonly static LightComparer Instance = new LightComparer(); 96 | 97 | public int Compare(KeyValuePair x, KeyValuePair y) 98 | { 99 | //Debug.Assert(x.Key.Path.Equals(y.Key.Path)); 100 | 101 | return x.Key.Locator.KeyComparer.Compare(x.Key.Key, y.Key.Key); 102 | } 103 | } 104 | } 105 | 106 | [DebuggerDisplay("FirstIndex = {FirstIndex}, LastIndex = {LastIndex}, IsBaseLocator = {IsBaseLocator}")] 107 | private class Range 108 | { 109 | public int FirstIndex; 110 | public int LastIndex; 111 | public bool IsBaseLocator; 112 | 113 | public Range(int firstIndex, bool baseLocator) 114 | { 115 | FirstIndex = firstIndex; 116 | LastIndex = firstIndex; 117 | IsBaseLocator = baseLocator; 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/WTree.FullKey.cs: -------------------------------------------------------------------------------- 1 | using STSdb4.Data; 2 | using STSdb4.Database; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace STSdb4.WaterfallTree 9 | { 10 | public partial class WTree 11 | { 12 | public struct FullKey : IComparable, IEquatable 13 | { 14 | public readonly Locator Locator; 15 | public readonly IData Key; 16 | 17 | public FullKey(Locator locator, IData key) 18 | { 19 | Locator = locator; 20 | Key = key; 21 | } 22 | 23 | public override string ToString() 24 | { 25 | return String.Format("Locator = {0}, Key = {1}", Locator, Key); 26 | } 27 | 28 | #region IComparable Members 29 | 30 | public int CompareTo(FullKey other) 31 | { 32 | int cmp = Locator.CompareTo(other.Locator); 33 | if (cmp != 0) 34 | return cmp; 35 | 36 | return Locator.KeyComparer.Compare(Key, other.Key); 37 | } 38 | 39 | #endregion 40 | 41 | #region IEquatable Members 42 | 43 | public override int GetHashCode() 44 | { 45 | return Locator.GetHashCode() ^ Key.GetHashCode(); 46 | } 47 | 48 | public bool Equals(FullKey other) 49 | { 50 | if (!Locator.Equals(other.Locator)) 51 | return false; 52 | 53 | return Locator.KeyEqualityComparer.Equals(Key, other.Key); 54 | } 55 | 56 | #endregion 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/WTree.Header.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace STSdb4.WaterfallTree 8 | { 9 | public partial class WTree 10 | { 11 | private static class Settings 12 | { 13 | public static void Serialize(WTree tree, Stream stream) 14 | { 15 | BinaryWriter writer = new BinaryWriter(stream); 16 | 17 | const int VERSION = 1; 18 | writer.Write(VERSION); 19 | 20 | switch (VERSION) 21 | { 22 | //case 0: 23 | // { 24 | // writer.Write(tree.GlobalVersion); 25 | // writer.Write(tree.RootBranch.NodeHandle); 26 | // writer.Write((byte)tree.RootBranch.NodeType); 27 | // writer.Write(tree.Depth); 28 | // writer.Write(tree.INTERNAL_NODE_MAX_OPERATIONS_IN_ROOT); 29 | // writer.Write(tree.INTERNAL_NODE_MIN_BRANCHES); 30 | // writer.Write(tree.INTERNAL_NODE_MAX_BRANCHES); 31 | // writer.Write(tree.INTERNAL_NODE_MIN_OPERATIONS); 32 | // writer.Write(tree.INTERNAL_NODE_MAX_OPERATIONS); 33 | // } 34 | // break; 35 | case 1: 36 | { 37 | writer.Write(tree.GlobalVersion); 38 | writer.Write(tree.RootBranch.NodeHandle); 39 | writer.Write((byte)tree.RootBranch.NodeType); 40 | writer.Write(tree.Depth); 41 | 42 | writer.Write(tree.INTERNAL_NODE_MIN_BRANCHES); 43 | writer.Write(tree.INTERNAL_NODE_MAX_BRANCHES); 44 | writer.Write(tree.INTERNAL_NODE_MAX_OPERATIONS_IN_ROOT); 45 | writer.Write(tree.INTERNAL_NODE_MIN_OPERATIONS); 46 | writer.Write(tree.INTERNAL_NODE_MAX_OPERATIONS); 47 | writer.Write(tree.LEAF_NODE_MIN_RECORDS); 48 | writer.Write(tree.LEAF_NODE_MAX_RECORDS); 49 | } 50 | break; 51 | } 52 | } 53 | 54 | public static void Deserialize(WTree tree, Stream stream) 55 | { 56 | BinaryReader reader = new BinaryReader(stream); 57 | int version = reader.ReadInt32(); 58 | 59 | switch (version) 60 | { 61 | case 0: 62 | { 63 | tree.GlobalVersion = reader.ReadInt64(); 64 | tree.RootBranch.NodeHandle = reader.ReadInt64(); 65 | tree.RootBranch.NodeType = (NodeType)reader.ReadByte(); 66 | tree.Depth = reader.ReadInt32(); 67 | tree.INTERNAL_NODE_MAX_OPERATIONS_IN_ROOT = reader.ReadInt32(); 68 | tree.INTERNAL_NODE_MIN_BRANCHES = reader.ReadInt32(); 69 | tree.INTERNAL_NODE_MAX_BRANCHES = reader.ReadInt32(); 70 | tree.INTERNAL_NODE_MIN_OPERATIONS = reader.ReadInt32(); 71 | tree.INTERNAL_NODE_MAX_OPERATIONS = reader.ReadInt32(); 72 | } 73 | break; 74 | case 1: //from 4.0.3 75 | { 76 | tree.GlobalVersion = reader.ReadInt64(); 77 | tree.RootBranch.NodeHandle = reader.ReadInt64(); 78 | tree.RootBranch.NodeType = (NodeType)reader.ReadByte(); 79 | tree.Depth = reader.ReadInt32(); 80 | 81 | tree.INTERNAL_NODE_MIN_BRANCHES = reader.ReadInt32(); 82 | tree.INTERNAL_NODE_MAX_BRANCHES = reader.ReadInt32(); 83 | tree.INTERNAL_NODE_MAX_OPERATIONS_IN_ROOT = reader.ReadInt32(); 84 | tree.INTERNAL_NODE_MIN_OPERATIONS = reader.ReadInt32(); 85 | tree.INTERNAL_NODE_MAX_OPERATIONS = reader.ReadInt32(); 86 | tree.LEAF_NODE_MIN_RECORDS = reader.ReadInt32(); 87 | tree.LEAF_NODE_MAX_RECORDS = reader.ReadInt32(); 88 | } 89 | break; 90 | 91 | default: 92 | throw new NotSupportedException("Unknown WTree header version."); 93 | } 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /STSdb4/WaterfallTree/WTree.Node.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | using System.Threading; 7 | using System.IO; 8 | using System.IO.Compression; 9 | using STSdb4.General.Compression; 10 | 11 | namespace STSdb4.WaterfallTree 12 | { 13 | public partial class WTree 14 | { 15 | private abstract class Node 16 | { 17 | public bool IsModified { get; protected set; } 18 | public Branch Branch; 19 | public volatile bool IsExpiredFromCache; 20 | #if DEBUG 21 | public volatile int TaskID; 22 | #endif 23 | private static long globalTouchID = 0; 24 | private long touchID; 25 | 26 | public long TouchID 27 | { 28 | get { return Interlocked.Read(ref touchID); } 29 | set { Interlocked.Exchange(ref touchID, value); } 30 | } 31 | 32 | public Node(Branch branch) 33 | { 34 | Branch = branch; 35 | } 36 | 37 | public abstract void Apply(IOperationCollection operations); 38 | public abstract Node Split(); 39 | public abstract void Merge(Node node); 40 | public abstract bool IsOverflow { get; } 41 | public abstract bool IsUnderflow { get; } 42 | public abstract FullKey FirstKey { get; } 43 | 44 | public abstract void Store(Stream stream); 45 | public abstract void Load(Stream stream); 46 | 47 | public void Touch(long count) 48 | { 49 | Debug.Assert(count > 0); 50 | touchID = Interlocked.Add(ref globalTouchID, count); 51 | 52 | //IsExpiredFromCache = false; 53 | } 54 | 55 | //only for speed reason 56 | public NodeType Type 57 | { 58 | get { return Branch.NodeType; } 59 | } 60 | 61 | public bool IsRoot 62 | { 63 | get { return Object.ReferenceEquals(Branch.Tree.RootBranch, Branch); } 64 | } 65 | 66 | public NodeState State 67 | { 68 | get 69 | { 70 | if (IsOverflow) 71 | return NodeState.Overflow; 72 | 73 | if (IsUnderflow) 74 | return NodeState.Underflow; 75 | 76 | return NodeState.None; 77 | } 78 | } 79 | 80 | public void Store() 81 | { 82 | using (MemoryStream stream = new MemoryStream()) 83 | { 84 | Store(stream); 85 | 86 | //int recordCount = 0; 87 | //string type = ""; 88 | //if (this is InternalNode) 89 | //{ 90 | // recordCount = ((InternalNode)this).Branch.Cache.OperationCount; 91 | // type = "Internal"; 92 | //} 93 | //else 94 | //{ 95 | // recordCount = ((LeafNode)this).RecordCount; 96 | // type = "Leaf"; 97 | //} 98 | //double sizeInMB = Math.Round(stream.Length / (1024.0 * 1024), 2); 99 | //Console.WriteLine("{0} {1}, Records {2}, Size {3} MB", type, Branch.NodeHandle, recordCount, sizeInMB); 100 | 101 | Branch.Tree.heap.Write(Branch.NodeHandle, stream.GetBuffer(), 0, (int)stream.Length); 102 | } 103 | } 104 | 105 | public void Load() 106 | { 107 | var heap = Branch.Tree.heap; 108 | byte[] buffer = heap.Read(Branch.NodeHandle); 109 | Load(new MemoryStream(buffer)); 110 | } 111 | 112 | public static Node Create(Branch branch) 113 | { 114 | Node node; 115 | switch (branch.NodeType) 116 | { 117 | case WTree.NodeType.Leaf: 118 | node = new LeafNode(branch, true); 119 | break; 120 | case WTree.NodeType.Internal: 121 | node = new InternalNode(branch, new BranchCollection(), true); 122 | break; 123 | default: 124 | throw new NotSupportedException(); 125 | } 126 | 127 | branch.Tree.Packet(node.Branch.NodeHandle, node); 128 | return node; 129 | } 130 | } 131 | 132 | public enum NodeState 133 | { 134 | None, 135 | Overflow, 136 | Underflow 137 | } 138 | 139 | protected enum NodeType : byte 140 | { 141 | Leaf, 142 | Internal 143 | } 144 | } 145 | } 146 | --------------------------------------------------------------------------------