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
24   * lock/unlocks.
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 }