@joystick.js/db-canary 0.0.0-canary.2209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.build/getFilesToBuild.js +26 -0
- package/.build/getPlatformSafeFilePath.js +6 -0
- package/.build/getPlatformSafePath.js +6 -0
- package/.build/index.js +88 -0
- package/.build/isWindows.js +3 -0
- package/API_KEY +1 -0
- package/README.md +1821 -0
- package/data/data.mdb +0 -0
- package/data/lock.mdb +0 -0
- package/dist/client/database.js +1 -0
- package/dist/client/index.js +1 -0
- package/dist/server/cluster/index.js +1 -0
- package/dist/server/cluster/master.js +20 -0
- package/dist/server/cluster/worker.js +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/lib/api_key_manager.js +9 -0
- package/dist/server/lib/auth_manager.js +1 -0
- package/dist/server/lib/auto_index_manager.js +1 -0
- package/dist/server/lib/backup_manager.js +1 -0
- package/dist/server/lib/connection_manager.js +1 -0
- package/dist/server/lib/disk_utils.js +2 -0
- package/dist/server/lib/http_server.js +405 -0
- package/dist/server/lib/index_manager.js +1 -0
- package/dist/server/lib/load_settings.js +1 -0
- package/dist/server/lib/logger.js +1 -0
- package/dist/server/lib/op_types.js +1 -0
- package/dist/server/lib/operation_dispatcher.js +1 -0
- package/dist/server/lib/operations/admin.js +1 -0
- package/dist/server/lib/operations/bulk_write.js +1 -0
- package/dist/server/lib/operations/create_index.js +1 -0
- package/dist/server/lib/operations/delete_one.js +1 -0
- package/dist/server/lib/operations/drop_index.js +1 -0
- package/dist/server/lib/operations/find.js +1 -0
- package/dist/server/lib/operations/find_one.js +1 -0
- package/dist/server/lib/operations/get_indexes.js +1 -0
- package/dist/server/lib/operations/insert_one.js +1 -0
- package/dist/server/lib/operations/update_one.js +1 -0
- package/dist/server/lib/performance_monitor.js +1 -0
- package/dist/server/lib/query_engine.js +1 -0
- package/dist/server/lib/recovery_manager.js +1 -0
- package/dist/server/lib/replication_manager.js +1 -0
- package/dist/server/lib/safe_json_parse.js +1 -0
- package/dist/server/lib/send_response.js +1 -0
- package/dist/server/lib/tcp_protocol.js +1 -0
- package/dist/server/lib/write_forwarder.js +1 -0
- package/dist/server/lib/write_queue.js +1 -0
- package/increment_version.js +3 -0
- package/logs/.013e15b54597d05db4b4b53ecc37b10c92a72927-audit.json +20 -0
- package/logs/.02de550a67ea0f5961faa2dfd458a4d06f59ebd1-audit.json +20 -0
- package/logs/.03494ba24eb3c72214b4068a77d54b8993bee651-audit.json +20 -0
- package/logs/.06309ec60b339be1259a7993dd09c732f8907fbc-audit.json +20 -0
- package/logs/.0663a04dcfa17285661e5e1b8cfa51f41523b210-audit.json +20 -0
- package/logs/.0f06e6c4c9b824622729e13927587479e5060391-audit.json +20 -0
- package/logs/.16ccf58682ecb22b3e3ec63f0da1b7fe9be56528-audit.json +20 -0
- package/logs/.1fa1a5d02f496474b1ab473524c65c984146a9ad-audit.json +20 -0
- package/logs/.2223c0ae3bea6f0d62c62b1d319cc8634856abb7-audit.json +20 -0
- package/logs/.23dc79ffda3e083665e6f5993f59397adcbf4a46-audit.json +20 -0
- package/logs/.28104f49b03906b189eefd1cd462cb46c3c0af22-audit.json +20 -0
- package/logs/.29cdbf13808abe6a0ce70ee2f2efdd680ce3fd8e-audit.json +20 -0
- package/logs/.2a9889afd071f77f41f5170d08703a0afca866b7-audit.json +20 -0
- package/logs/.2acec3d1940a2bbed487528b703ee5948959a599-audit.json +20 -0
- package/logs/.2fb60ff326338c02bfedbcd0e936444e4a216750-audit.json +20 -0
- package/logs/.318fc7a19530d76a345f030f7cad00dda15300e7-audit.json +20 -0
- package/logs/.3cf27043e19085f908cedc7701e6d013463208ee-audit.json +25 -0
- package/logs/.3d90d785415817fc443402843b7c95f8371adc9b-audit.json +20 -0
- package/logs/.4074bca620375f72966fc52dfd439577727671e5-audit.json +20 -0
- package/logs/.40eecf018417ea80a70ea8ec7a3cc9406bc6334b-audit.json +20 -0
- package/logs/.50e974f1ef7c365fca6a1251b2e2c2252914cb5e-audit.json +20 -0
- package/logs/.52cb7d9e4223cf26ba36006ac26b949a97c7923c-audit.json +20 -0
- package/logs/.54befcdb84c15aad980705a31bcc9f555c3577ab-audit.json +20 -0
- package/logs/.57dfb70e22eddb84db2e3c0ceeefac5c0b9baffa-audit.json +20 -0
- package/logs/.5f0b24705a1eaad4eca4968f2d86f91b3f9be683-audit.json +20 -0
- package/logs/.61ba98fdda7db58576b382fee07904e5db1169d6-audit.json +20 -0
- package/logs/.6235017727ef6b199d569a99d6aa8c8e80a1b475-audit.json +20 -0
- package/logs/.63db16193699219489d218a1ddea5dde3750cae4-audit.json +20 -0
- package/logs/.64fb67dfe14149c9eef728d79bf30a54da809c60-audit.json +20 -0
- package/logs/.669137453368987c1f311b5345342527afb54e50-audit.json +20 -0
- package/logs/.7a71f8c89ea28ae266d356aeff6306e876a30fbb-audit.json +20 -0
- package/logs/.7afbaa90fe9dc3a7d682676f9bb79f9a1b1fd9a6-audit.json +20 -0
- package/logs/.7ca29e322cd05327035de850099e7610864f2347-audit.json +20 -0
- package/logs/.83335ab3347e449dae03455a110aaf7f120d4802-audit.json +20 -0
- package/logs/.8c2487b5fd445d2c8e5c483c80b9fa99bbf1ca58-audit.json +20 -0
- package/logs/.8c8b9dc386922c9f3b4c13251af7052aac1d24c0-audit.json +20 -0
- package/logs/.8d6155d94640c4863301ae0fee5e4e7372a21446-audit.json +20 -0
- package/logs/.944a3119a243deea7c8270d5d9e582bb1d0eaa10-audit.json +20 -0
- package/logs/.9816a845c30fb2909f3b26a23eeb3538ebcad5db-audit.json +20 -0
- package/logs/.9dc08784e38b865488177c26d4af5934555e0323-audit.json +20 -0
- package/logs/.9dd27d2e0e454ac0a37600206d1cac5493b0d7ee-audit.json +20 -0
- package/logs/.a3d486feeac7654c59b547de96600e8849a06d4f-audit.json +20 -0
- package/logs/.a5b811f4def22250f86cc18870d7c4573625df22-audit.json +20 -0
- package/logs/.a61648eb5f830e0b6f508ac35e4f8f629d2ad4c7-audit.json +20 -0
- package/logs/.a89016d507045771b4b5a65656944a9c0f1e528b-audit.json +20 -0
- package/logs/.a99bee160a1c590be959af46bacc02724803f691-audit.json +20 -0
- package/logs/.ada7906d6243fd7da802f03d86c4ae5dd9df6236-audit.json +20 -0
- package/logs/.b518339ee942143b6af983af167f5bbb6983b4de-audit.json +20 -0
- package/logs/.b51b124b166d53c9519017856ea610d61d65fabe-audit.json +20 -0
- package/logs/.b7a6aee19f58e55633d5e4a3709041c47dfff975-audit.json +20 -0
- package/logs/.bd7a8a6ba9c55d557a4867ab53f02e3ec2e1553d-audit.json +20 -0
- package/logs/.c1435dafe453b169d6392b25065f3cf4ab6fbb21-audit.json +20 -0
- package/logs/.c17e1ce043109f77dc2f0e2aa290a9d1ed842c03-audit.json +20 -0
- package/logs/.ca62637ce9540e5a38a2fbedb2115febb6ad308a-audit.json +15 -0
- package/logs/.ccee67b9c176967f8977071409a41f5cb5cd6ad4-audit.json +20 -0
- package/logs/.db24043417ea79a6f14cd947476399e53930b48d-audit.json +20 -0
- package/logs/.e0f12acccb57829f5f33712bb2e2607ecd808147-audit.json +20 -0
- package/logs/.e9b6cc33d0bbd2e644c4e2bf44d177f850016557-audit.json +20 -0
- package/logs/.f15291d434808e3bdca7963ccd2e73893be027e6-audit.json +20 -0
- package/logs/.f4bdf9e21ef84f8a3fae3ffb32bbc39275991351-audit.json +15 -0
- package/logs/.fbac3aefac1e81b4230df5aa50667cb90d51024f-audit.json +20 -0
- package/logs/.fcfd495c0a9169db243f4a4f21878ee02b76413c-audit.json +20 -0
- package/logs/admin-2025-09-12.log +580 -0
- package/logs/admin-2025-09-15.log +283 -0
- package/logs/admin-error-2025-09-12.log +22 -0
- package/logs/admin-error-2025-09-15.log +10 -0
- package/logs/api_key_manager-2025-09-12.log +658 -0
- package/logs/api_key_manager-2025-09-15.log +295 -0
- package/logs/api_key_manager-error-2025-09-12.log +0 -0
- package/logs/api_key_manager-error-2025-09-15.log +0 -0
- package/logs/auth_manager-2025-09-12.log +4432 -0
- package/logs/auth_manager-2025-09-15.log +2000 -0
- package/logs/auth_manager-error-2025-09-12.log +11 -0
- package/logs/auth_manager-error-2025-09-15.log +5 -0
- package/logs/auto_index_manager-2025-09-12.log +84 -0
- package/logs/auto_index_manager-2025-09-15.log +45 -0
- package/logs/auto_index_manager-error-2025-09-12.log +6 -0
- package/logs/auto_index_manager-error-2025-09-15.log +0 -0
- package/logs/backup_manager-2025-09-12.log +198 -0
- package/logs/backup_manager-2025-09-15.log +90 -0
- package/logs/backup_manager-error-2025-09-12.log +198 -0
- package/logs/backup_manager-error-2025-09-15.log +90 -0
- package/logs/bulk_write-2025-09-12.log +66 -0
- package/logs/bulk_write-2025-09-15.log +38 -0
- package/logs/bulk_write-error-2025-09-12.log +0 -0
- package/logs/bulk_write-error-2025-09-15.log +0 -0
- package/logs/connection_manager-2025-09-12.log +2412 -0
- package/logs/connection_manager-2025-09-15.log +1132 -0
- package/logs/connection_manager-error-2025-09-12.log +0 -0
- package/logs/connection_manager-error-2025-09-15.log +0 -0
- package/logs/create_index-2025-09-12.log +302 -0
- package/logs/create_index-2025-09-15.log +158 -0
- package/logs/create_index-error-2025-09-12.log +30 -0
- package/logs/create_index-error-2025-09-15.log +13 -0
- package/logs/delete_one-2025-09-12.log +73 -0
- package/logs/delete_one-2025-09-15.log +43 -0
- package/logs/delete_one-error-2025-09-12.log +0 -0
- package/logs/delete_one-error-2025-09-15.log +0 -0
- package/logs/disk_utils-2025-09-12.log +4954 -0
- package/logs/disk_utils-2025-09-15.log +2446 -0
- package/logs/disk_utils-error-2025-09-12.log +0 -0
- package/logs/disk_utils-error-2025-09-15.log +0 -0
- package/logs/drop_index-2025-09-12.log +41 -0
- package/logs/drop_index-2025-09-15.log +23 -0
- package/logs/drop_index-error-2025-09-12.log +11 -0
- package/logs/drop_index-error-2025-09-15.log +5 -0
- package/logs/find-2025-09-12.log +1050 -0
- package/logs/find-2025-09-15.log +592 -0
- package/logs/find-error-2025-09-12.log +1 -0
- package/logs/find-error-2025-09-15.log +0 -0
- package/logs/find_one-2025-09-12.log +425 -0
- package/logs/find_one-2025-09-15.log +264 -0
- package/logs/find_one-error-2025-09-12.log +5 -0
- package/logs/find_one-error-2025-09-15.log +0 -0
- package/logs/get_indexes-2025-09-12.log +84 -0
- package/logs/get_indexes-2025-09-15.log +56 -0
- package/logs/get_indexes-error-2025-09-12.log +6 -0
- package/logs/get_indexes-error-2025-09-15.log +0 -0
- package/logs/http_server-2025-09-12.log +2772 -0
- package/logs/http_server-2025-09-15.log +1276 -0
- package/logs/http_server-error-2025-09-12.log +212 -0
- package/logs/http_server-error-2025-09-15.log +44 -0
- package/logs/index_manager-2025-09-12.log +5031 -0
- package/logs/index_manager-2025-09-15.log +2909 -0
- package/logs/index_manager-error-2025-09-12.log +80 -0
- package/logs/index_manager-error-2025-09-15.log +38 -0
- package/logs/insert_one-2025-09-12.log +2181 -0
- package/logs/insert_one-2025-09-15.log +1293 -0
- package/logs/insert_one-error-2025-09-12.log +0 -0
- package/logs/insert_one-error-2025-09-15.log +0 -0
- package/logs/master-2025-09-12.log +1882 -0
- package/logs/master-2025-09-15.log +910 -0
- package/logs/master-error-2025-09-12.log +80 -0
- package/logs/master-error-2025-09-15.log +0 -0
- package/logs/operation_dispatcher-2025-09-12.log +751 -0
- package/logs/operation_dispatcher-2025-09-15.log +359 -0
- package/logs/operation_dispatcher-error-2025-09-12.log +33 -0
- package/logs/operation_dispatcher-error-2025-09-15.log +11 -0
- package/logs/performance_monitor-2025-09-12.log +14889 -0
- package/logs/performance_monitor-2025-09-15.log +6803 -0
- package/logs/performance_monitor-error-2025-09-12.log +0 -0
- package/logs/performance_monitor-error-2025-09-15.log +0 -0
- package/logs/query_engine-2025-09-12.log +5310 -0
- package/logs/query_engine-2025-09-15.log +2639 -0
- package/logs/query_engine-error-2025-09-12.log +0 -0
- package/logs/query_engine-error-2025-09-15.log +0 -0
- package/logs/recovery_manager-2025-09-12.log +462 -0
- package/logs/recovery_manager-2025-09-15.log +210 -0
- package/logs/recovery_manager-error-2025-09-12.log +22 -0
- package/logs/recovery_manager-error-2025-09-15.log +10 -0
- package/logs/replication-2025-09-12.log +1923 -0
- package/logs/replication-2025-09-15.log +917 -0
- package/logs/replication-error-2025-09-12.log +33 -0
- package/logs/replication-error-2025-09-15.log +15 -0
- package/logs/server-2025-09-12.log +2601 -0
- package/logs/server-2025-09-15.log +1191 -0
- package/logs/server-error-2025-09-12.log +0 -0
- package/logs/server-error-2025-09-15.log +0 -0
- package/logs/tcp_protocol-2025-09-12.log +22 -0
- package/logs/tcp_protocol-2025-09-15.log +10 -0
- package/logs/tcp_protocol-error-2025-09-12.log +22 -0
- package/logs/tcp_protocol-error-2025-09-15.log +10 -0
- package/logs/test-2025-09-12.log +0 -0
- package/logs/test-2025-09-15.log +0 -0
- package/logs/test-error-2025-09-12.log +0 -0
- package/logs/test-error-2025-09-15.log +0 -0
- package/logs/update_one-2025-09-12.log +173 -0
- package/logs/update_one-2025-09-15.log +118 -0
- package/logs/update_one-error-2025-09-12.log +0 -0
- package/logs/update_one-error-2025-09-15.log +0 -0
- package/logs/worker-2025-09-12.log +1457 -0
- package/logs/worker-2025-09-15.log +695 -0
- package/logs/worker-error-2025-09-12.log +0 -0
- package/logs/worker-error-2025-09-15.log +0 -0
- package/logs/write_forwarder-2025-09-12.log +1956 -0
- package/logs/write_forwarder-2025-09-15.log +932 -0
- package/logs/write_forwarder-error-2025-09-12.log +66 -0
- package/logs/write_forwarder-error-2025-09-15.log +30 -0
- package/logs/write_queue-2025-09-12.log +612 -0
- package/logs/write_queue-2025-09-15.log +301 -0
- package/logs/write_queue-error-2025-09-12.log +184 -0
- package/logs/write_queue-error-2025-09-15.log +83 -0
- package/package.json +48 -0
- package/prompts/01-core-infrastructure.md +56 -0
- package/prompts/02-secondary-indexing.md +65 -0
- package/prompts/03-write-serialization.md +63 -0
- package/prompts/04-enhanced-authentication.md +75 -0
- package/prompts/05-comprehensive-admin-operations.md +75 -0
- package/prompts/06-backup-and-restore-system.md +106 -0
- package/prompts/07-production-safety-features.md +107 -0
- package/prompts/08-tcp-client-library.md +121 -0
- package/prompts/09-api-method-chaining.md +134 -0
- package/prompts/10-automatic-index-creation.md +223 -0
- package/prompts/11-operation-naming-consistency.md +268 -0
- package/prompts/12-tcp-replication-system.md +333 -0
- package/prompts/13-master-read-write-operations.md +57 -0
- package/prompts/14-index-upsert-operations.md +68 -0
- package/prompts/15-client-api-return-types.md +81 -0
- package/prompts/16-server-setup-ui.md +97 -0
- package/prompts/17-emergency-password-change.md +108 -0
- package/prompts/18-joystick-framework-integration.md +116 -0
- package/prompts/19-api-key-authentication-system.md +137 -0
- package/prompts/20-configurable-server-port.md +105 -0
- package/prompts/21-multi-database-support.md +161 -0
- package/prompts/FULL_TEXT_SEARCH.md +293 -0
- package/prompts/PROMPTS.md +158 -0
- package/prompts/README.md +221 -0
- package/prompts/TYPESCRIPT_GENERATION.md +179 -0
- package/src/client/database.js +166 -0
- package/src/client/index.js +752 -0
- package/src/server/cluster/index.js +53 -0
- package/src/server/cluster/master.js +774 -0
- package/src/server/cluster/worker.js +537 -0
- package/src/server/index.js +540 -0
- package/src/server/lib/api_key_manager.js +473 -0
- package/src/server/lib/auth_manager.js +375 -0
- package/src/server/lib/auto_index_manager.js +681 -0
- package/src/server/lib/backup_manager.js +650 -0
- package/src/server/lib/connection_manager.js +218 -0
- package/src/server/lib/disk_utils.js +118 -0
- package/src/server/lib/http_server.js +1165 -0
- package/src/server/lib/index_manager.js +756 -0
- package/src/server/lib/load_settings.js +143 -0
- package/src/server/lib/logger.js +135 -0
- package/src/server/lib/op_types.js +29 -0
- package/src/server/lib/operation_dispatcher.js +268 -0
- package/src/server/lib/operations/admin.js +808 -0
- package/src/server/lib/operations/bulk_write.js +367 -0
- package/src/server/lib/operations/create_index.js +68 -0
- package/src/server/lib/operations/delete_one.js +114 -0
- package/src/server/lib/operations/drop_index.js +58 -0
- package/src/server/lib/operations/find.js +340 -0
- package/src/server/lib/operations/find_one.js +319 -0
- package/src/server/lib/operations/get_indexes.js +52 -0
- package/src/server/lib/operations/insert_one.js +113 -0
- package/src/server/lib/operations/update_one.js +225 -0
- package/src/server/lib/performance_monitor.js +313 -0
- package/src/server/lib/query_engine.js +243 -0
- package/src/server/lib/recovery_manager.js +388 -0
- package/src/server/lib/replication_manager.js +727 -0
- package/src/server/lib/safe_json_parse.js +21 -0
- package/src/server/lib/send_response.js +47 -0
- package/src/server/lib/tcp_protocol.js +130 -0
- package/src/server/lib/write_forwarder.js +636 -0
- package/src/server/lib/write_queue.js +335 -0
- package/test_data/data.mdb +0 -0
- package/test_data/lock.mdb +0 -0
- package/tests/client/index.test.js +1232 -0
- package/tests/server/cluster/cluster.test.js +248 -0
- package/tests/server/cluster/master_read_write_operations.test.js +577 -0
- package/tests/server/index.test.js +651 -0
- package/tests/server/integration/authentication_integration.test.js +294 -0
- package/tests/server/integration/auto_indexing_integration.test.js +268 -0
- package/tests/server/integration/backup_integration.test.js +513 -0
- package/tests/server/integration/indexing_integration.test.js +126 -0
- package/tests/server/integration/production_safety_integration.test.js +358 -0
- package/tests/server/integration/replication_integration.test.js +227 -0
- package/tests/server/integration/write_serialization_integration.test.js +246 -0
- package/tests/server/lib/api_key_manager.test.js +516 -0
- package/tests/server/lib/auth_manager.test.js +317 -0
- package/tests/server/lib/auto_index_manager.test.js +275 -0
- package/tests/server/lib/backup_manager.test.js +238 -0
- package/tests/server/lib/connection_manager.test.js +221 -0
- package/tests/server/lib/disk_utils.test.js +63 -0
- package/tests/server/lib/http_server.test.js +389 -0
- package/tests/server/lib/index_manager.test.js +301 -0
- package/tests/server/lib/load_settings.test.js +107 -0
- package/tests/server/lib/load_settings_port_config.test.js +243 -0
- package/tests/server/lib/logger.test.js +282 -0
- package/tests/server/lib/operations/admin.test.js +638 -0
- package/tests/server/lib/operations/bulk_write.test.js +128 -0
- package/tests/server/lib/operations/create_index.test.js +138 -0
- package/tests/server/lib/operations/delete_one.test.js +52 -0
- package/tests/server/lib/operations/drop_index.test.js +72 -0
- package/tests/server/lib/operations/find.test.js +93 -0
- package/tests/server/lib/operations/find_one.test.js +91 -0
- package/tests/server/lib/operations/get_indexes.test.js +87 -0
- package/tests/server/lib/operations/insert_one.test.js +42 -0
- package/tests/server/lib/operations/update_one.test.js +89 -0
- package/tests/server/lib/performance_monitor.test.js +185 -0
- package/tests/server/lib/query_engine.test.js +46 -0
- package/tests/server/lib/recovery_manager.test.js +414 -0
- package/tests/server/lib/replication_manager.test.js +202 -0
- package/tests/server/lib/safe_json_parse.test.js +45 -0
- package/tests/server/lib/send_response.test.js +155 -0
- package/tests/server/lib/tcp_protocol.test.js +169 -0
- package/tests/server/lib/write_forwarder.test.js +258 -0
- package/tests/server/lib/write_queue.test.js +255 -0
- package/tsconfig.json +30 -0
- package/types/client/index.d.ts +447 -0
- package/types/server/cluster/index.d.ts +28 -0
- package/types/server/cluster/master.d.ts +115 -0
- package/types/server/cluster/worker.d.ts +1 -0
- package/types/server/lib/auth_manager.d.ts +13 -0
- package/types/server/lib/backup_manager.d.ts +43 -0
- package/types/server/lib/connection_manager.d.ts +15 -0
- package/types/server/lib/disk_utils.d.ts +3 -0
- package/types/server/lib/index_manager.d.ts +24 -0
- package/types/server/lib/load_settings.d.ts +4 -0
- package/types/server/lib/logger.d.ts +44 -0
- package/types/server/lib/op_types.d.ts +6 -0
- package/types/server/lib/performance_monitor.d.ts +68 -0
- package/types/server/lib/query_engine.d.ts +10 -0
- package/types/server/lib/safe_json_parse.d.ts +7 -0
- package/types/server/lib/send_response.d.ts +3 -0
- package/types/server/lib/tcp_protocol.d.ts +12 -0
- package/types/server/lib/write_queue.d.ts +2 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Insert operation for adding single documents to collections with indexing and write queue support.
|
|
3
|
+
*
|
|
4
|
+
* Provides document insertion with automatic ID generation, timestamp management,
|
|
5
|
+
* duplicate prevention, index updates, and write queue serialization for consistency.
|
|
6
|
+
* Handles both internal and external insert operations with comprehensive error handling.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { get_database, generate_document_id, build_collection_key } from '../query_engine.js';
|
|
10
|
+
import { update_indexes_on_insert } from '../index_manager.js';
|
|
11
|
+
import { get_write_queue } from '../write_queue.js';
|
|
12
|
+
import create_logger from '../logger.js';
|
|
13
|
+
|
|
14
|
+
const { create_context_logger } = create_logger('insert_one');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Internal implementation of insert_one operation without write queue serialization.
|
|
18
|
+
* @param {string} database_name - Name of the database
|
|
19
|
+
* @param {string} collection_name - Name of the collection
|
|
20
|
+
* @param {Object} document - Document to insert
|
|
21
|
+
* @param {Object} [options={}] - Insert options
|
|
22
|
+
* @returns {Promise<Object>} Insert result with acknowledged and inserted_id
|
|
23
|
+
* @throws {Error} When database/collection name is missing, document is invalid, or document already exists
|
|
24
|
+
*/
|
|
25
|
+
const insert_one_internal = async (database_name, collection_name, document, options = {}) => {
|
|
26
|
+
const log = create_context_logger();
|
|
27
|
+
|
|
28
|
+
if (!database_name) {
|
|
29
|
+
throw new Error('Database name is required');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!collection_name) {
|
|
33
|
+
throw new Error('Collection name is required');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!document || typeof document !== 'object') {
|
|
37
|
+
throw new Error('Document must be a valid object');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const db = get_database();
|
|
41
|
+
const document_id = document._id || generate_document_id();
|
|
42
|
+
const collection_key = build_collection_key(database_name, collection_name, document_id);
|
|
43
|
+
|
|
44
|
+
const document_to_insert = {
|
|
45
|
+
...document,
|
|
46
|
+
_id: document_id,
|
|
47
|
+
_created_at: new Date().toISOString(),
|
|
48
|
+
_updated_at: new Date().toISOString()
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
let inserted_document = null;
|
|
52
|
+
|
|
53
|
+
await db.transaction(() => {
|
|
54
|
+
const existing_document = db.get(collection_key);
|
|
55
|
+
|
|
56
|
+
if (existing_document) {
|
|
57
|
+
throw new Error(`Document with _id ${document_id} already exists`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
db.put(collection_key, JSON.stringify(document_to_insert));
|
|
61
|
+
inserted_document = document_to_insert;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await update_indexes_on_insert(database_name, collection_name, inserted_document);
|
|
65
|
+
|
|
66
|
+
log.info('Document inserted successfully', {
|
|
67
|
+
database: database_name,
|
|
68
|
+
collection: collection_name,
|
|
69
|
+
document_id: document_id
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
acknowledged: true,
|
|
74
|
+
inserted_id: document_id
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Inserts a single document into a collection with write queue serialization.
|
|
80
|
+
* @param {string} database_name - Name of the database
|
|
81
|
+
* @param {string} collection_name - Name of the collection
|
|
82
|
+
* @param {Object} document - Document to insert
|
|
83
|
+
* @param {Object} [options={}] - Insert options
|
|
84
|
+
* @returns {Promise<Object>} Insert result with acknowledged and inserted_id
|
|
85
|
+
* @throws {Error} When database/collection name is missing or document is invalid
|
|
86
|
+
*/
|
|
87
|
+
const insert_one = async (database_name, collection_name, document, options = {}) => {
|
|
88
|
+
if (!database_name) {
|
|
89
|
+
throw new Error('Database name is required');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!collection_name) {
|
|
93
|
+
throw new Error('Collection name is required');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!document || typeof document !== 'object') {
|
|
97
|
+
throw new Error('Document must be a valid object');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const write_queue = get_write_queue();
|
|
101
|
+
|
|
102
|
+
return await write_queue.enqueue_write_operation(
|
|
103
|
+
() => insert_one_internal(database_name, collection_name, document, options),
|
|
104
|
+
{
|
|
105
|
+
operation: 'insert_one',
|
|
106
|
+
database: database_name,
|
|
107
|
+
collection: collection_name,
|
|
108
|
+
document_id: document._id || 'auto-generated'
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export default insert_one;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { get_database, build_collection_key, generate_document_id } from '../query_engine.js';
|
|
2
|
+
import { update_indexes_on_update, update_indexes_on_insert } from '../index_manager.js';
|
|
3
|
+
import { get_write_queue } from '../write_queue.js';
|
|
4
|
+
import create_logger from '../logger.js';
|
|
5
|
+
|
|
6
|
+
const { create_context_logger } = create_logger('update_one');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Applies MongoDB-style update operators to a document.
|
|
10
|
+
* @param {Object} document - Original document
|
|
11
|
+
* @param {Object} update_operations - Update operations ($set, $unset, $inc, $push, $pull)
|
|
12
|
+
* @returns {Object} Updated document
|
|
13
|
+
* @throws {Error} When unsupported update operator is used
|
|
14
|
+
*/
|
|
15
|
+
const apply_update_operators = (document, update_operations) => {
|
|
16
|
+
const updated_document = { ...document };
|
|
17
|
+
|
|
18
|
+
for (const [operator, operations] of Object.entries(update_operations)) {
|
|
19
|
+
switch (operator) {
|
|
20
|
+
case '$set':
|
|
21
|
+
Object.assign(updated_document, operations);
|
|
22
|
+
break;
|
|
23
|
+
|
|
24
|
+
case '$unset':
|
|
25
|
+
for (const field of Object.keys(operations)) {
|
|
26
|
+
delete updated_document[field];
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
|
|
30
|
+
case '$inc':
|
|
31
|
+
for (const [field, value] of Object.entries(operations)) {
|
|
32
|
+
updated_document[field] = (updated_document[field] || 0) + value;
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
|
|
36
|
+
case '$push':
|
|
37
|
+
for (const [field, value] of Object.entries(operations)) {
|
|
38
|
+
if (!Array.isArray(updated_document[field])) {
|
|
39
|
+
updated_document[field] = [];
|
|
40
|
+
}
|
|
41
|
+
updated_document[field].push(value);
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
|
|
45
|
+
case '$pull':
|
|
46
|
+
for (const [field, value] of Object.entries(operations)) {
|
|
47
|
+
if (Array.isArray(updated_document[field])) {
|
|
48
|
+
updated_document[field] = updated_document[field].filter(item => item !== value);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
|
|
53
|
+
default:
|
|
54
|
+
throw new Error(`Unsupported update operator: ${operator}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return updated_document;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Checks if a document matches the given filter criteria (simple equality check).
|
|
63
|
+
* @param {Object} document - Document to test
|
|
64
|
+
* @param {Object} filter - Filter criteria
|
|
65
|
+
* @returns {boolean} True if document matches filter
|
|
66
|
+
*/
|
|
67
|
+
const matches_filter = (document, filter) => {
|
|
68
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const [field, value] of Object.entries(filter)) {
|
|
73
|
+
if (document[field] !== value) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return true;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Internal implementation of update_one operation without write queue serialization.
|
|
83
|
+
* @param {string} database_name - Name of the database
|
|
84
|
+
* @param {string} collection_name - Name of the collection
|
|
85
|
+
* @param {Object} filter - Filter criteria to match document
|
|
86
|
+
* @param {Object} update - Update operations to apply
|
|
87
|
+
* @param {Object} [options={}] - Update options
|
|
88
|
+
* @param {boolean} [options.upsert] - Create document if not found
|
|
89
|
+
* @returns {Promise<Object>} Update result with acknowledged, matched_count, modified_count, and optional upserted_id
|
|
90
|
+
* @throws {Error} When database name, collection name, filter, or update is invalid
|
|
91
|
+
*/
|
|
92
|
+
const update_one_internal = async (database_name, collection_name, filter, update, options = {}) => {
|
|
93
|
+
const log = create_context_logger();
|
|
94
|
+
|
|
95
|
+
if (!database_name) {
|
|
96
|
+
throw new Error('Database name is required');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!collection_name) {
|
|
100
|
+
throw new Error('Collection name is required');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!filter || typeof filter !== 'object') {
|
|
104
|
+
throw new Error('Filter must be a valid object');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!update || typeof update !== 'object') {
|
|
108
|
+
throw new Error('Update must be a valid object');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const db = get_database();
|
|
112
|
+
let matched_count = 0;
|
|
113
|
+
let modified_count = 0;
|
|
114
|
+
let upserted_id = null;
|
|
115
|
+
|
|
116
|
+
let old_document = null;
|
|
117
|
+
let new_document = null;
|
|
118
|
+
let upserted_document = null;
|
|
119
|
+
|
|
120
|
+
await db.transaction(() => {
|
|
121
|
+
const collection_prefix = `${database_name}:${collection_name}:`;
|
|
122
|
+
let document_found = false;
|
|
123
|
+
|
|
124
|
+
const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
|
|
125
|
+
for (const { key, value } of range) {
|
|
126
|
+
let document;
|
|
127
|
+
try {
|
|
128
|
+
document = JSON.parse(value);
|
|
129
|
+
} catch (parse_error) {
|
|
130
|
+
// Skip documents that can't be parsed
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (matches_filter(document, filter)) {
|
|
135
|
+
document_found = true;
|
|
136
|
+
matched_count = 1;
|
|
137
|
+
|
|
138
|
+
const updated_document = apply_update_operators(document, update);
|
|
139
|
+
updated_document._updated_at = new Date().toISOString();
|
|
140
|
+
|
|
141
|
+
if (JSON.stringify(document) !== JSON.stringify(updated_document)) {
|
|
142
|
+
db.put(key, JSON.stringify(updated_document));
|
|
143
|
+
old_document = document;
|
|
144
|
+
new_document = updated_document;
|
|
145
|
+
modified_count = 1;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!document_found && options.upsert) {
|
|
153
|
+
const document_id = generate_document_id();
|
|
154
|
+
const collection_key = build_collection_key(database_name, collection_name, document_id);
|
|
155
|
+
|
|
156
|
+
const new_doc = {
|
|
157
|
+
...filter,
|
|
158
|
+
_id: document_id,
|
|
159
|
+
_created_at: new Date().toISOString(),
|
|
160
|
+
_updated_at: new Date().toISOString()
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
upserted_document = apply_update_operators(new_doc, update);
|
|
164
|
+
db.put(collection_key, JSON.stringify(upserted_document));
|
|
165
|
+
|
|
166
|
+
upserted_id = document_id;
|
|
167
|
+
matched_count = 0;
|
|
168
|
+
modified_count = 0;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (old_document && new_document) {
|
|
173
|
+
await update_indexes_on_update(database_name, collection_name, old_document, new_document);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (upserted_document) {
|
|
177
|
+
await update_indexes_on_insert(database_name, collection_name, upserted_document);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
log.info('Update operation completed', {
|
|
181
|
+
database: database_name,
|
|
182
|
+
collection: collection_name,
|
|
183
|
+
matched_count,
|
|
184
|
+
modified_count,
|
|
185
|
+
upserted_id
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const result = {
|
|
189
|
+
acknowledged: true,
|
|
190
|
+
matched_count,
|
|
191
|
+
modified_count
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (upserted_id) {
|
|
195
|
+
result.upserted_id = upserted_id;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return result;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Updates a single document in a collection with write queue serialization.
|
|
203
|
+
* @param {string} database_name - Name of the database
|
|
204
|
+
* @param {string} collection_name - Name of the collection
|
|
205
|
+
* @param {Object} filter - Filter criteria to match document
|
|
206
|
+
* @param {Object} update - Update operations to apply
|
|
207
|
+
* @param {Object} [options={}] - Update options
|
|
208
|
+
* @param {boolean} [options.upsert] - Create document if not found
|
|
209
|
+
* @returns {Promise<Object>} Update result with acknowledged, matched_count, modified_count, and optional upserted_id
|
|
210
|
+
*/
|
|
211
|
+
const update_one = async (database_name, collection_name, filter, update, options = {}) => {
|
|
212
|
+
const write_queue = get_write_queue();
|
|
213
|
+
|
|
214
|
+
return await write_queue.enqueue_write_operation(
|
|
215
|
+
() => update_one_internal(database_name, collection_name, filter, update, options),
|
|
216
|
+
{
|
|
217
|
+
operation: 'update_one',
|
|
218
|
+
database: database_name,
|
|
219
|
+
collection: collection_name,
|
|
220
|
+
filter_keys: Object.keys(filter || {})
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export default update_one;
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Performance monitoring system for JoystickDB server operations.
|
|
3
|
+
* Tracks operation metrics, response times, error rates, memory usage, database statistics,
|
|
4
|
+
* and system performance. Provides comprehensive monitoring and logging capabilities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import create_logger from './logger.js';
|
|
8
|
+
import { get_database } from './query_engine.js';
|
|
9
|
+
|
|
10
|
+
const { create_context_logger } = create_logger('performance_monitor');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Performance monitoring class that tracks server operations and system metrics.
|
|
14
|
+
* Provides detailed statistics on operations, errors, response times, and resource usage.
|
|
15
|
+
*/
|
|
16
|
+
class PerformanceMonitor {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new PerformanceMonitor instance.
|
|
19
|
+
* Initializes metrics tracking and logging capabilities.
|
|
20
|
+
*/
|
|
21
|
+
constructor() {
|
|
22
|
+
this.log = create_context_logger();
|
|
23
|
+
|
|
24
|
+
/** @type {Object} Performance metrics storage */
|
|
25
|
+
this.metrics = {
|
|
26
|
+
operations: new Map(),
|
|
27
|
+
errors: new Map(),
|
|
28
|
+
response_times: [],
|
|
29
|
+
start_time: Date.now(),
|
|
30
|
+
total_requests: 0,
|
|
31
|
+
total_errors: 0
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** @type {number} Maximum number of response times to keep in memory */
|
|
35
|
+
this.max_response_times = 1000;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Tracks a database operation with timing and error information.
|
|
40
|
+
* @param {string} op_type - Type of operation (e.g., 'find', 'insert', 'update')
|
|
41
|
+
* @param {number} duration_ms - Operation duration in milliseconds
|
|
42
|
+
* @param {string} status - Operation status ('success' or 'error')
|
|
43
|
+
* @param {string|null} [error=null] - Error message if operation failed
|
|
44
|
+
* @param {Object} [metadata={}] - Additional metadata for logging
|
|
45
|
+
*/
|
|
46
|
+
track_operation(op_type, duration_ms, status, error = null, metadata = {}) {
|
|
47
|
+
this.metrics.total_requests++;
|
|
48
|
+
|
|
49
|
+
// Track operation counts
|
|
50
|
+
if (!this.metrics.operations.has(op_type)) {
|
|
51
|
+
this.metrics.operations.set(op_type, { count: 0, total_time: 0, errors: 0 });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const op_stats = this.metrics.operations.get(op_type);
|
|
55
|
+
op_stats.count++;
|
|
56
|
+
op_stats.total_time += duration_ms;
|
|
57
|
+
|
|
58
|
+
if (status === 'error') {
|
|
59
|
+
this.metrics.total_errors++;
|
|
60
|
+
op_stats.errors++;
|
|
61
|
+
|
|
62
|
+
// Track error types
|
|
63
|
+
const error_key = error || 'unknown_error';
|
|
64
|
+
if (!this.metrics.errors.has(error_key)) {
|
|
65
|
+
this.metrics.errors.set(error_key, 0);
|
|
66
|
+
}
|
|
67
|
+
this.metrics.errors.set(error_key, this.metrics.errors.get(error_key) + 1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Track response times (keep only recent ones)
|
|
71
|
+
this.metrics.response_times.push({
|
|
72
|
+
timestamp: Date.now(),
|
|
73
|
+
duration_ms,
|
|
74
|
+
op_type,
|
|
75
|
+
status
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (this.metrics.response_times.length > this.max_response_times) {
|
|
79
|
+
this.metrics.response_times.shift();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Log detailed operation info
|
|
83
|
+
this.log.info('Operation tracked', {
|
|
84
|
+
op: op_type,
|
|
85
|
+
duration_ms,
|
|
86
|
+
status,
|
|
87
|
+
error: error || undefined,
|
|
88
|
+
...metadata
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Gets comprehensive performance statistics including operation metrics and rates.
|
|
94
|
+
* @returns {Object} Performance statistics object
|
|
95
|
+
* @returns {number} returns.uptime_ms - Server uptime in milliseconds
|
|
96
|
+
* @returns {number} returns.uptime_seconds - Server uptime in seconds
|
|
97
|
+
* @returns {number} returns.total_requests - Total number of requests processed
|
|
98
|
+
* @returns {number} returns.total_errors - Total number of errors encountered
|
|
99
|
+
* @returns {number} returns.ops_per_second - Operations per second rate
|
|
100
|
+
* @returns {number} returns.avg_response_time_ms - Average response time in milliseconds
|
|
101
|
+
* @returns {number} returns.error_rate_percent - Error rate as percentage
|
|
102
|
+
* @returns {Object} returns.operations - Per-operation statistics breakdown
|
|
103
|
+
* @returns {Array} returns.top_errors - Top 10 most frequent errors
|
|
104
|
+
* @returns {number} returns.recent_response_times - Number of recent response times tracked
|
|
105
|
+
*/
|
|
106
|
+
get_performance_stats() {
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
const uptime_ms = now - this.metrics.start_time;
|
|
109
|
+
const uptime_seconds = uptime_ms / 1000;
|
|
110
|
+
|
|
111
|
+
// Calculate operations per second
|
|
112
|
+
const ops_per_second = uptime_seconds > 0 ? Math.round(this.metrics.total_requests / uptime_seconds) : 0;
|
|
113
|
+
|
|
114
|
+
// Calculate average response time
|
|
115
|
+
const recent_response_times = this.metrics.response_times
|
|
116
|
+
.filter(rt => now - rt.timestamp < 60000) // Last minute
|
|
117
|
+
.map(rt => rt.duration_ms);
|
|
118
|
+
|
|
119
|
+
const avg_response_time = recent_response_times.length > 0
|
|
120
|
+
? Math.round(recent_response_times.reduce((sum, time) => sum + time, 0) / recent_response_times.length)
|
|
121
|
+
: 0;
|
|
122
|
+
|
|
123
|
+
// Calculate error rate
|
|
124
|
+
const error_rate = this.metrics.total_requests > 0
|
|
125
|
+
? Math.round((this.metrics.total_errors / this.metrics.total_requests) * 100 * 100) / 100
|
|
126
|
+
: 0;
|
|
127
|
+
|
|
128
|
+
// Get operation breakdown
|
|
129
|
+
const operation_stats = {};
|
|
130
|
+
for (const [op_type, stats] of this.metrics.operations) {
|
|
131
|
+
operation_stats[op_type] = {
|
|
132
|
+
count: stats.count,
|
|
133
|
+
avg_duration_ms: stats.count > 0 ? Math.round(stats.total_time / stats.count) : 0,
|
|
134
|
+
error_count: stats.errors,
|
|
135
|
+
error_rate: stats.count > 0 ? Math.round((stats.errors / stats.count) * 100 * 100) / 100 : 0
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Get top errors
|
|
140
|
+
const top_errors = Array.from(this.metrics.errors.entries())
|
|
141
|
+
.sort((a, b) => b[1] - a[1])
|
|
142
|
+
.slice(0, 10)
|
|
143
|
+
.map(([error, count]) => ({ error, count }));
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
uptime_ms,
|
|
147
|
+
uptime_seconds: Math.round(uptime_seconds),
|
|
148
|
+
total_requests: this.metrics.total_requests,
|
|
149
|
+
total_errors: this.metrics.total_errors,
|
|
150
|
+
ops_per_second,
|
|
151
|
+
avg_response_time_ms: avg_response_time,
|
|
152
|
+
error_rate_percent: error_rate,
|
|
153
|
+
operations: operation_stats,
|
|
154
|
+
top_errors,
|
|
155
|
+
recent_response_times: recent_response_times.length
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Gets current Node.js process memory usage statistics.
|
|
161
|
+
* @returns {Object} Memory usage statistics
|
|
162
|
+
* @returns {number} returns.rss_mb - Resident Set Size in MB
|
|
163
|
+
* @returns {number} returns.heap_total_mb - Total heap size in MB
|
|
164
|
+
* @returns {number} returns.heap_used_mb - Used heap size in MB
|
|
165
|
+
* @returns {number} returns.heap_used_percent - Heap usage percentage
|
|
166
|
+
* @returns {number} returns.external_mb - External memory usage in MB
|
|
167
|
+
* @returns {number} returns.array_buffers_mb - ArrayBuffer memory usage in MB
|
|
168
|
+
*/
|
|
169
|
+
get_memory_stats() {
|
|
170
|
+
const memory_usage = process.memoryUsage();
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
rss_mb: Math.round(memory_usage.rss / 1024 / 1024),
|
|
174
|
+
heap_total_mb: Math.round(memory_usage.heapTotal / 1024 / 1024),
|
|
175
|
+
heap_used_mb: Math.round(memory_usage.heapUsed / 1024 / 1024),
|
|
176
|
+
heap_used_percent: Math.round((memory_usage.heapUsed / memory_usage.heapTotal) * 100),
|
|
177
|
+
external_mb: Math.round(memory_usage.external / 1024 / 1024),
|
|
178
|
+
array_buffers_mb: Math.round((memory_usage.arrayBuffers || 0) / 1024 / 1024)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Gets LMDB database statistics including storage usage and structure info.
|
|
184
|
+
* @returns {Object} Database statistics object
|
|
185
|
+
* @returns {number} returns.map_size_mb - Total database map size in MB
|
|
186
|
+
* @returns {number} returns.used_space_mb - Used database space in MB
|
|
187
|
+
* @returns {number} returns.usage_percent - Database usage percentage
|
|
188
|
+
* @returns {number} returns.page_size - Database page size in bytes
|
|
189
|
+
* @returns {number} returns.tree_depth - B-tree depth
|
|
190
|
+
* @returns {number} returns.entry_count - Total number of entries
|
|
191
|
+
* @returns {number} returns.branch_pages - Number of branch pages
|
|
192
|
+
* @returns {number} returns.leaf_pages - Number of leaf pages
|
|
193
|
+
*/
|
|
194
|
+
get_database_stats() {
|
|
195
|
+
try {
|
|
196
|
+
const db = get_database();
|
|
197
|
+
const raw_stats = db.getStats ? db.getStats() : {};
|
|
198
|
+
|
|
199
|
+
const map_size_mb = Math.round((raw_stats.mapSize || 0) / 1024 / 1024);
|
|
200
|
+
const used_space_mb = Math.round(((raw_stats.lastPageNumber || 0) * (raw_stats.pageSize || 0)) / 1024 / 1024);
|
|
201
|
+
const usage_percent = map_size_mb > 0 ? Math.round((used_space_mb / map_size_mb) * 100) : 0;
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
map_size_mb,
|
|
205
|
+
used_space_mb,
|
|
206
|
+
usage_percent,
|
|
207
|
+
page_size: raw_stats.pageSize || 0,
|
|
208
|
+
tree_depth: raw_stats.treeDepth || 0,
|
|
209
|
+
entry_count: raw_stats.entryCount || 0,
|
|
210
|
+
branch_pages: raw_stats.treeBranchPages || 0,
|
|
211
|
+
leaf_pages: raw_stats.treeLeafPages || 0
|
|
212
|
+
};
|
|
213
|
+
} catch (error) {
|
|
214
|
+
this.log.warn('Could not get database stats', { error: error.message });
|
|
215
|
+
return {
|
|
216
|
+
error: 'Database stats unavailable',
|
|
217
|
+
map_size_mb: 0,
|
|
218
|
+
used_space_mb: 0,
|
|
219
|
+
usage_percent: 0
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Gets system and Node.js runtime statistics.
|
|
226
|
+
* @returns {Object} System statistics object
|
|
227
|
+
* @returns {string} returns.node_version - Node.js version
|
|
228
|
+
* @returns {string} returns.platform - Operating system platform
|
|
229
|
+
* @returns {string} returns.arch - CPU architecture
|
|
230
|
+
* @returns {number} returns.pid - Process ID
|
|
231
|
+
* @returns {number} returns.cpu_user_ms - CPU user time in milliseconds
|
|
232
|
+
* @returns {number} returns.cpu_system_ms - CPU system time in milliseconds
|
|
233
|
+
*/
|
|
234
|
+
get_system_stats() {
|
|
235
|
+
const cpu_usage = process.cpuUsage();
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
node_version: process.version,
|
|
239
|
+
platform: process.platform,
|
|
240
|
+
arch: process.arch,
|
|
241
|
+
pid: process.pid,
|
|
242
|
+
cpu_user_ms: Math.round(cpu_usage.user / 1000),
|
|
243
|
+
cpu_system_ms: Math.round(cpu_usage.system / 1000)
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Logs a structured operation entry with detailed metrics and automatically tracks it.
|
|
249
|
+
* @param {string} client_id - Client identifier
|
|
250
|
+
* @param {string} op_type - Operation type
|
|
251
|
+
* @param {string|null} collection - Collection name (if applicable)
|
|
252
|
+
* @param {number} duration_ms - Operation duration in milliseconds
|
|
253
|
+
* @param {string} status - Operation status ('success' or 'error')
|
|
254
|
+
* @param {string|null} [error=null] - Error message if operation failed
|
|
255
|
+
* @param {number} [request_size=0] - Request size in bytes
|
|
256
|
+
* @param {number} [response_size=0] - Response size in bytes
|
|
257
|
+
*/
|
|
258
|
+
log_structured_operation(client_id, op_type, collection, duration_ms, status, error = null, request_size = 0, response_size = 0) {
|
|
259
|
+
const log_entry = {
|
|
260
|
+
ts: new Date().toISOString(),
|
|
261
|
+
client_id,
|
|
262
|
+
op: op_type,
|
|
263
|
+
collection: collection || undefined,
|
|
264
|
+
duration_ms,
|
|
265
|
+
status,
|
|
266
|
+
error: error || undefined,
|
|
267
|
+
request_size: request_size || undefined,
|
|
268
|
+
response_size: response_size || undefined
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// Remove undefined fields
|
|
272
|
+
Object.keys(log_entry).forEach(key => {
|
|
273
|
+
if (log_entry[key] === undefined) {
|
|
274
|
+
delete log_entry[key];
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
this.log.info('Structured operation log', log_entry);
|
|
279
|
+
|
|
280
|
+
// Track in performance metrics
|
|
281
|
+
this.track_operation(op_type, duration_ms, status, error, {
|
|
282
|
+
client_id,
|
|
283
|
+
collection,
|
|
284
|
+
request_size,
|
|
285
|
+
response_size
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Resets all performance metrics to initial state.
|
|
291
|
+
* Preserves the start time as current time for accurate uptime calculation.
|
|
292
|
+
*/
|
|
293
|
+
reset_metrics() {
|
|
294
|
+
this.metrics = {
|
|
295
|
+
operations: new Map(),
|
|
296
|
+
errors: new Map(),
|
|
297
|
+
response_times: [],
|
|
298
|
+
start_time: Date.now(),
|
|
299
|
+
total_requests: 0,
|
|
300
|
+
total_errors: 0
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
this.log.info('Performance metrics reset');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Global instance
|
|
308
|
+
const performance_monitor = new PerformanceMonitor();
|
|
309
|
+
|
|
310
|
+
export {
|
|
311
|
+
performance_monitor,
|
|
312
|
+
PerformanceMonitor
|
|
313
|
+
};
|