Skip to content

Commit 8cb87df

Browse files
committed
Fixes #118. Add schema reading on connect.
1 parent 032f209 commit 8cb87df

File tree

16 files changed

+220
-153
lines changed

16 files changed

+220
-153
lines changed

src/progaudi.tarantool/Box.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ public Box(ClientOptions options)
1919

2020
_logicalConnection = new LogicalConnectionManager(options);
2121
Metrics = new Metrics(_logicalConnection);
22+
Schema = new Schema(_logicalConnection);
2223
}
2324

2425
public async Task Connect()
2526
{
2627
await _logicalConnection.Connect().ConfigureAwait(false);
28+
await ReloadSchema().ConfigureAwait(false);
2729
}
2830

2931
public static async Task<Box> Connect(string replicationSource)
@@ -57,10 +59,14 @@ public void Dispose()
5759
_logicalConnection.Dispose();
5860
}
5961

60-
public ISchema GetSchema()
62+
public ISchema GetSchema() => Schema;
63+
64+
public ISchema Schema { get; }
65+
66+
public Task ReloadSchema()
6167
{
62-
_clientOptions.LogWriter?.WriteLine("Schema acquiring...");
63-
return new Schema(_logicalConnection);
68+
_clientOptions.LogWriter?.WriteLine("Schema reloading...");
69+
return Schema.Reload();
6470
}
6571

6672
public async Task Call_1_6(string functionName)

src/progaudi.tarantool/Converters/CallPacketConverter.cs

-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System;
22

33
using ProGaudi.MsgPack.Light;
4-
5-
using ProGaudi.Tarantool.Client.Model;
64
using ProGaudi.Tarantool.Client.Model.Enums;
75
using ProGaudi.Tarantool.Client.Model.Requests;
86

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using ProGaudi.MsgPack.Light;
1+
using System.Runtime.Serialization;
2+
using ProGaudi.MsgPack.Light;
23

