/** * CatalogueBenchmark - Benchmarks for Catalogue entity operations * * Measures performance of catalogue creation, key enumeration, * and group retrieval operations. * * @version 0.1 * @since 0.1 */ namespace Implexus.Tools.Perf { /** * Benchmark for Catalogue entity operations. * * Tests: * - create_catalogue: Creating catalogues with key expressions * - get_keys: Enumerating catalogue keys * - get_group: Retrieving documents in a specific group * - get_group_documents: Full enumeration of group members * - create_catalogue_numeric: Creating catalogues with numeric keys * - get_all_groups: Getting all groups from a catalogue * - create_catalogue_multifield: Creating catalogues with different fields */ public class CatalogueBenchmark : Benchmark { /** * {@inheritDoc} */ public override string name { get { return "Catalogue"; } } /** * Creates a new CatalogueBenchmark. * * @param engine The engine to benchmark * @param config The benchmark configuration */ public CatalogueBenchmark(Core.Engine engine, BenchmarkConfig config) { base(engine, config); } /** * {@inheritDoc} */ public override async void run_async(Results results) throws Error { // Setup: Create test documents with varying key values var parent_path = new Core.EntityPath("/perf-test/catalogues"); yield ensure_container_async(new Core.EntityPath("/perf-test"), "perf-test"); _cleanup_tracker.add_container(new Core.EntityPath("/perf-test").to_string()); yield cleanup_path_async(parent_path); var root = yield _engine.get_root_async(); var perf_test = yield root.get_child_async("perf-test"); var parent_container = yield perf_test.create_container_async("catalogues"); _cleanup_tracker.add_container(parent_path.to_string()); int test_doc_count = _config.test_doc_count; int quick_iterations = _config.quick_iterations; int iterations = _config.iterations; // Create test documents with status property print(" Setting up test documents (%d documents)...\n", test_doc_count); string[] statuses = { "active", "inactive", "pending", "archived" }; for (int i = 0; i < test_doc_count; i++) { var doc_name = "item-%d".printf(i); var doc_path = parent_path.append_child(doc_name); yield cleanup_path_async(doc_path); var doc = yield parent_container.create_document_async(doc_name, "StatusItem"); yield doc.set_entity_property_async( "status", new Invercargill.NativeElement(statuses[i % statuses.length]) ); yield doc.set_entity_property_async( "priority", new Invercargill.NativeElement(i % 5) ); yield doc.set_entity_property_async( "department", new Invercargill.NativeElement("dept-%d".printf(i % 3)) ); // Track for deferred cleanup _cleanup_tracker.add_document(doc_path.to_string()); } // Test 1: Create catalogue with status key var catalogue_path = parent_path.append_child("by-status"); print(" Testing create_catalogue (%d iterations)...\n", quick_iterations); var create_op = new CreateCatalogueOp(this, parent_container, catalogue_path, "by-status", "StatusItem", "status"); var create_result = yield measure_async("create_catalogue", quick_iterations, create_op); results.add(name, create_result); // Test 2: Get catalogue keys print(" Testing get_keys (%d iterations)...\n", iterations); Core.Entity? cat_entity = yield _engine.get_entity_or_null_async(catalogue_path); var catalogue_entity = cat_entity as Entities.Catalogue; var keys_op = new GetKeysOp(catalogue_entity); var keys_result = yield measure_async("get_keys", iterations, keys_op); results.add(name, keys_result); // Test 3: Get group by key print(" Testing get_group (%d iterations)...\n", iterations); var group_op = new GetGroupOp(catalogue_entity, "active"); var group_result = yield measure_async("get_group", iterations, group_op); results.add(name, group_result); // Test 4: Get group documents print(" Testing get_group_documents (%d iterations)...\n", iterations); var group_docs_op = new GetGroupDocumentsOp(catalogue_entity, "active"); var group_docs_result = yield measure_async("get_group_documents", iterations, group_docs_op); results.add(name, group_docs_result); // Test 5: Create catalogue with numeric key var priority_catalogue_path = parent_path.append_child("by-priority"); print(" Testing create_catalogue_numeric (%d iterations)...\n", quick_iterations); var priority_create_op = new CreateCatalogueOp(this, parent_container, priority_catalogue_path, "by-priority", "StatusItem", "priority"); var priority_create_result = yield measure_async("create_catalogue_numeric", quick_iterations, priority_create_op); results.add(name, priority_create_result); // Test 6: Get all groups from numeric catalogue print(" Testing get_all_groups (%d iterations)...\n", quick_iterations); Core.Entity? prio_cat_entity = yield _engine.get_entity_or_null_async(priority_catalogue_path); var priority_catalogue = prio_cat_entity as Entities.Catalogue; var all_groups_op = new GetAllGroupsOp(priority_catalogue); var all_groups_result = yield measure_async("get_all_groups", quick_iterations, all_groups_op); results.add(name, all_groups_result); // Test 7: Create multi-field catalogue var dept_catalogue_path = parent_path.append_child("by-department"); print(" Testing create_catalogue_multifield (%d iterations)...\n", quick_iterations); var dept_create_op = new CreateCatalogueOp(this, parent_container, dept_catalogue_path, "by-department", "StatusItem", "department"); var dept_create_result = yield measure_async("create_catalogue_multifield", quick_iterations, dept_create_op); results.add(name, dept_create_result); } } // Operation classes for CatalogueBenchmark private class CreateCatalogueOp : AsyncOperation { private CatalogueBenchmark _benchmark; private Core.Entity _parent_container; private Core.EntityPath _catalogue_path; private string _name; private string _entity_type; private string _key_expression; public CreateCatalogueOp(CatalogueBenchmark benchmark, Core.Entity parent_container, Core.EntityPath catalogue_path, string name, string entity_type, string key_expression) { _benchmark = benchmark; _parent_container = parent_container; _catalogue_path = catalogue_path; _name = name; _entity_type = entity_type; _key_expression = key_expression; } public override async void execute_async() throws Error { yield _benchmark.cleanup_path_async(_catalogue_path); yield _parent_container.create_catalogue_async(_name, _entity_type, _key_expression); // Track for deferred cleanup _benchmark._cleanup_tracker.add_catalogue(_catalogue_path.to_string()); } } private class GetKeysOp : AsyncOperation { private Entities.Catalogue? _catalogue_entity; public GetKeysOp(Entities.Catalogue? catalogue_entity) { _catalogue_entity = catalogue_entity; } public override async void execute_async() throws Error { if (_catalogue_entity != null) { // get_group_keys is synchronous (runs in DBM thread context) var keys = ((!) _catalogue_entity).get_group_keys(); // Force enumeration int count = 0; foreach (var key in keys) { count++; } } } } private class GetGroupOp : AsyncOperation { private Entities.Catalogue? _catalogue_entity; private string _group_name; public GetGroupOp(Entities.Catalogue? catalogue_entity, string group_name) { _catalogue_entity = catalogue_entity; _group_name = group_name; } public override async void execute_async() throws Error { if (_catalogue_entity != null) { var group = yield ((!) _catalogue_entity).get_child_async(_group_name); } } } private class GetGroupDocumentsOp : AsyncOperation { private Entities.Catalogue? _catalogue_entity; private string _group_name; public GetGroupDocumentsOp(Entities.Catalogue? catalogue_entity, string group_name) { _catalogue_entity = catalogue_entity; _group_name = group_name; } public override async void execute_async() throws Error { if (_catalogue_entity != null) { var docs = yield ((!) _catalogue_entity).get_group_documents_async(_group_name); // Force enumeration int count = 0; foreach (var doc in docs) { count++; } } } } private class GetAllGroupsOp : AsyncOperation { private Entities.Catalogue? _catalogue; public GetAllGroupsOp(Entities.Catalogue? catalogue) { _catalogue = catalogue; } public override async void execute_async() throws Error { if (_catalogue != null) { var children = yield ((!) _catalogue).get_children_async(); // Force enumeration of all groups int total_count = 0; foreach (var group in children) { var group_children = yield group.get_children_async(); foreach (var doc in group_children) { total_count++; } } } } } }