2
0

test_1m.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. const net = require('net');
  2. class KVClient {
  3. constructor(host = 'localhost', port = 8080) {
  4. this.host = host;
  5. this.port = port;
  6. this.client = null;
  7. }
  8. connect() {
  9. return new Promise((resolve, reject) => {
  10. this.client = net.createConnection({ host: this.host, port: this.port }, () => {
  11. console.log('Connected to KV database');
  12. resolve();
  13. });
  14. this.client.on('error', (err) => {
  15. reject(err);
  16. });
  17. });
  18. }
  19. sendCommand(command) {
  20. return new Promise((resolve, reject) => {
  21. let response = '';
  22. const dataHandler = (data) => {
  23. response += data.toString();
  24. // Assuming responses end with \r
  25. if (response.includes('\r')) {
  26. this.client.removeListener('data', dataHandler);
  27. resolve(response.replace(/\r/g, '').trim());
  28. }
  29. };
  30. this.client.on('data', dataHandler);
  31. this.client.write(command + '\r', (err) => {
  32. if (err) {
  33. this.client.removeListener('data', dataHandler);
  34. reject(err);
  35. }
  36. });
  37. // Timeout after 5 seconds
  38. setTimeout(() => {
  39. this.client.removeListener('data', dataHandler);
  40. reject(new Error('Command timeout'));
  41. }, 5000);
  42. });
  43. }
  44. async write(key, value) {
  45. return await this.sendCommand(`write ${key}|${value}`);
  46. }
  47. async read(key) {
  48. return await this.sendCommand(`read ${key}`);
  49. }
  50. close() {
  51. if (this.client) {
  52. this.client.end();
  53. }
  54. }
  55. }
  56. async function testBatch(client, batchSize, batchNum, allResults) {
  57. console.log(`\n${'='.repeat(60)}`);
  58. console.log(`BATCH ${batchNum}: Writing and verifying ${batchSize.toLocaleString()} entries`);
  59. console.log('='.repeat(60));
  60. const batchData = new Map();
  61. const batchResults = {
  62. batchSize,
  63. batchNum,
  64. successfulWrites: 0,
  65. failedWrites: 0,
  66. successfulReads: 0,
  67. failedReads: 0,
  68. mismatches: 0,
  69. errors: []
  70. };
  71. // Write phase
  72. console.log(`\nWriting ${batchSize.toLocaleString()} entries...`);
  73. const startWrite = Date.now();
  74. for (let i = 0; i < batchSize; i++) {
  75. const key = `key_batch${batchNum}_${i}`;
  76. const value = `value_${batchNum}_${i}_${Math.random().toString(36).substring(7)}`;
  77. batchData.set(key, value);
  78. try {
  79. await client.write(key, value);
  80. batchResults.successfulWrites++;
  81. } catch (err) {
  82. batchResults.failedWrites++;
  83. batchResults.errors.push({ operation: 'write', key, error: err.message });
  84. }
  85. if ((i + 1) % Math.max(1, Math.floor(batchSize / 10)) === 0) {
  86. const progress = ((i + 1) / batchSize * 100).toFixed(1);
  87. process.stdout.write(`\r Progress: ${(i + 1).toLocaleString()}/${batchSize.toLocaleString()} (${progress}%)`);
  88. }
  89. }
  90. const writeDuration = Date.now() - startWrite;
  91. console.log(`\n Completed in ${writeDuration}ms (${(writeDuration / 1000).toFixed(2)}s) - ${(batchSize / (writeDuration / 1000)).toFixed(2)} writes/sec`);
  92. // Read and verify phase
  93. console.log(`\nVerifying ${batchSize.toLocaleString()} entries...`);
  94. const startRead = Date.now();
  95. let readCount = 0;
  96. for (const [key, expectedValue] of batchData) {
  97. try {
  98. const response = await client.read(key);
  99. readCount++;
  100. // Parse response (adjust based on your server's response format)
  101. const actualValue = response.includes('|') ? response.split('|')[1] : response;
  102. if (actualValue === expectedValue) {
  103. batchResults.successfulReads++;
  104. } else {
  105. batchResults.mismatches++;
  106. batchResults.errors.push({
  107. operation: 'read',
  108. key,
  109. expected: expectedValue,
  110. actual: actualValue
  111. });
  112. }
  113. if (readCount % Math.max(1, Math.floor(batchSize / 10)) === 0) {
  114. const progress = (readCount / batchSize * 100).toFixed(1);
  115. process.stdout.write(`\r Progress: ${readCount.toLocaleString()}/${batchSize.toLocaleString()} (${progress}%)`);
  116. }
  117. } catch (err) {
  118. batchResults.failedReads++;
  119. batchResults.errors.push({ operation: 'read', key, error: err.message });
  120. }
  121. }
  122. const readDuration = Date.now() - startRead;
  123. console.log(`\n Completed in ${readDuration}ms (${(readDuration / 1000).toFixed(2)}s) - ${(batchSize / (readDuration / 1000)).toFixed(2)} reads/sec`);
  124. // Batch summary
  125. const batchSuccess = batchResults.failedWrites === 0 &&
  126. batchResults.failedReads === 0 &&
  127. batchResults.mismatches === 0;
  128. console.log(`\nBatch ${batchNum} Results:`);
  129. console.log(` Writes: ${batchResults.successfulWrites}/${batchSize} successful`);
  130. console.log(` Reads: ${batchResults.successfulReads}/${batchSize} successful`);
  131. console.log(` Status: ${batchSuccess ? '✓ PASSED' : '✗ FAILED'}`);
  132. if (batchResults.errors.length > 0) {
  133. console.log(` Errors: ${batchResults.errors.length} (showing first 5):`);
  134. batchResults.errors.slice(0, 5).forEach((err, idx) => {
  135. console.log(` ${idx + 1}. ${err.operation.toUpperCase()} ${err.key}: ${err.error || 'Value mismatch'}`);
  136. });
  137. }
  138. allResults.push(batchResults);
  139. return batchData;
  140. }
  141. async function testKVDatabase() {
  142. const client = new KVClient('localhost', 8080);
  143. const allResults = [];
  144. const allData = new Map();
  145. // Batch sizes: 1K, 10K, 100K, 1M
  146. const batches = [
  147. { size: 1000, label: '1K' },
  148. { size: 10000, label: '10K' },
  149. { size: 100000, label: '100K' },
  150. { size: 1000000, label: '1M' }
  151. ];
  152. try {
  153. await client.connect();
  154. const overallStart = Date.now();
  155. for (let i = 0; i < batches.length; i++) {
  156. const batchData = await testBatch(client, batches[i].size, i + 1, allResults);
  157. // Store all data for potential final verification
  158. for (const [key, value] of batchData) {
  159. allData.set(key, value);
  160. }
  161. }
  162. const overallDuration = Date.now() - overallStart;
  163. // Final comprehensive report
  164. console.log('\n\n' + '='.repeat(60));
  165. console.log('FINAL COMPREHENSIVE REPORT');
  166. console.log('='.repeat(60));
  167. let totalWrites = 0, successfulWrites = 0, failedWrites = 0;
  168. let totalReads = 0, successfulReads = 0, failedReads = 0, totalMismatches = 0;
  169. let totalErrors = 0;
  170. console.log('\nPer-Batch Summary:');
  171. allResults.forEach((batch) => {
  172. totalWrites += batch.batchSize;
  173. successfulWrites += batch.successfulWrites;
  174. failedWrites += batch.failedWrites;
  175. successfulReads += batch.successfulReads;
  176. failedReads += batch.failedReads;
  177. totalMismatches += batch.mismatches;
  178. totalErrors += batch.errors.length;
  179. const batchSuccess = batch.failedWrites === 0 && batch.failedReads === 0 && batch.mismatches === 0;
  180. console.log(` Batch ${batch.batchNum} (${batch.batchSize.toLocaleString()}): ${batchSuccess ? '✓ PASSED' : '✗ FAILED'}`);
  181. });
  182. console.log(`\nOverall Statistics:`);
  183. console.log(` Total entries: ${allData.size.toLocaleString()}`);
  184. console.log(` Total time: ${overallDuration}ms (${(overallDuration / 1000).toFixed(2)}s)`);
  185. console.log(` Average throughput: ${(totalWrites / (overallDuration / 1000)).toFixed(2)} operations/sec`);
  186. console.log(`\nWrite Operations:`);
  187. console.log(` Total: ${totalWrites.toLocaleString()}`);
  188. console.log(` Successful: ${successfulWrites.toLocaleString()}`);
  189. console.log(` Failed: ${failedWrites.toLocaleString()}`);
  190. console.log(` Success rate: ${((successfulWrites / totalWrites) * 100).toFixed(2)}%`);
  191. console.log(`\nRead Operations:`);
  192. console.log(` Total: ${totalReads.toLocaleString()}`);
  193. console.log(` Successful: ${successfulReads.toLocaleString()}`);
  194. console.log(` Failed: ${failedReads.toLocaleString()}`);
  195. console.log(` Mismatches: ${totalMismatches.toLocaleString()}`);
  196. console.log(` Success rate: ${((successfulReads / totalReads) * 100).toFixed(2)}%`);
  197. const overallSuccess = failedWrites === 0 && failedReads === 0 && totalMismatches === 0;
  198. console.log(`\n${'='.repeat(60)}`);
  199. console.log(`FINAL RESULT: ${overallSuccess ? '✓ ALL TESTS PASSED!' : '✗ SOME TESTS FAILED'}`);
  200. console.log('='.repeat(60));
  201. if (totalErrors > 0) {
  202. console.log(`\nTotal errors across all batches: ${totalErrors}`);
  203. }
  204. } catch (err) {
  205. console.error('\nConnection error:', err.message);
  206. } finally {
  207. client.close();
  208. }
  209. }
  210. // Run the test
  211. console.log('Starting KV Database Progressive Load Test');
  212. console.log('Testing batches: 1K → 10K → 100K → 1M entries\n');
  213. testKVDatabase().catch(console.error);