JDBC: Idea of a Connection Pool

medium JDBC and Databases

Problem

Opening a database connection is slow, so real programs keep a pool of ready connections and reuse them. Simulate a pool without a database. The first line is pool N (connections numbered 1 to N). Commands: acquire (give out the free connection with the smallest number and print it, or print none if all are in use), release ID (take the connection back and print ok, or print error if the number is not valid or that connection is not in use), status (print the number of free connections and the number in use, like: 2 1).

Constraints

  • 1 <= N <= 100
  • 1 <= commands <= 100

Examples

Input

pool 2
acquire
acquire
acquire
release 1
acquire

Output

1
2
none
ok
1

Solutions

Best approachTime O(n log N)Space O(N)

Keep the free numbers in a structure that gives the smallest one fast (a sorted set or a min-heap). Acquire takes from it and release puts back. A real pool (HikariCP, for example) also checks that a connection is still alive, and waits when none is free.

Same code works in Java810172125Basic features only, so nothing changes between versions.

This problem does not use a database, so all four solutions are really run and verified.

/*
 * Problem : Run the commands.
 * Input   : Input lines.
 * Output  : Output lines.
 * Approach: Sorted free set
 * Time    : O(n log N)
 * Space   : O(N)
 * Java    : 8 or newer.
 */
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        int size = Integer.parseInt(lines[0].split(" ")[1]);
        // Step 1: A sorted set of the free connection numbers. pollFirst takes the smallest one.
        TreeSet<Integer> free = new TreeSet<Integer>();
        for (int id = 1; id <= size; id++) {
            free.add(id);
        }
        List<String> out = new ArrayList<String>();
        for (int i = 1; i < lines.length; i++) {
            String[] part = lines[i].split(" ");
            if (part[0].equals("acquire")) {
                // Step 2: Acquire removes the smallest free number. An empty set means the pool is exhausted.
                Integer id = free.pollFirst();
                out.add(id == null ? "none" : String.valueOf(id));
            } else if (part[0].equals("release")) {
                // Step 3: Only a number in range, which is not already free, can be released.
                int id = Integer.parseInt(part[1]);
                if (id < 1 || id > size || free.contains(id)) {
                    out.add("error");
                } else {
                    free.add(id);
                    out.add("ok");
                }
            } else {
                out.add(free.size() + " " + (size - free.size()));
            }
        }
        return out.toArray(new String[0]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (1)
  1. Why is a pool faster than opening a connection each time?