| /** |
| * SessionPool Example |
| * |
| * This example demonstrates how to use SessionPool for efficient connection |
| * management in high-concurrency scenarios, including explicit session management. |
| */ |
| |
| import { SessionPool, PoolConfigBuilder, TreeTablet, TSDataType } from "../src"; |
| |
| async function main() { |
| console.log("=== SessionPool Example ===\n"); |
| |
| // Method 1: Traditional constructor (backward compatible) |
| console.log("Creating session pool using traditional constructor..."); |
| const pool1 = new SessionPool("localhost", 6667, { |
| username: "root", |
| password: "root", |
| maxPoolSize: 10, |
| minPoolSize: 2, |
| maxIdleTime: 60000, |
| waitTimeout: 60000, |
| }); |
| |
| // Method 2: Using Builder pattern (recommended) |
| console.log("Creating session pool using Builder pattern..."); |
| const pool2 = new SessionPool( |
| new PoolConfigBuilder() |
| .host("localhost") |
| .port(6667) |
| .username("root") |
| .password("root") |
| .maxPoolSize(10) |
| .minPoolSize(2) |
| .maxIdleTime(60000) |
| .waitTimeout(60000) |
| .build(), |
| ); |
| |
| // For demo purposes, we'll use pool1 |
| const pool = pool1; |
| |
| try { |
| // Initialize the pool |
| console.log("\nInitializing session pool..."); |
| await pool.init(); |
| console.log("Pool initialized with", pool.getPoolSize(), "connections"); |
| |
| // Create database |
| console.log("\nCreating database..."); |
| await pool.executeNonQueryStatement("CREATE DATABASE root.pool_example"); |
| |
| // Create timeseries |
| console.log("Creating timeseries..."); |
| await pool.executeNonQueryStatement( |
| "CREATE TIMESERIES root.pool_example.sensor1.value WITH DATATYPE=FLOAT", |
| ); |
| |
| // Approach 1: Using pool methods directly (automatic session management) |
| console.log("\n--- Approach 1: Automatic session management ---"); |
| console.log("Executing concurrent queries..."); |
| const promises = []; |
| |
| for (let i = 0; i < 20; i++) { |
| promises.push( |
| pool.executeQueryStatement("SHOW DATABASES").then(async (dataSet) => { |
| let count = 0; |
| while (await dataSet.hasNext()) { |
| dataSet.next(); |
| count++; |
| } |
| await dataSet.close(); |
| console.log(`Query ${i + 1} completed with ${count} rows`); |
| }), |
| ); |
| } |
| |
| await Promise.all(promises); |
| console.log("All concurrent queries completed"); |
| |
| // Approach 2: Explicit session management (new API) |
| console.log("\n--- Approach 2: Explicit session management ---"); |
| console.log("Getting a session from the pool..."); |
| const session = await pool.getSession(); |
| |
| try { |
| console.log("Executing operations with explicit session..."); |
| |
| // Insert data using TreeTablet class with addRow |
| const tablet = new TreeTablet( |
| "root.pool_example.sensor1", |
| ["value"], |
| [TSDataType.FLOAT] |
| ); |
| tablet.addRow(Date.now(), [42.5]); |
| tablet.addRow(Date.now() + 1000, [43.0]); |
| |
| await session.insertTablet(tablet); |
| console.log("Tree tablet data inserted via explicit session"); |
| |
| // Query data |
| const dataSet = await session.executeQueryStatement( |
| "SELECT * FROM root.pool_example.sensor1", |
| ); |
| let rowCount = 0; |
| while (await dataSet.hasNext()) { |
| dataSet.next(); |
| rowCount++; |
| } |
| await dataSet.close(); |
| console.log("Query result:", rowCount, "rows"); |
| } finally { |
| // Always release the session back to the pool |
| pool.releaseSession(session); |
| console.log("Session released back to the pool"); |
| } |
| |
| // Check pool statistics |
| console.log("\nPool statistics:"); |
| console.log("Total connections:", pool.getPoolSize()); |
| console.log("Available connections:", pool.getAvailableSize()); |
| console.log("In-use connections:", pool.getInUseSize()); |
| |
| // Enhanced metrics |
| console.log("\nEnhanced pool metrics:"); |
| console.log("Total (new API):", pool.totalCount); |
| console.log("Idle (new API):", pool.idleCount); |
| console.log("Active (new API):", pool.activeCount); |
| console.log("Waiting requests:", pool.waitingCount); |
| |
| // Comprehensive statistics |
| const stats = pool.getPoolStats(); |
| console.log("\nComprehensive stats:", stats); |
| |
| // Approach 3: Concurrent batch insertion (NEW API) |
| console.log("\n--- Approach 3: Concurrent batch insertion (insertTabletsParallel) ---"); |
| const tablets = []; |
| const batchTime = Date.now(); |
| |
| for (let i = 0; i < 20; i++) { |
| tablets.push({ |
| deviceId: `root.pool_example.batch_sensor${i}`, |
| measurements: ["value"], |
| dataTypes: [TSDataType.FLOAT], |
| timestamps: [batchTime + i * 1000], |
| values: [[100.0 + i]], |
| }); |
| } |
| |
| console.log(`Inserting ${tablets.length} tablets concurrently...`); |
| const startTime = Date.now(); |
| await pool.insertTabletsParallel(tablets, { concurrency: 5 }); |
| const elapsed = Date.now() - startTime; |
| console.log(`Inserted ${tablets.length} tablets in ${elapsed}ms (${(tablets.length * 1000 / elapsed).toFixed(2)} tablets/sec)`); |
| |
| // Approach 4: Generic parallel execution (NEW API) |
| console.log("\n--- Approach 4: Generic parallel execution (executeParallel) ---"); |
| const deviceNames = ["parallel_d1", "parallel_d2", "parallel_d3", "parallel_d4"]; |
| |
| console.log(`Creating ${deviceNames.length} timeseries in parallel...`); |
| const results = await pool.executeParallel( |
| deviceNames, |
| async (session, deviceName) => { |
| try { |
| await session.executeNonQueryStatement( |
| `CREATE TIMESERIES root.pool_example.${deviceName}.value WITH DATATYPE=FLOAT` |
| ); |
| } catch { |
| // Ignore if already exists |
| } |
| return `Created ${deviceName}`; |
| }, |
| { concurrency: 4 } |
| ); |
| console.log("Results:", results); |
| |
| } catch (error) { |
| console.error("Error:", error); |
| } finally { |
| // Close the pool |
| console.log("\nClosing session pool..."); |
| await pool.close(); |
| console.log("Pool closed"); |
| } |
| } |
| |
| main().catch(console.error); |