34
using ProGaudi.Tarantool.Client.Model;
45
using ProGaudi.Tarantool.Client.Model.Enums;
@@ -10,31 +11,118 @@ internal class IndexPartConverter : IMsgPackConverter<IndexPart>
1011
{
1112
private IMsgPackConverter<uint> _uintConverter;
1213
private IMsgPackConverter<IndexPartType> _indexPartTypeConverter;
14+
private IMsgPackConverter<string> _stringConverter;
1315

1416
public void Initialize(MsgPackContext context)
1517
{
1618
_uintConverter = context.GetConverter<uint>();
1719
_indexPartTypeConverter = context.GetConverter<IndexPartType>();
20+
_stringConverter = context.GetConverter<string>();
1821
}
1922

20-
public void Write(IndexPart value, IMsgPackWriter writer)
23+
public void Write(IndexPart value, IMsgPackWriter writer) => throw new System.NotImplementedException();
24+
25+
public IndexPart Read(IMsgPackReader reader)
2126
{
22-
throw new System.NotImplementedException();
27+
var type = reader.ReadDataType();
28+
switch (type)
29+
{
30+
case DataTypes.Map16:
31+
return ReadFromMap(reader, ReadUInt16(reader));
32+
33+
case DataTypes.Map32:
34+
return ReadFromMap(reader, ReadUInt32(reader));
35+
36+
case DataTypes.Array16:
37+
return ReadFromArray(reader, ReadUInt16(reader));
38+
39+
case DataTypes.Array32:
40+
return ReadFromArray(reader, ReadUInt32(reader));
41+
}
42+
43+
var length = TryGetLengthFromFixMap(type);
44+
if (length.HasValue)
45+
{
46+
return ReadFromMap(reader, length.Value);
47+
}
48+
49+
length = TryGetLengthFromFixArray(type);
50+
if (length != null)
51+
{
52+
return ReadFromArray(reader, length.Value);
53+
}
54+
55+
throw ExceptionUtils.BadTypeException(type, DataTypes.Map16, DataTypes.Map32, DataTypes.FixMap, DataTypes.Array16, DataTypes.Array32, DataTypes.FixArray);
2356
}
2457

25-
public IndexPart Read(IMsgPackReader reader)
58+
private IndexPart ReadFromArray(IMsgPackReader reader, uint length)
2659
{
27-
var length = reader.ReadArrayLength();
2860
if (length != 2u)
2961
{
3062
throw ExceptionHelper.InvalidArrayLength(2u, length);
3163
}
3264

33-
3465
var fieldNo = _uintConverter.Read(reader);
3566
var indexPartType = _indexPartTypeConverter.Read(reader);
3667

3768
return new IndexPart(fieldNo, indexPartType);
3869
}
70+
71+
// throw new System.NotImplementedException();
72+
private IndexPart ReadFromMap(IMsgPackReader reader, uint length)
73+
{
74+
uint? fieldNo = null;
75+
IndexPartType? indexPartType = null;
76+
77+
for (var i = 0; i < length; i++)
78+
{
79+
switch (_stringConverter.Read(reader))
80+
{
81+
case "field":
82+
fieldNo = _uintConverter.Read(reader);
83+
break;
84+
case "type":
85+
indexPartType = _indexPartTypeConverter.Read(reader);
86+
break;
87+
default:
88+
reader.SkipToken();
89+
break;
90+
}
91+
}
92+
93+
if (fieldNo.HasValue && indexPartType.HasValue)
94+
{
95+
return new IndexPart(fieldNo.Value, indexPartType.Value);
96+
}
97+
98+
throw new SerializationException("Can't read fieldNo or indexPart from map of index metadata");
99+
}
100+
101+
private static uint? TryGetLengthFromFixArray(DataTypes type)
102+
{
103+
var length = type - DataTypes.FixArray;
104+
return type.GetHighBits(4) == DataTypes.FixArray.GetHighBits(4) ? length : (uint?)null;
105+
}
106+
107+
private static uint? TryGetLengthFromFixMap(DataTypes type)
108+
{
109+
var length = type - DataTypes.FixMap;
110+
return type.GetHighBits(4) == DataTypes.FixMap.GetHighBits(4) ? length : (uint?)null;
111+
}
112+
113+
internal static ushort ReadUInt16(IMsgPackReader reader)
114+
{
115+
return (ushort)((reader.ReadByte() << 8) + reader.ReadByte());
116+
}
117+
118+
internal static uint ReadUInt32(IMsgPackReader reader)
119+
{
120+
var temp = (uint)(reader.ReadByte() << 24);
121+
temp += (uint)reader.ReadByte() << 16;
122+
temp += (uint)reader.ReadByte() << 8;
123+
temp += reader.ReadByte();
124+
125+
return temp;
126+
}
39127
}
40128
}

src/progaudi.tarantool/Converters/SpaceConverter.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public Space Read(IMsgPackReader reader)
5252

5353
var fields = _fieldConverter.Read(reader);
5454

55-
return new Space(id, fieldCount, name, null, engine, fields.AsReadOnly());
55+
return new Space(id, fieldCount, name, engine, fields.AsReadOnly());
5656
}
5757
}
5858
}

src/progaudi.tarantool/IBox.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ public interface IBox : IDisposable
1111

1212
bool IsConnected { get; }
1313

14-
Model.Metrics Metrics { get; }
14+
Metrics Metrics { get; }
1515

16+
[Obsolete]
1617
ISchema GetSchema();
1718

19+
Task ReloadSchema();
20+
21+
ISchema Schema { get; }
22+
1823
Task Call_1_6(string functionName);
1924

2025
Task Call_1_6<TTuple>(string functionName, TTuple parameters);

src/progaudi.tarantool/IIndex.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ public interface IIndex
2828
Task<DataResponse<TTuple[]>> Select<TKey, TTuple>(TKey key, SelectOptions options = null);
2929

