-
Notifications
You must be signed in to change notification settings - Fork 100
/
Store.cs
124 lines (104 loc) · 4.02 KB
/
Store.cs
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using Neo.IO.Caching;
using Neo.Persistence;
using RocksDbSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Neo.Plugins.Storage
{
internal class Store : IStore
{
private static readonly byte[] SYS_Version = { 0xf0 };
private readonly RocksDb db;
private readonly Dictionary<byte, ColumnFamilyHandle> _families = new Dictionary<byte, ColumnFamilyHandle>();
public Store(string path)
{
var families = new ColumnFamilies();
try
{
foreach (var family in RocksDb.ListColumnFamilies(Options.Default, Path.GetFullPath(path)))
{
families.Add(new ColumnFamilies.Descriptor(family, new ColumnFamilyOptions()));
}
}
catch { }
db = RocksDb.Open(Options.Default, Path.GetFullPath(path), families);
ColumnFamilyHandle defaultFamily = db.GetDefaultColumnFamily();
byte[] value = db.Get(SYS_Version, defaultFamily, Options.ReadDefault);
if (value != null && Version.TryParse(Encoding.ASCII.GetString(value), out Version version) && version >= Version.Parse("3.0.0"))
return;
if (value != null)
{
// Clean all families only if the version are different
Parallel.For(0, byte.MaxValue + 1, (x) => db.DropColumnFamily(x.ToString()));
_families.Clear();
}
// Update version
db.Put(SYS_Version, Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().GetName().Version.ToString()), defaultFamily, Options.WriteDefault);
}
public void Dispose()
{
db.Dispose();
_families.Clear();
}
/// <summary>
/// Get family
/// </summary>
/// <param name="table">Table</param>
/// <returns>Return column family</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ColumnFamilyHandle GetFamily(byte table)
{
if (!_families.TryGetValue(table, out var family))
{
try
{
// Try to find the family
family = db.GetColumnFamily(table.ToString());
_families.Add(table, family);
}
catch (KeyNotFoundException)
{
// Try to create the family
family = db.CreateColumnFamily(new ColumnFamilyOptions(), table.ToString());
_families.Add(table, family);
}
}
return family;
}
public ISnapshot GetSnapshot()
{
return new Snapshot(this, db);
}
public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward)
{
using var it = db.NewIterator(GetFamily(table), Options.ReadDefault);
if (direction == SeekDirection.Forward)
for (it.Seek(keyOrPrefix); it.Valid(); it.Next())
yield return (it.Key(), it.Value());
else
for (it.SeekForPrev(keyOrPrefix); it.Valid(); it.Prev())
yield return (it.Key(), it.Value());
}
public byte[] TryGet(byte table, byte[] key)
{
return db.Get(key, GetFamily(table), Options.ReadDefault);
}
public void Delete(byte table, byte[] key)
{
db.Remove(key, GetFamily(table), Options.WriteDefault);
}
public void Put(byte table, byte[] key, byte[] value)
{
db.Put(key, value, GetFamily(table), Options.WriteDefault);
}
public void PutSync(byte table, byte[] key, byte[] value)
{
db.Put(key, value, GetFamily(table), Options.WriteDefaultSync);
}
}
}