public async Task Put() { using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { var input = await context.ReadForMemoryAsync(RequestBodyStream(), "Sorters"); if (input.TryGet("Sorters", out BlittableJsonReaderArray analyzers) == false) { ThrowRequiredPropertyNameInRequest("Sorters"); } var commands = new List <PutServerWideSorterCommand>(); foreach (var sorterToAdd in analyzers) { var sorterDefinition = JsonDeserializationServer.SorterDefinition((BlittableJsonReaderObject)sorterToAdd); sorterDefinition.Name = sorterDefinition.Name?.Trim(); if (LoggingSource.AuditLog.IsInfoEnabled) { var clientCert = GetCurrentCertificate(); var auditLog = LoggingSource.AuditLog.GetLogger("Server", "Audit"); auditLog.Info($"Sorter {sorterDefinition.Name} PUT by {clientCert?.Subject} {clientCert?.Thumbprint} with definition: {sorterToAdd}"); } sorterDefinition.Validate(); // check if sorter is compilable SorterCompiler.Compile(sorterDefinition.Name, sorterDefinition.Code); var command = new PutServerWideSorterCommand(sorterDefinition, GetRaftRequestIdFromQuery()); commands.Add(command); } var index = 0L; foreach (var command in commands) { index = (await ServerStore.SendToLeaderAsync(command)).Index; } await ServerStore.WaitForCommitIndexChange(RachisConsensus.CommitIndexModification.GreaterOrEqual, index); NoContentStatus(HttpStatusCode.Created); } }
public async Task Get() { using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) using (context.OpenReadTransaction()) { var sorters = new Dictionary <string, SorterDefinition>(); foreach (var item in ServerStore.Cluster.ItemsStartingWith(context, PutServerWideSorterCommand.Prefix, 0, long.MaxValue)) { var sorterDefinition = JsonDeserializationServer.SorterDefinition(item.Value); sorters.Add(PutServerWideSorterCommand.ExtractName(item.ItemName), sorterDefinition); } await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) { writer.WriteStartObject(); writer.WriteArray(context, "Sorters", sorters.Values, (w, c, analyzer) => { w.WriteStartObject(); w.WritePropertyName(nameof(SorterDefinition.Name)); w.WriteString(analyzer.Name); w.WriteComma(); w.WritePropertyName(nameof(SorterDefinition.Code)); w.WriteString(analyzer.Code); w.WriteEndObject(); }); writer.WriteEndObject(); } } }
public void CanUseCustomSorter_Restart_Faulty() { var serverPath = NewDataPath(); var databasePath = NewDataPath(); IOExtensions.DeleteDirectory(serverPath); IOExtensions.DeleteDirectory(databasePath); var sorterName = GetDatabaseName(); using (var server = GetNewServer(new ServerCreationOptions { DataDirectory = serverPath, RunInMemory = false })) using (var store = GetDocumentStore(new Options { ModifyDatabaseName = _ => sorterName, Path = databasePath, RunInMemory = false, Server = server, DeleteDatabaseOnDispose = false })) { using (var session = store.OpenSession()) { session.Store(new Company { Name = "C1" }); session.Store(new Company { Name = "C2" }); session.SaveChanges(); } CanUseSorterInternal <SorterDoesNotExistException>(store, $"There is no sorter with '{sorterName}' name", $"There is no sorter with '{sorterName}' name", sorterName); var sorterCode = GetSorter("RavenDB_8355.MySorter.cs", "MySorter", sorterName); store.Maintenance.Server.Send(new PutServerWideSortersOperation(new SorterDefinition { Name = sorterName, Code = sorterCode })); CanUseSorterInternal <RavenException>(store, "Catch me: Name:2:0:False", "Catch me: Name:2:0:True", sorterName); server.ServerStore.DatabasesLandlord.UnloadDirectly(store.Database); // skipping compilation on purpose using (server.ServerStore.Engine.ContextPool.AllocateOperationContext(out ClusterOperationContext context)) using (var tx = context.OpenWriteTransaction()) { var command = new PutServerWideSorterCommand( new SorterDefinition { Name = sorterName, Code = sorterCode.Replace(sorterCode, "MySorter") }, RaftIdGenerator.NewId()); using (var json = context.ReadObject(command.ValueToJson(), command.Name)) { ClusterStateMachine.PutValueDirectly(context, command.Name, json, 1); } tx.Commit(); } } SorterCompilationCache.Instance.RemoveServerWideItem(sorterName); using (var server = GetNewServer(new ServerCreationOptions { DataDirectory = serverPath, RunInMemory = false, DeletePrevious = false })) using (var store = GetDocumentStore(new Options { ModifyDatabaseName = _ => sorterName, Path = databasePath, RunInMemory = false, Server = server, CreateDatabase = false })) { CanUseSorterInternal <RavenException>(store, "is an implementation of a faulty sorter", "is an implementation of a faulty sorter", sorterName); // can override with database sorter store.Maintenance.Send(new PutSortersOperation(new SorterDefinition { Name = sorterName, Code = GetSorter("RavenDB_8355.MySorter.cs", "MySorter", sorterName) })); CanUseSorterInternal <RavenException>(store, "Catch me: Name:2:0:False", "Catch me: Name:2:0:True", sorterName); // can go back to server analyzer store.Maintenance.Send(new DeleteSorterOperation(sorterName)); CanUseSorterInternal <RavenException>(store, "is an implementation of a faulty sorter", "is an implementation of a faulty sorter", sorterName); // can fix server sorter store.Maintenance.Server.Send(new PutServerWideSortersOperation(new SorterDefinition { Name = sorterName, Code = GetSorter("RavenDB_8355.MySorter.cs", "MySorter", sorterName) })); CanUseSorterInternal <RavenException>(store, "Catch me: Name:2:0:False", "Catch me: Name:2:0:True", sorterName); } }