3030
///Note: there is no such method in specification http://tarantool.org/doc/book/box/box_index.html.
31-
///But common sense, and sources https://github.com/tarantool/tarantool/blob/1.7/src/box/lua/index.c says that that method sould be
31+
///But common sense, and sources https://github.com/tarantool/tarantool/blob/1.7/src/box/lua/index.c says that that method should be
3232
Task<DataResponse<TTuple[]>> Insert<TTuple>(TTuple tuple);
3333

3434
///Note: there is no such method in specification http://tarantool.org/doc/book/box/box_index.html.
35-
///But common sense, and sources https://github.com/tarantool/tarantool/blob/1.7/src/box/lua/index.c says that that method sould be
35+
///But common sense, and sources https://github.com/tarantool/tarantool/blob/1.7/src/box/lua/index.c says that that method should be
3636
Task<DataResponse<TTuple[]>> Replace<TTuple>(TTuple tuple);
3737

3838
Task<TTuple> Min<TTuple>();

src/progaudi.tarantool/ISchema.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
using System.Threading.Tasks;
2-
using ProGaudi.Tarantool.Client.Model;
1+
using System;
2+
using System.Threading.Tasks;
33

44
namespace ProGaudi.Tarantool.Client
55
{
66
public interface ISchema
77
{
8-
Task<ISpace> CreateSpaceAsync(string spaceName, SpaceCreationOptions options = null);
8+
[Obsolete("Use indexer")]
99
Task<ISpace> GetSpace(string name);
10+
[Obsolete("Use indexer")]
1011
Task<ISpace> GetSpace(uint id);
12+
13+
ISpace this[string name] { get; }
14+
ISpace this[uint id] { get; }
15+
16+
Task Reload();
1117
}
1218
}

src/progaudi.tarantool/ISpace.cs

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Threading.Tasks;
34
using ProGaudi.Tarantool.Client.Model;
45
using ProGaudi.Tarantool.Client.Model.Enums;
@@ -23,16 +24,16 @@ public interface ISpace
2324

2425
ILogicalConnection LogicalConnection { get; }
2526

26-
Task<IIndex> CreateIndex();
27-
28-
Task Drop();
29-
30-
Task Rename(string newName);
31-
27+
[Obsolete("Use indexer")]
3228
Task<IIndex> GetIndex(string indexName);
3329

30+
[Obsolete("Use indexer")]
3431
Task<IIndex> GetIndex(uint indexId);
3532

33+
IIndex this[string name] { get; }
34+
35+
IIndex this[uint id] { get; }
36+
3637
Task<DataResponse<TTuple[]>> Insert<TTuple>(TTuple tuple);
3738

3839
Task<DataResponse<TTuple[]>> Select<TKey, TTuple>(TKey selectKey);
@@ -56,9 +57,5 @@ public interface ISpace
5657
Task<DataResponse<TTuple[]>> Increment<TTuple, TKey>(TKey key);
5758

5859
Task<DataResponse<TTuple[]>> Decrement<TTuple, TKey>(TKey key);
59-
60-
TTuple AutoIncrement<TTuple, TRest>(TRest tupleRest);
61-
62-
Task<IEnumerable<KeyValuePair<TKey, TValue>>> Pairs<TKey, TValue>();
6360
}
6461
}

src/progaudi.tarantool/Schema.cs

