View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
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   * Reduce a file consisting of lock and unlock operations by removing matching lock/unlocks.
24   */
25  public class Reduce {
26  
27      static int NA = -1;
28  
29      enum OperationType {
30          LOCK, UNLOCK
31      }
32  
33      public static void main(String[] args) throws IOException {
34          File inputFile = new File(args[0]);
35          if (!inputFile.exists()) {
36              throw new IllegalArgumentException("Missing file [" + args[0] + "]");
37          }
38          List<String> lines = readFile(inputFile);
39          System.out.println("Lines count=" + lines.size());
40          List<Structure> structuredLines = structure(lines);
41          List<Structure> reduction = reduce(structuredLines);
42          if (reduction.isEmpty()) {
43              System.out.println("Reduction is EMPTY as it should be.");
44          } else {
45              System.out.println("Non-empty reduction!!! WTF?");
46              System.out.println(reduction);
47          }
48  
49      }
50  
51      private static List<String> readFile(File inputFile) throws IOException {
52          BufferedReader reader = null;
53          List<String> lines = new ArrayList<>();
54          try {
55              reader = new BufferedReader(new FileReader(inputFile));
56              String line;
57              while ((line = reader.readLine()) != null) {
58                  lines.add(line);
59              }
60          } finally {
61              if (reader != null)
62                  try {
63                      reader.close();
64                  } catch (IOException e) {
65                  }
66          }
67          return lines;
68      }
69  
70      private static List<Structure> reduce(List<Structure> structuredLines) {
71          List<Structure> matching = new ArrayList<>();
72          int lockIndex = 0;
73          while (lockIndex < structuredLines.size()) {
74              lockIndex = findNearestLock(structuredLines, lockIndex);
75              if (lockIndex == NA)
76                  break;
77              else {
78                  int unlockIndex = findNearestUnlockInSameThread(structuredLines, lockIndex);
79                  if (unlockIndex != NA) {
80                      matching.add(structuredLines.get(lockIndex));
81                      matching.add(structuredLines.get(unlockIndex));
82                  }
83                  lockIndex++;
84              }
85          }
86          System.out.println("matching list size: " + matching.size());
87          List<Structure> reduction = new ArrayList<Structure>();
88          for (Structure s : structuredLines) {
89              if (!matching.contains(s)) {
90                  reduction.add(s);
91              }
92          }
93          return reduction;
94  
95      }
96  
97      private static int findNearestLock(List<Structure> reduction, int index) {
98          for (int i = index; i < reduction.size(); i++) {
99              Structure s = reduction.get(i);
100             if (s.operationType == OperationType.LOCK) {
101                 return i;
102             }
103         }
104         return NA;
105     }
106 
107     private static int findNearestUnlockInSameThread(List<Structure> reduction, int lockIndex) {
108         int firstCandidateIndex = lockIndex + 1;
109         Structure lockStructure = reduction.get(lockIndex);
110         for (int i = firstCandidateIndex; i < reduction.size(); i++) {
111             Structure s = reduction.get(i);
112             if (s.operationType == OperationType.UNLOCK && lockStructure.thread.equals(s.thread)) {
113                 return i;
114             }
115         }
116         return NA;
117     }
118 
119     static List<Structure> structure(List<String> lines) {
120         List<Structure> structuredLines = new ArrayList<>();
121         Pattern p = Pattern.compile("(\\d{2,5})\\ +(.*) (LOCK|UNLOCK)");
122 
123         for (String line : lines) {
124             Matcher m = p.matcher(line);
125             if (m.matches()) {
126                 String relTime = m.group(1);
127                 String t = m.group(2);
128                 String opStr = m.group(3);
129                 Structure structure = buildStructure(relTime, t, opStr);
130                 structuredLines.add(structure);
131             } else {
132                 System.out.println("NON MATCHING LINE: [" + line + "]");
133             }
134 
135         }
136         return structuredLines;
137     }
138 
139     private static Structure buildStructure(String relTime, String t, String opStr) {
140         long r = Long.parseLong(relTime);
141         OperationType operationType;
142         if (opStr.equals("LOCK"))
143             operationType = OperationType.LOCK;
144         else if (opStr.equals("UNLOCK")) {
145             operationType = OperationType.UNLOCK;
146         } else {
147             throw new IllegalArgumentException(opStr + " is not LOCK|UNLOCK");
148         }
149         return new Structure(r, t, operationType);
150     }
151 
152     static class Structure {
153         long time;
154         String thread;
155         OperationType operationType;
156 
157         Structure(long time, String thread, OperationType operationType) {
158             this.time = time;
159             this.thread = thread;
160             this.operationType = operationType;
161         }
162 
163         @Override
164         public String toString() {
165             return "Structure{" + "time=" + time + ", thread='" + thread + '\'' + ", operationType=" + operationType + '}';
166         }
167     }
168 
169 }