1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.issue.lbcore224;
15
16 import java.io.*;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.regex.Matcher;
20 import java.util.regex.Pattern;
21
22
23
24
25
26 public class Reduce {
27
28 static int NA = -1;
29
30 enum OperationType {
31 LOCK, UNLOCK
32 }
33
34 public static void main(String[] args) throws IOException {
35 File inputFile = new File(args[0]);
36 if (!inputFile.exists()) {
37 throw new IllegalArgumentException("Missing file [" + args[0] + "]");
38 }
39 List<String> lines = readFile(inputFile);
40 System.out.println("Lines count=" + lines.size());
41 List<Structure> structuredLines = structure(lines);
42 List<Structure> reduction = reduce(structuredLines);
43 if (reduction.isEmpty()) {
44 System.out.println("Reduction is EMPTY as it should be.");
45 } else {
46 System.out.println("Non-empty reduction!!! WTF?");
47 System.out.println(reduction);
48 }
49
50 }
51
52 private static List<String> readFile(File inputFile) throws IOException {
53 BufferedReader reader = null;
54 List<String> lines = new ArrayList<>();
55 try {
56 reader = new BufferedReader(new FileReader(inputFile));
57 String line;
58 while ((line = reader.readLine()) != null) {
59 lines.add(line);
60 }
61 } finally {
62 if (reader != null)
63 try {
64 reader.close();
65 } catch (IOException e) {
66 }
67 }
68 return lines;
69 }
70
71 private static List<Structure> reduce(List<Structure> structuredLines) {
72 List<Structure> matching = new ArrayList<>();
73 int lockIndex = 0;
74 while (lockIndex < structuredLines.size()) {
75 lockIndex = findNearestLock(structuredLines, lockIndex);
76 if (lockIndex == NA)
77 break;
78 else {
79 int unlockIndex = findNearestUnlockInSameThread(structuredLines, lockIndex);
80 if (unlockIndex != NA) {
81 matching.add(structuredLines.get(lockIndex));
82 matching.add(structuredLines.get(unlockIndex));
83 }
84 lockIndex++;
85 }
86 }
87 System.out.println("matching list size: " + matching.size());
88 List<Structure> reduction = new ArrayList<Structure>();
89 for (Structure s : structuredLines) {
90 if (!matching.contains(s)) {
91 reduction.add(s);
92 }
93 }
94 return reduction;
95
96 }
97
98 private static int findNearestLock(List<Structure> reduction, int index) {
99 for (int i = index; i < reduction.size(); i++) {
100 Structure s = reduction.get(i);
101 if (s.operationType == OperationType.LOCK) {
102 return i;
103 }
104 }
105 return NA;
106 }
107
108 private static int findNearestUnlockInSameThread(List<Structure> reduction, int lockIndex) {
109 int firstCandidateIndex = lockIndex + 1;
110 Structure lockStructure = reduction.get(lockIndex);
111 for (int i = firstCandidateIndex; i < reduction.size(); i++) {
112 Structure s = reduction.get(i);
113 if (s.operationType == OperationType.UNLOCK && lockStructure.thread.equals(s.thread)) {
114 return i;
115 }
116 }
117 return NA;
118 }
119
120 static List<Structure> structure(List<String> lines) {
121 List<Structure> structuredLines = new ArrayList<>();
122 Pattern p = Pattern.compile("(\\d{2,5})\\ +(.*) (LOCK|UNLOCK)");
123
124 for (String line : lines) {
125 Matcher m = p.matcher(line);
126 if (m.matches()) {
127 String relTime = m.group(1);
128 String t = m.group(2);
129 String opStr = m.group(3);
130 Structure structure = buildStructure(relTime, t, opStr);
131 structuredLines.add(structure);
132 } else {
133 System.out.println("NON MATCHING LINE: [" + line + "]");
134 }
135
136 }
137 return structuredLines;
138 }
139
140 private static Structure buildStructure(String relTime, String t, String opStr) {
141 long r = Long.parseLong(relTime);
142 OperationType operationType;
143 if (opStr.equals("LOCK"))
144 operationType = OperationType.LOCK;
145 else if (opStr.equals("UNLOCK")) {
146 operationType = OperationType.UNLOCK;
147 } else {
148 throw new IllegalArgumentException(opStr + " is not LOCK|UNLOCK");
149 }
150 return new Structure(r, t, operationType);
151 }
152
153 static class Structure {
154 long time;
155 String thread;
156 OperationType operationType;
157
158 Structure(long time, String thread, OperationType operationType) {
159 this.time = time;
160 this.thread = thread;
161 this.operationType = operationType;
162 }
163
164 @Override
165 public String toString() {
166 return "Structure{" + "time=" + time + ", thread='" + thread + '\'' + ", operationType=" + operationType
167 + '}';
168 }
169 }
170
171 }