/// <inheritdoc/> public void TruncateNamespace(string nsName) { using (var nsNameRx = nsName.GetHandle()) Assert.ThrowIfError(() => ReindexerBinding.reindexer_truncate_namespace(Rx, nsNameRx, _ctxInfo) ); }
/// <inheritdoc/> public void RenameNamespace(string oldName, string newName) { using (var oldNameRx = oldName.GetHandle()) using (var newNameRx = newName.GetHandle()) Assert.ThrowIfError(() => ReindexerBinding.reindexer_rename_namespace(Rx, oldNameRx, newNameRx, _ctxInfo)); }
/// <summary> /// Disables logger. /// </summary> public static void DisableLogger() { lock (_logWriterLocker) { ReindexerBinding.reindexer_disable_logger();//if we free previous delegate before disabling, gc may collect before enabling. _logWriter = null; } }
public void InitReindexer() { _rx = ReindexerBinding.init_reindexer(); Assert.AreNotEqual(UIntPtr.Zero, _rx); _logWriter = new LogWriterAction(Log); ReindexerBinding.reindexer_enable_logger(_logWriter); Connect(); }
private static LogWriterAction _logWriter; //we must pin the delegate before informing to reindexer, so we keep a reference to it, so gc won't collect it. /// <summary> /// Enables logger and send internal reindexer logs to <paramref name="logWriterAction"/>. /// </summary> /// <param name="logWriterAction">Action to send logs</param> public static void EnableLogger(LogWriterAction logWriterAction) { lock (_logWriterLocker) { ReindexerBinding.reindexer_disable_logger(); //if we free previous delegate before disabling, gc may collect before enabling. _logWriter = logWriterAction; ReindexerBinding.reindexer_enable_logger(_logWriter); } }
public void OpenNamespace() { AssertError(ReindexerBinding.reindexer_open_namespace(_rx, "OpenNamespaceTest".GetHandle(), new StorageOpts { options = StorageOpt.kStorageOptCreateIfMissing | StorageOpt.kStorageOptEnabled }, _ctxInfo)); AssertError(ReindexerBinding.reindexer_drop_namespace(_rx, "OpenNamespaceTest".GetHandle(), _ctxInfo)); }
public void EnableStorage() { var dbPath = Path.Combine(Path.GetTempPath(), "TestDbForEnableStorage"); if (Directory.Exists(dbPath)) { Directory.Delete(dbPath, true); } AssertError(ReindexerBinding.reindexer_enable_storage(ReindexerBinding.init_reindexer(), dbPath.GetHandle(), _ctxInfo)); }
/// <inheritdoc/> public void DropIndex(string nsName, params string[] indexName) { using (var nsNameRx = nsName.GetHandle()) foreach (var iname in indexName) { using (var inameRx = iname.GetHandle()) Assert.ThrowIfError(() => ReindexerBinding.reindexer_drop_index(Rx, nsNameRx, inameRx, _ctxInfo) ); } }
public void Connect() { AssertError( ReindexerBinding.reindexer_connect(_rx, $"builtin://{Path.Combine(Path.GetTempPath(), "ReindexerBindingTest")}".GetHandle(), new ConnectOpts { options = ConnectOpt.kConnectOptAllowNamespaceErrors, storage = StorageTypeOpt.kStorageTypeOptLevelDB, expectedClusterID = 0 }, ReindexerBinding.ReindexerVersion.GetHandle())); }
public void DropNamespace() { var error = ReindexerBinding.reindexer_drop_namespace(_rx, "DropNamespaceTest".GetHandle(), _ctxInfo); Assert.AreNotEqual(0, error.code); AssertError(ReindexerBinding.reindexer_open_namespace(_rx, "DropNamespaceTest".GetHandle(), new StorageOpts { options = StorageOpt.kStorageOptCreateIfMissing | StorageOpt.kStorageOptEnabled }, _ctxInfo)); AssertError(ReindexerBinding.reindexer_drop_namespace(_rx, "DropNamespaceTest".GetHandle(), _ctxInfo)); }
/// <inheritdoc/> public ReindexerTransaction StartTransaction(string nsName) { UIntPtr tr = UIntPtr.Zero; using (var nsNameRx = nsName.GetHandle()) Assert.ThrowIfError(() => { var rsp = ReindexerBinding.reindexer_start_transaction(Rx, nsNameRx); tr = rsp.tx_id; return(rsp.err); }); return(new ReindexerTransaction(new EmbeddedTransactionInvoker(Rx, tr, _ctxInfo))); }
/// <summary> /// Starts the server with server yaml and waits for ready for 5 seconds. Use <see cref="Connect(string, ConnectionOptions)"/> instead. /// </summary> /// <param name="serverConfigYaml">Reindexer server configuration yaml</param> /// <param name="dbName"></param> /// <param name="user"></param> /// <param name="pass"></param> /// <param name="waitTimeoutForReady">Wait timeout for the server is ready. Default is 60sec.</param> /// <exception cref="TimeoutException">Throws if the server doesn't start in timeout interval.</exception> public void Start(string serverConfigYaml, string dbName, string user = null, string pass = null, TimeSpan?waitTimeoutForReady = null) { lock (_serverStartupLocker) //for not spinning extra threads and double checking lock. { if (Interlocked.Read(ref _isServerThreadStarted) == 1) //Interlocked for not extra locking in future to check is startup { return; } _serverThread = new Thread(() => { Interlocked.Exchange(ref _isServerThreadStarted, 1); try { DebugHelper.Log("Starting reindexer server..."); using (var configYaml = serverConfigYaml.GetHandle()) ReindexerBinding.start_reindexer_server(_pServer, configYaml); } catch (Exception e) { DebugHelper.Log(e.Message); } finally { Interlocked.Exchange(ref _isServerThreadStarted, 0); } }) { IsBackground = false }; _serverThread.Start(); } var waitTimeout = waitTimeoutForReady ?? TimeSpan.FromSeconds(60); var startTime = DateTime.UtcNow; while (ReindexerBinding.check_server_ready(_pServer) == 0) { if (DateTime.UtcNow - startTime > waitTimeout) { throw new TimeoutException($"Reindexer Embedded Server couldn't be started in {waitTimeout.TotalSeconds} seconds. Check configs."); } Thread.Sleep(100); } DebugHelper.Log("Reindexer server is started."); using (var dbNameRx = dbName.GetHandle()) using (var userRx = user.GetHandle()) using (var passRx = pass.GetHandle()) Assert.ThrowIfError(() => ReindexerBinding.get_reindexer_instance(_pServer, dbNameRx, userRx, passRx, ref Rx)); }
/// <inheritdoc/> public virtual void Connect(string connectionString, ConnectionOptions options = null) { if (!Directory.Exists(connectionString)) { Directory.CreateDirectory(connectionString); //reindexer sometimes throws permission exception from c++ mkdir func. so we try to crate directory before. } using (var dsn = $"builtin://{connectionString}".GetHandle()) using (var version = ReindexerBinding.ReindexerVersion.GetHandle()) Assert.ThrowIfError(() => ReindexerBinding.reindexer_connect(Rx, dsn, options ?? new ConnectionOptions(), version) ); }
public int Commit() { var rsp = Assert.ThrowIfError(() => ReindexerBinding.reindexer_commit_transaction(_rx, _tr, _ctxInfo)); try { var reader = new CJsonReader(rsp.@out); var rawQueryParams = reader.ReadRawQueryParams(); return(rawQueryParams.count); } finally { [email protected](); } }
/// <inheritdoc/> public void OpenNamespace(string nsName, NamespaceOptions options = null) { using (var nsNameRx = nsName.GetHandle()) Assert.ThrowIfError(() => { reindexer_error rsp = default; for (int retry = 0; retry < 2; retry++) { rsp = ReindexerBinding.reindexer_open_namespace(Rx, nsNameRx, options ?? new NamespaceOptions(), _ctxInfo); if (rsp.code != 0) { ReindexerBinding.reindexer_close_namespace(Rx, nsNameRx, _ctxInfo); } } return(rsp); }); }
/// <inheritdoc/> public QueryItemsOf <T> ExecuteSql <T>(string sql, Func <byte[], T> deserializeItem) { var result = new QueryItemsOf <T> { Items = new List <T>() }; using (var sqlRx = sql.GetHandle()) { var rsp = Assert.ThrowIfError(() => ReindexerBinding.reindexer_select(Rx, sqlRx, 1, new int[0], 0, _ctxInfo)); try { var reader = new CJsonReader(rsp.@out); var rawQueryParams = reader.ReadRawQueryParams(); var explain = rawQueryParams.explainResults; result.QueryTotalItems = rawQueryParams.totalcount != 0 ? rawQueryParams.totalcount : rawQueryParams.count; if (explain.Length > 0) { result.Explain = JsonSerializer.Deserialize <ExplainDef>(explain.ToArray(), //todo: use span when utf8json supports it. StandardResolver.ExcludeNull); } for (var i = 0; i < rawQueryParams.count; i++) { var item = reader.ReadRawItemParams(); if (item.data.Length > 0) { result.Items.Add(deserializeItem(item.data.ToArray())); //todo: use span when utf8json supports it. } } if ((rawQueryParams.flags & CJsonReader.ResultsWithJoined) != 0 && reader.GetVarUInt() != 0) { throw new NotImplementedException("Sorry, not implemented: Can't return join query results as json"); } return(result); } finally { [email protected](); } } }
/// <inheritdoc/> public void AddIndex(string nsName, params Index[] indexDefinitions) { using (var nsNameRx = nsName.GetHandle()) foreach (var index in indexDefinitions) { if (index.JsonPaths == null || index.JsonPaths.Count == 0) { index.JsonPaths = new List <string> { index.Name } } ; using (var jsonRx = SerializeJson(index).GetStringHandle()) Assert.ThrowIfError(() => ReindexerBinding.reindexer_add_index(Rx, nsNameRx, jsonRx, _ctxInfo) ); } }
public void SelectSql() { ModifyItemPacked(); var rsp = ReindexerBinding.reindexer_select(_rx, $"SELECT * FROM {DataTestNamespace}".GetHandle(), 1, new int[0], 0, _ctxInfo); if (rsp.err_code != 0) { Assert.AreEqual(null, (string)rsp.@out); } Assert.AreNotEqual(UIntPtr.Zero, [email protected]_ptr); var(json, offsets, explain) = BindingHelpers.RawResultToJson(rsp.@out, "items", "total_count"); Assert.AreNotEqual(0, json.Length); Assert.AreNotEqual(0, offsets.Count); }
/// <summary> /// Stops the server. /// </summary> public void Stop() { DebugHelper.Log("Stopping reindexer server..."); try { foreach (var ns in ExecuteSql <Namespace>(GetNamespacesQuery).Items) { CloseNamespace(ns.Name); } } catch { //sometimes server had been stopped before this stop method because of ctrl+c on console or any sigterm signal. } Assert.ThrowIfError(() => ReindexerBinding.stop_reindexer_server(_pServer) ); var waitTimeout = TimeSpan.FromSeconds(10); var startTime = DateTime.UtcNow; while (IsStarted) { if (DateTime.UtcNow - startTime > waitTimeout) { DebugHelper.Log($"Reindexer Embedded Server couldn't be stopped in {waitTimeout.TotalSeconds} seconds."); break; } Thread.Sleep(100); } lock (_serverStartupLocker) { if (_serverThread.IsAlive) { _serverThread.Join(); } } Rx = default; DebugHelper.Log("Reindexer server is stopped."); }
/// <inheritdoc/> protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing && Rx != default) { foreach (var ns in ExecuteSql <Namespace>(GetNamespacesQuery).Items) { CloseNamespace(ns.Name); } if (Rx != default) { ReindexerBinding.destroy_reindexer(Rx); } } Rx = default; disposedValue = true; } }
/// <inheritdoc/> public int ModifyItem(string nsName, ItemModifyMode mode, byte[] itemJson, params string[] precepts) { var result = 0; using (var writer = new CJsonWriter()) { writer.PutVString(nsName); writer.PutVarCUInt((int)DataFormat.FormatJson); //format writer.PutVarCUInt((int)mode); //mode writer.PutVarCUInt(0); //stateToken writer.PutVarCUInt(precepts.Length); //len(precepts) foreach (var precept in precepts) { writer.PutVString(precept); } reindexer_buffer.PinBufferFor(writer.CurrentBuffer, args => { using (var data = reindexer_buffer.From(itemJson)) { var rsp = Assert.ThrowIfError(() => ReindexerBinding.reindexer_modify_item_packed(Rx, args, data, _ctxInfo)); try { var reader = new CJsonReader(rsp.@out); var rawQueryParams = reader.ReadRawQueryParams(); result = rawQueryParams.count; } finally { [email protected](); } } }); } return(result); }
public void DeleteSql() { AssertError(ReindexerBinding.reindexer_open_namespace(_rx, DataTestNamespace.GetHandle(), new StorageOpts { options = StorageOpt.kStorageOptCreateIfMissing | StorageOpt.kStorageOptEnabled }, _ctxInfo)); ModifyItemPacked($"{{\"Id\":2, \"Guid\":\"{Guid.NewGuid()}\"}}"); var delRsp = ReindexerBinding.reindexer_select(_rx, $"DELETE FROM {DataTestNamespace} WHERE Id=2".GetHandle(), 1, new int[0], 0, _ctxInfo); if (delRsp.err_code != 0) { Assert.AreEqual(null, (string)delRsp.@out); } Assert.AreNotEqual(UIntPtr.Zero, [email protected]_ptr); var(json, offsets, explain) = BindingHelpers.RawResultToJson(delRsp.@out, "items", "total_count"); Assert.AreNotEqual(0, json.Length); Assert.AreNotEqual(0, offsets.Count); var selRsp = ReindexerBinding.reindexer_select(_rx, $"SELECT * FROM {DataTestNamespace} WHERE Id=2".GetHandle(), 1, new int[] { 0 }, 1, _ctxInfo); if (selRsp.err_code != 0) { Assert.AreEqual(null, (string)selRsp.@out); } Assert.AreNotEqual(UIntPtr.Zero, [email protected]_ptr); (json, offsets, explain) = BindingHelpers.RawResultToJson(selRsp.@out, "items", "total_count"); Assert.AreNotEqual(0, json.Length); Assert.AreEqual(0, offsets.Count); }
public void ModifyItem(ItemModifyMode mode, byte[] itemJson, params string[] precepts) { using (var writer = new CJsonWriter()) { writer.PutVarCUInt((int)DataFormat.FormatJson); // format writer.PutVarCUInt((int)mode); // mode writer.PutVarCUInt(0); // stateToken writer.PutVarCUInt(precepts.Length); // len(precepts) foreach (var precept in precepts) { writer.PutVString(precept); } reindexer_buffer.PinBufferFor(writer.CurrentBuffer, args => { using (var data = itemJson.GetHandle()) { Assert.ThrowIfError(() => ReindexerBinding.reindexer_modify_item_packed_tx(_rx, _tr, args, data.Buffer)); } }); } }
public void Rollback() { Assert.ThrowIfError(() => ReindexerBinding.reindexer_rollback_transaction(_rx, _tr)); }
public void ParallelModifyItemPacked() { var nsName = "ParallelTestNs"; AssertError(ReindexerBinding.reindexer_open_namespace(_rx, nsName.GetHandle(), new StorageOpts { options = StorageOpt.kStorageOptCreateIfMissing | StorageOpt.kStorageOptEnabled }, _ctxInfo)); var indexDefJson = JsonSerializer.ToJsonString( new Index { Name = "Id", IsPk = true, FieldType = FieldType.Int64, IndexType = IndexType.Hash, JsonPaths = new List <string> { "Id" } }, Utf8Json.Resolvers.StandardResolver.ExcludeNull); AssertError(ReindexerBinding.reindexer_add_index(_rx, nsName.GetHandle(), indexDefJson.GetHandle(), _ctxInfo)); using (var ser1 = new CJsonWriter()) { ser1.PutVString(nsName); ser1.PutVarCUInt((int)DataFormat.FormatJson); ser1.PutVarCUInt((int)ItemModifyMode.Upsert); ser1.PutVarCUInt(0); ser1.PutVarCUInt(0); reindexer_buffer.PinBufferFor(ser1.CurrentBuffer, args => { Parallel.For(0, 30000, i => { var dataHandle = reindexer_buffer.From(Encoding.UTF8.GetBytes($"{{\"Id\":{i}, \"Guid\":\"{Guid.NewGuid()}\"}}")); var rsp = ReindexerBinding.reindexer_modify_item_packed(_rx, args, dataHandle.Buffer, _ctxInfo); try { if (rsp.err_code != 0) { Assert.AreEqual(null, (string)rsp.@out); } Assert.AreNotEqual(UIntPtr.Zero, [email protected]_ptr); var reader = new CJsonReader(rsp.@out); var rawQueryParams = reader.ReadRawQueryParams(); Assert.AreEqual(1, rawQueryParams.count); reader.ReadRawItemParams(); } finally { dataHandle.Dispose(); [email protected](); } }); }); } Thread.Sleep(6000); #pragma warning disable S1215 // "GC.Collect" should not be called GC.Collect(); GC.WaitForPendingFinalizers(); #pragma warning restore S1215 // "GC.Collect" should not be called AssertError(ReindexerBinding.reindexer_truncate_namespace(_rx, nsName.GetHandle(), _ctxInfo)); }
public void DestroyReindexer() { ReindexerBinding.destroy_reindexer(_rx); }
public void Ping() { AssertError(ReindexerBinding.reindexer_ping(_rx)); }
public void InitSystemNamespaces() { AssertError(ReindexerBinding.reindexer_init_system_namespaces(_rx)); }
}; //TODO: Implement async/await logic. /// <summary> /// Creates a new embedded Reindexer database. /// </summary> public ReindexerEmbedded() { Rx = ReindexerBinding.init_reindexer(); }
/// <inheritdoc/> public void Ping() { Assert.ThrowIfError(() => ReindexerBinding.reindexer_ping(Rx)); }