|
26 | 26 | import java.util.Locale; |
27 | 27 | import java.util.concurrent.TimeUnit; |
28 | 28 | import java.util.Random; |
| 29 | +import java.util.concurrent.atomic.AtomicInteger; |
29 | 30 |
|
30 | 31 | @Service |
31 | 32 | public class ClinicActivityDataService { |
@@ -200,4 +201,106 @@ private String csv(String value) { |
200 | 201 | String escaped = value.replace("\"", "\"\"").replace("\\", "\\\\"); |
201 | 202 | return '"' + escaped + '"'; |
202 | 203 | } |
| 204 | + |
| 205 | + public void createIOIntensiveLoad(int durationMinutes, int numThreads, int limit) { |
| 206 | + logger.warn("Starting I/O INTENSIVE load test for {} minutes with {} threads and {} limit - This will MAX OUT disk I/O operations!", |
| 207 | + durationMinutes, numThreads, limit); |
| 208 | + long startTime = System.currentTimeMillis(); |
| 209 | + long endTime = startTime + (durationMinutes * 60 * 1000L); |
| 210 | + |
| 211 | + try { |
| 212 | + AtomicInteger globalOperationCount = new AtomicInteger(0); |
| 213 | + List<Thread> threads = new ArrayList<>(); |
| 214 | + |
| 215 | + logger.info("Creating {} I/O intensive threads with {} record limit per query...", numThreads, limit); |
| 216 | + |
| 217 | + // Create I/O intensive threads |
| 218 | + for (int t = 0; t < numThreads; t++) { |
| 219 | + final int threadId = t; |
| 220 | + Thread ioThread = new Thread(() -> { |
| 221 | + try { |
| 222 | + executeIOIntensiveThread(threadId, endTime, globalOperationCount, limit); |
| 223 | + } catch (Exception e) { |
| 224 | + logger.error("Error in I/O intensive thread {}", threadId, e); |
| 225 | + } |
| 226 | + }); |
| 227 | + |
| 228 | + ioThread.setName("IOIntensiveThread-" + threadId); |
| 229 | + threads.add(ioThread); |
| 230 | + } |
| 231 | + |
| 232 | + // Start all threads |
| 233 | + logger.info("Starting all {} I/O intensive threads...", numThreads); |
| 234 | + for (Thread thread : threads) { |
| 235 | + thread.start(); |
| 236 | + } |
| 237 | + |
| 238 | + // Wait for all threads to complete |
| 239 | + for (Thread thread : threads) { |
| 240 | + try { |
| 241 | + thread.join(); |
| 242 | + } catch (InterruptedException e) { |
| 243 | + Thread.currentThread().interrupt(); |
| 244 | + logger.warn("Interrupted while waiting for I/O thread: {}", thread.getName()); |
| 245 | + } |
| 246 | + } |
| 247 | + |
| 248 | + long actualEndTime = System.currentTimeMillis(); |
| 249 | + logger.warn("Completed I/O INTENSIVE load test in {} ms with {} threads and {} limit. Total operations: {}", |
| 250 | + (actualEndTime - startTime), numThreads, limit, globalOperationCount.get()); |
| 251 | + |
| 252 | + } catch (Exception e) { |
| 253 | + logger.error("Error during I/O intensive load test", e); |
| 254 | + throw new RuntimeException("Error during I/O intensive load test: " + e.getMessage(), e); |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + private void executeIOIntensiveThread(int threadId, long endTime, AtomicInteger globalOperationCount, int limit) { |
| 259 | + Random random = new Random(); |
| 260 | + Faker faker = new Faker(new Locale("en-US")); |
| 261 | + int localOperationCount = 0; |
| 262 | + |
| 263 | + logger.info("I/O Thread {} starting I/O intensive operations with {} record limit...", threadId, limit); |
| 264 | + |
| 265 | + while (System.currentTimeMillis() < endTime) { |
| 266 | + try { |
| 267 | + // LARGE SEQUENTIAL SCAN - Forces full table scan I/O |
| 268 | + jdbcTemplate.queryForList( |
| 269 | + "SET work_mem = '512MB';" + |
| 270 | + "SELECT id, activity_type, numeric_value, event_timestamp, payload " + |
| 271 | + "FROM clinic_activity_logs " + |
| 272 | + "WHERE LENGTH(payload) > 100 " + |
| 273 | + "ORDER BY random()" + |
| 274 | + "LIMIT " + limit); |
| 275 | + |
| 276 | + |
| 277 | + localOperationCount++; |
| 278 | + int currentGlobalCount = globalOperationCount.incrementAndGet(); |
| 279 | + |
| 280 | + // Log progress every 100 operations per thread |
| 281 | + if (localOperationCount % 100 == 0) { |
| 282 | + long remainingTime = (endTime - System.currentTimeMillis()) / 1000; |
| 283 | + logger.info("I/O Thread {} completed {} operations (Global: {}). Time remaining: {}s", |
| 284 | + threadId, localOperationCount, currentGlobalCount, remainingTime); |
| 285 | + } |
| 286 | + |
| 287 | + // No sleep - continuous I/O operations for maximum I/O pressure |
| 288 | + // But avoid overwhelming the system with a tiny yield |
| 289 | + if (localOperationCount % 50 == 0) { |
| 290 | + Thread.yield(); |
| 291 | + } |
| 292 | + |
| 293 | + } catch (Exception e) { |
| 294 | + logger.error("Error in I/O operation for thread {}", threadId, e); |
| 295 | + try { |
| 296 | + Thread.sleep(10); // Brief pause on error |
| 297 | + } catch (InterruptedException ie) { |
| 298 | + Thread.currentThread().interrupt(); |
| 299 | + break; |
| 300 | + } |
| 301 | + } |
| 302 | + } |
| 303 | + |
| 304 | + logger.info("I/O Thread {} completed {} total I/O operations", threadId, localOperationCount); |
| 305 | + } |
203 | 306 | } |
0 commit comments