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