DocumentBenchmark.vala 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /**
  2. * DocumentBenchmark - Benchmarks for Document entity operations
  3. *
  4. * Measures performance of document creation, reading, and updating
  5. * with various property sizes.
  6. *
  7. * @version 0.2
  8. * @since 0.1
  9. */
  10. namespace Implexus.Tools.Perf {
  11. /**
  12. * Benchmark for Document entity operations.
  13. *
  14. * Tests:
  15. * - create_document_small: Creating documents with few properties
  16. * - create_document_large: Creating documents with many properties
  17. * - get_document: Reading document properties
  18. * - update_document: Modifying document properties
  19. * - get_property: Getting a single property
  20. * - delete_document: Deleting documents (tracked for deferred cleanup)
  21. */
  22. public class DocumentBenchmark : Benchmark {
  23. /**
  24. * {@inheritDoc}
  25. */
  26. public override string name { get { return "Document"; } }
  27. /**
  28. * Creates a new DocumentBenchmark.
  29. *
  30. * @param engine The engine to benchmark
  31. * @param config The benchmark configuration
  32. */
  33. public DocumentBenchmark(Core.Engine engine, BenchmarkConfig config) {
  34. base(engine, config);
  35. }
  36. /**
  37. * {@inheritDoc}
  38. */
  39. public override async void run_async(Results results) throws Error {
  40. // Create parent container first
  41. var parent_path = new Core.EntityPath("/perf-test/documents");
  42. yield ensure_container_async(new Core.EntityPath("/perf-test"), "perf-test");
  43. _cleanup_tracker.add_container(new Core.EntityPath("/perf-test").to_string());
  44. yield cleanup_path_async(parent_path);
  45. var root = yield _engine.get_root_async();
  46. var perf_test = yield root.get_child_async("perf-test");
  47. var parent_container = yield perf_test.create_container_async("documents");
  48. _cleanup_tracker.add_container(parent_path.to_string());
  49. int iterations = _config.iterations;
  50. int heavy_iterations = _config.heavy_iterations;
  51. // Test 1: Create documents with small properties (2 properties)
  52. print(" Testing create_document_small (%d iterations)...\n", iterations);
  53. var create_small_op = new CreateSmallDocOp(this, parent_container, parent_path);
  54. var create_small = yield measure_async("create_document_small", iterations, create_small_op);
  55. results.add(name, create_small);
  56. // Test 2: Create documents with large properties (50 properties)
  57. print(" Testing create_document_large (%d iterations)...\n", heavy_iterations);
  58. var create_large_op = new CreateLargeDocOp(this, parent_container, parent_path);
  59. var create_large = yield measure_async("create_document_large", heavy_iterations, create_large_op);
  60. results.add(name, create_large);
  61. // Test 3: Read documents (small)
  62. print(" Testing get_document (%d iterations)...\n", iterations);
  63. var read_op = new GetDocumentOp(_engine, parent_path, iterations);
  64. var read_result = yield measure_async("get_document", iterations, read_op);
  65. results.add(name, read_result);
  66. // Test 4: Update documents
  67. print(" Testing update_document (%d iterations)...\n", iterations);
  68. var update_op = new UpdateDocumentOp(_engine, parent_path, iterations);
  69. var update_result = yield measure_async("update_document", iterations, update_op);
  70. results.add(name, update_result);
  71. // Test 5: Get property by name
  72. print(" Testing get_property (%d iterations)...\n", iterations);
  73. var get_prop_op = new GetPropertyOp(_engine, parent_path, iterations);
  74. var get_prop_result = yield measure_async("get_property", iterations, get_prop_op);
  75. results.add(name, get_prop_result);
  76. // Test 6: Delete documents (still measured, but tracked for cleanup)
  77. print(" Testing delete_document (%d iterations)...\n", iterations);
  78. var delete_op = new DeleteDocumentOp(_engine, parent_path);
  79. var delete_result = yield measure_async("delete_document", iterations, delete_op);
  80. results.add(name, delete_result);
  81. }
  82. }
  83. // Operation classes for DocumentBenchmark
  84. private class CreateSmallDocOp : AsyncOperation {
  85. private DocumentBenchmark _benchmark;
  86. private Core.Entity _parent_container;
  87. private Core.EntityPath _parent_path;
  88. public CreateSmallDocOp(DocumentBenchmark benchmark, Core.Entity parent_container, Core.EntityPath parent_path) {
  89. _benchmark = benchmark;
  90. _parent_container = parent_container;
  91. _parent_path = parent_path;
  92. }
  93. public override async void execute_async() throws Error {
  94. var doc_name = "doc-%d".printf(iteration);
  95. var doc_path = _parent_path.append_child(doc_name);
  96. yield _benchmark.cleanup_path_async(doc_path);
  97. var doc = yield _parent_container.create_document_async(doc_name, "User");
  98. yield doc.set_entity_property_async("name", new Invercargill.NativeElement<string>("user-%d".printf(iteration)));
  99. yield doc.set_entity_property_async("age", new Invercargill.NativeElement<int>(iteration));
  100. // Track for deferred cleanup
  101. _benchmark._cleanup_tracker.add_document(doc_path.to_string());
  102. }
  103. }
  104. private class CreateLargeDocOp : AsyncOperation {
  105. private DocumentBenchmark _benchmark;
  106. private Core.Entity _parent_container;
  107. private Core.EntityPath _parent_path;
  108. public CreateLargeDocOp(DocumentBenchmark benchmark, Core.Entity parent_container, Core.EntityPath parent_path) {
  109. _benchmark = benchmark;
  110. _parent_container = parent_container;
  111. _parent_path = parent_path;
  112. }
  113. public override async void execute_async() throws Error {
  114. var doc_name = "large-doc-%d".printf(iteration);
  115. var doc_path = _parent_path.append_child(doc_name);
  116. yield _benchmark.cleanup_path_async(doc_path);
  117. var doc = yield _parent_container.create_document_async(doc_name, "LargeDocument");
  118. // Add 50 properties
  119. for (int j = 0; j < 50; j++) {
  120. yield doc.set_entity_property_async(
  121. "field_%d".printf(j),
  122. new Invercargill.NativeElement<string>("value-%d-%d".printf(iteration, j))
  123. );
  124. }
  125. // Track for deferred cleanup
  126. _benchmark._cleanup_tracker.add_document(doc_path.to_string());
  127. }
  128. }
  129. private class GetDocumentOp : AsyncOperation {
  130. private Core.Engine _engine;
  131. private Core.EntityPath _parent_path;
  132. private int _iterations;
  133. public GetDocumentOp(Core.Engine engine, Core.EntityPath parent_path, int iterations) {
  134. _engine = engine;
  135. _parent_path = parent_path;
  136. _iterations = iterations;
  137. }
  138. public override async void execute_async() throws Error {
  139. var doc_name = "doc-%d".printf(iteration % _iterations);
  140. var path = _parent_path.append_child(doc_name);
  141. var entity = yield _engine.get_entity_or_null_async(path);
  142. if (entity != null) {
  143. // Access properties to force load
  144. var props = yield ((!) entity).get_properties_async();
  145. var name_prop = props.get("name");
  146. }
  147. }
  148. }
  149. private class UpdateDocumentOp : AsyncOperation {
  150. private Core.Engine _engine;
  151. private Core.EntityPath _parent_path;
  152. private int _iterations;
  153. public UpdateDocumentOp(Core.Engine engine, Core.EntityPath parent_path, int iterations) {
  154. _engine = engine;
  155. _parent_path = parent_path;
  156. _iterations = iterations;
  157. }
  158. public override async void execute_async() throws Error {
  159. var doc_name = "doc-%d".printf(iteration % _iterations);
  160. var path = _parent_path.append_child(doc_name);
  161. var entity = yield _engine.get_entity_or_null_async(path);
  162. if (entity != null) {
  163. yield ((!) entity).set_entity_property_async(
  164. "updated",
  165. new Invercargill.NativeElement<bool?>(true)
  166. );
  167. }
  168. }
  169. }
  170. private class GetPropertyOp : AsyncOperation {
  171. private Core.Engine _engine;
  172. private Core.EntityPath _parent_path;
  173. private int _iterations;
  174. public GetPropertyOp(Core.Engine engine, Core.EntityPath parent_path, int iterations) {
  175. _engine = engine;
  176. _parent_path = parent_path;
  177. _iterations = iterations;
  178. }
  179. public override async void execute_async() throws Error {
  180. var doc_name = "doc-%d".printf(iteration % _iterations);
  181. var path = _parent_path.append_child(doc_name);
  182. var entity = yield _engine.get_entity_or_null_async(path);
  183. if (entity != null) {
  184. var prop = yield ((!) entity).get_entity_property_async("name");
  185. }
  186. }
  187. }
  188. private class DeleteDocumentOp : AsyncOperation {
  189. private Core.Engine _engine;
  190. private Core.EntityPath _parent_path;
  191. public DeleteDocumentOp(Core.Engine engine, Core.EntityPath parent_path) {
  192. _engine = engine;
  193. _parent_path = parent_path;
  194. }
  195. public override async void execute_async() throws Error {
  196. var doc_name = "doc-%d".printf(iteration);
  197. var path = _parent_path.append_child(doc_name);
  198. var entity = yield _engine.get_entity_or_null_async(path);
  199. if (entity != null) {
  200. yield ((!) entity).delete_async();
  201. }
  202. }
  203. }
  204. }