Sunday, May 2, 2021

Multithreading for experienced Professional

Problem 1.) I have a large text file, in this case it's roughly 4.5 GB, and I need to process the entire file as fast as is possible. 


When the data gets to output, it either needs to be sorted into the correct order, or it needs to already be in the correct order.

It is better to do it with ordered task:

class OrderedTask implements Comparable<OrderedTask> {

    private final Integer index;
    private final String line;

    public OrderedTask(Integer index, String line) {
        this.index = index;
        this.line = line;
    }


    @Override
    public int compareTo(OrderedTask o) {
        return index < o.getIndex() ? -1 : index == o.getIndex() ? 0 : 1;
    }

    public Integer getIndex() {
        return index;
    }

    public String getLine() {
        return line;
    }    
}

As an output queue you can use your own backed by priority queue:

class OrderedTaskQueue {

    private final ReentrantLock lock;
    private final Condition waitForOrderedItem;
    private final int maxQueuesize;
    private final PriorityQueue<OrderedTask> backedQueue;

    private int expectedIndex;

    public OrderedTaskQueue(int maxQueueSize, int startIndex) {
        this.maxQueuesize = maxQueueSize;
        this.expectedIndex = startIndex;
        this.backedQueue = new PriorityQueue<>(2 * this.maxQueuesize);

        this.lock = new ReentrantLock();
        this.waitForOrderedItem = this.lock.newCondition();
    }


    public boolean put(OrderedTask item) {
        ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while (this.backedQueue.size() >= maxQueuesize && item.getIndex() != expectedIndex) {
                this.waitForOrderedItem.await();
            }

            boolean result = this.backedQueue.add(item);
            this.waitForOrderedItem.signalAll();
            return result;
        } catch (InterruptedException e) {
            throw new RuntimeException();
        } finally {
            lock.unlock();
        }
    }


    public OrderedTask take() {
        ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while (this.backedQueue.peek() == null || this.backedQueue.peek().getIndex() != expectedIndex) {
                this.waitForOrderedItem.await();
            }
            OrderedTask result = this.backedQueue.poll();
            expectedIndex++;
            this.waitForOrderedItem.signalAll();
            return result;
        } catch (InterruptedException e) {
            throw new RuntimeException();
        } finally {
            lock.unlock();
        }
    }
}

StartIndex is the index of the first ordered task, and maxQueueSize is used to stop processing of other tasks (not to fill the memory), when we wait for some earlier task to finish. It should be double/tripple of the number of processing thread, to not stop the processing immediatelly and allow the scalability.

Then you should create your task :