+32-32
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
using System;
2-
using System.Linq;
2+
using System.Collections.Generic;
3+
using System.Threading;
34
using System.Threading.Tasks;
4-
5-
using ProGaudi.Tarantool.Client.Model;
65
using ProGaudi.Tarantool.Client.Model.Enums;
76
using ProGaudi.Tarantool.Client.Model.Requests;
87
using ProGaudi.Tarantool.Client.Utils;
@@ -13,54 +12,55 @@ public class Schema : ISchema
1312
{
1413
private const int VSpace = 0x119;
1514

16-
private const int SpaceById = 0;
15+
private const int VIndex = 0x121;
1716

18-
private const int SpaceByName = 2;
17+
internal const uint PrimaryIndexId = 0;
1918

2019
private readonly ILogicalConnection _logicalConnection;
2120

21+
private Dictionary<string, ISpace> _indexByName = new Dictionary<string, ISpace>();
22+
23+
private Dictionary<uint, ISpace> _indexById = new Dictionary<uint, ISpace>();
24+
2225
public Schema(ILogicalConnection logicalConnection)
2326
{
2427
_logicalConnection = logicalConnection;
2528
}
2629

27-
public Task<ISpace> CreateSpaceAsync(string spaceName, SpaceCreationOptions options = null)
28-
{
29-
throw new NotImplementedException();
30-
}
30+
public Task<ISpace> GetSpace(string name) => Task.FromResult(this[name]);
3131

32-
public async Task<ISpace> GetSpace(string name)
33-
{
34-
var selectIndexRequest = new SelectRequest<TarantoolTuple<string>>(VSpace, SpaceByName, uint.MaxValue, 0, Iterator.Eq, TarantoolTuple.Create(name));
32+
public Task<ISpace> GetSpace(uint id) => Task.FromResult(this[id]);
3533

36-
var response = await _logicalConnection.SendRequest<SelectRequest<TarantoolTuple<string>>, Space>(selectIndexRequest).ConfigureAwait(false);
34+
public ISpace this[string name] => _indexByName.TryGetValue(name, out var space) ? space : throw ExceptionHelper.InvalidSpaceName(name);
3735

38-
var result = response.Data.SingleOrDefault();
39-
if (result == null)
40-
{
41-
throw ExceptionHelper.InvalidSpaceName(name);
42-
}
36+
public ISpace this[uint id] => _indexById.TryGetValue(id, out var space) ? space : throw ExceptionHelper.InvalidSpaceId(id);
4337

44-
result.LogicalConnection = _logicalConnection;
45-
46-
return result;
47-
}
48-
49-
public async Task<ISpace> GetSpace(uint id)
38+
public async Task Reload()
5039
{
51-
var selectIndexRequest = new SelectRequest<TarantoolTuple<uint>>(VSpace, SpaceById, uint.MaxValue, 0, Iterator.Eq, TarantoolTuple.Create(id));
52-
53-
var response = await _logicalConnection.SendRequest<SelectRequest<TarantoolTuple<uint>>, Space>(selectIndexRequest).ConfigureAwait(false);
40+
var byName = new Dictionary<string, ISpace>();
41+
var byId = new Dictionary<uint, ISpace>();
5442

55-
var result = response.Data.SingleOrDefault();
56-
if (result == null)
43+
var spaces = await Select<Space>(VSpace).ConfigureAwait(false);
44+
foreach (var space in spaces)
5745
{
58-
throw ExceptionHelper.InvalidSpaceId(id);
46+
byName[space.Name] = space;
47+
byId[space.Id] = space;
48+
space.LogicalConnection = _logicalConnection;
49+
space.SetIndices(await Select<Index>(VIndex, Iterator.Eq, space.Id).ConfigureAwait(false));
5950
}
6051

61-
result.LogicalConnection = _logicalConnection;
52+
Interlocked.Exchange(ref _indexByName, byName);
53+
Interlocked.Exchange(ref _indexById, byId);
54+
}
55+
56+
private async Task<T[]> Select<T>(uint spaceId, Iterator iterator = Iterator.All, uint id = 0u)
57+
{
58+
var request = new SelectRequest<ValueTuple<uint>>(spaceId, PrimaryIndexId, uint.MaxValue, 0, iterator, ValueTuple.Create(id));
6259

63-
return result;
60+
var response = await _logicalConnection
61+
.SendRequest<SelectRequest<ValueTuple<uint>>, T>(request)
62+
.ConfigureAwait(false);
63+
return response.Data;
6464
}
6565
}
6666
}

0 commit comments

Comments
 (0)