int indexOrder =0;
            while ((line = reader.readLine()) != null) {
                inputQueue.put(new OrderedTask(indexOrder++,line);                    

            }

The line by line is only used because of your example. You should change the OrderedTask to support the batch of lines.

Main thread:

static volatile boolean readerFinished = false; // class level variables
static volatile boolean writerFinished = false;

private void initialise() throws IOException {
    BlockingQueue<String> inputQueue = new LinkedBlockingQueue<>(1_000_000);
    BlockingQueue<String> outputQueue = new LinkedBlockingQueue<>(1_000_000); // capacity 1 million. 

    String inputFileName = "test.txt";
    String outputFileName = "outputTest.txt";

    BufferedReader reader = new BufferedReader(new FileReader(inputFileName));
    BufferedWriter writer = new BufferedWriter(new FileWriter(outputFileName));


    Thread T1 = new Thread(new Input(reader, inputQueue));
    Thread T2 = new Thread(new Processing(inputQueue, outputQueue));
    Thread T3 = new Thread(new Output(writer, outputQueue));

    T1.start();
    T2.start();
    T3.start();

    while (!writerFinished) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    reader.close();
    writer.close();

    System.out.println("Exited.");
}

Input thread: (Please forgive the commented debug code, was using it to ensure the reader thread was actually executing properly).

class Input implements Runnable {
    BufferedReader reader;
    BlockingQueue<String> inputQueue;

    Input(BufferedReader reader, BlockingQueue<String> inputQueue) {
        this.reader = reader;
        this.inputQueue = inputQueue;
    }

    @Override
    public void run() {
        String poisonPill = "ChH92PU2KYkZUBR";
        String line;
        //int linesRead = 0;

        try {
            while ((line = reader.readLine()) != null) {
                inputQueue.put(line);
                //linesRead++;

                /*
                if (linesRead == 500_000) {
                    //batchesRead += 1;
                    //System.out.println("Batch read");
                    linesRead = 0;
                }
                */
            }

            inputQueue.put(poisonPill);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

        readerFinished = true;

    }
}

Processing thread: (Normally this would actually be doing something to the line, but for purposes of the mockup I've just made it immediately push to the output thread). If necessary we can simulate it doing some work by making the thread sleep for a small amount of time for each line.

class Processing implements Runnable {
    BlockingQueue<String> inputQueue;
    BlockingQueue<String> outputQueue;

    Processing(BlockingQueue<String> inputQueue, BlockingQueue<String> outputQueue) {
        this.inputQueue = inputQueue;
        this.outputQueue = outputQueue;
    }

    @Override
    public void run() {
        while (true) {
            try {
                if (inputQueue.isEmpty() && readerFinished) {
                    break;
                }

                String line = inputQueue.take();
                outputQueue.put(line);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Output thread:

class Output implements Runnable {
    BufferedWriter writer;
    BlockingQueue<String> outputQueue;

    Output(BufferedWriter writer, BlockingQueue<String> outputQueue) {
        this.writer = writer;
        this.outputQueue = outputQueue;
    }

    @Override
    public void run() {
        String line;
        ArrayList<String> outputList = new ArrayList<>();

        while (true) {
            try {
                line = outputQueue.take();

                if (line.equals("ChH92PU2KYkZUBR")) {
                    for (String outputLine : outputList) {
                        writer.write(outputLine);
                    }
                    System.out.println("Writer finished - executing termination");

                    writerFinished = true;
                    break;
                }

                line += "\n";
                outputList.add(line);

                if (outputList.size() == 500_000) {
                    for (String outputLine : outputList) {
                        writer.write(outputLine);
                    }
                    System.out.println("Writer wrote batch");
                    outputList = new ArrayList<>();
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


Friday, April 30, 2021

Steps of Spring Security and JWT

 Steps of Spring Security and JWT:

1. Dependency of jsonWebToken in Maven.

2. In Main class, @EnableWebSecurity annotation which extends WebSecurityConfigurerAdapter

3. Override configure method

protected void configure(HttpSecurity httpSecurity){

    httpSecurity.csrf().disable()

                        .authorizeRequests().antMatchers("/authenticate")

                        .permitAll()

                        .anyRequest().authenticated().and().

                        .exceptionHandling().and().sessionManagement()

                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

  httSecurity.addFIlterBefore(jwtRequestFilter, userNamePwdAuthenticationFIlter);

4. Make request Mapping of "/authenticate" where jwtTokenUtil.generateToken(userDetails).

5. Create a Service class jwtTokenUtil having generateToken method:

     JwtBuilder.setClaims(claims).setSubject(subject).setIssuedAt(time).setExpiration(time)

    .signWith(SignatureAlgorithm.H256, SECRET_KEY).compare()

6. also validateToken by extracting userName.

7. Create Filter JwtRequestFilter extends OncePerRequestFilter

    @Override

    protected void doFilterInternal(HttpServletRequest request, response, filterChain){

        final String auth = request.getHeader("Authorization");

        jwtUtil.extractUserName(auth);

8. validateToken

9. chain.doFilter(request, response);


Performance Tests

 Performance Tests:

Frequently we discuss performance testing without considering the specifics. Multiple types of performance tests can be performed on a system at a very high scale.

The most common types of performance tests are as follow

LATENCY TEST

  • It is intended to compute the end to end transaction time.
  • The latency of the system is an observable parameter to the management, which tells how long customers have to wait for a transaction to happen. Hence this is one of the important performance tests.
  • Avg. value computation is not the right choice, latency is mostly computed in terms of P99.99, P99.9, P99, and P95.

THROUGHPUT TEST

  • It defines how many concurrent transactions a system can handle.
  • Latency and throughput tests are mostly interrelated.
  • Max throughput of the system is measured until the system starts degrading.

LOAD TEST

  • It represents a binary question — can the system handle a specific load?
  • It is mostly conducted just before the business events e.g. launch in a new country, viral content, and social media events.

STRESS TEST

  • It is intended to compute the breaking point of the system and how much spare headroom systems have.

ENDURANCE TEST

  • To detect the anomalies in the system if the system runs for an extended duration.
  • Many problems in the system are detected only if the system runs for a longer duration e.g. Slow memory leaks, cache population, and memory fragmentation issues.
  • It is the most suggested test for the fast response system which cannot tolerate the long length of the stop the world event caused by the full GC.

CAPACITY PLANNING TEST

  • To check if the system scales as per the expectations when additional resources are added to the system.

DEGRADATION TESTING

  • To check the behavior of the system when it partially fails. It is also known as the partial failure test.
  • It is usually done to validate the resiliency of the system. Chaos Monkey by Netflix is one such example to build a truly resilient system.

RULES TO SELECT TESTS

Golden rules that provide useful guidance over which performance test you should perform:

  • Identify what you care about and figure out how to measure it.
  • Optimize what matters, not what is easy to optimize.
  • Play the big points first.

NON FUNCTIONAL REQUIREMENTS

Observables that are important to the management and system.

NFR’s are generally provided as follow by the management:

  • Reduce the 95% percentile transaction time by 100ms
  • Improve system so that 5x throughput on existing hardware is possible.
  • Improve average response time by 30%

Top DataStructures Problem from Medium-2

  Array: Find a pair with the given sum in an array Maximum Sum Subarray Problem (Kadane’s Algorithm) Longest Increasing Subsequence Problem...