private Map substringSearch()

in storm-webapp/src/main/java/org/apache/storm/daemon/logviewer/handler/LogviewerLogSearchHandler.java [322:416]


    private Map<String, Object> substringSearch(Path file, String searchString, boolean isDaemon, Integer numMatches,
        Integer startByteOffset) throws InvalidRequestException {
        if (StringUtils.isEmpty(searchString)) {
            throw new IllegalArgumentException("Precondition fails: search string should not be empty.");
        }
        if (searchString.getBytes(StandardCharsets.UTF_8).length > GREP_MAX_SEARCH_SIZE) {
            throw new IllegalArgumentException("Precondition fails: the length of search string should be less than "
                + GREP_MAX_SEARCH_SIZE);
        }

        boolean isZipFile = file.toString().endsWith(".gz");
        try (InputStream fis = Files.newInputStream(file)) {
            try (InputStream gzippedInputStream = isZipFile ? new GZIPInputStream(fis) : fis;
                BufferedInputStream stream = new BufferedInputStream(gzippedInputStream)) {

                //It's more likely to be a file read exception here, so we don't differentiate
                int fileLength = isZipFile ? (int) ServerUtils.zipFileSize(file.toFile()) : (int) Files.size(file);

                ByteBuffer buf = ByteBuffer.allocate(GREP_BUF_SIZE);
                final byte[] bufArray = buf.array();
                final byte[] searchBytes = searchString.getBytes(StandardCharsets.UTF_8);
                numMatches = numMatches != null ? numMatches : 10;
                startByteOffset = startByteOffset != null ? startByteOffset : 0;

                // Start at the part of the log file we are interested in.
                // Allow searching when start-byte-offset == file-len so it doesn't blow up on 0-length files
                if (startByteOffset > fileLength) {
                    throw new InvalidRequestException("Cannot search past the end of the file");
                }

                if (startByteOffset > 0) {
                    StreamUtil.skipBytes(stream, startByteOffset);
                }

                Arrays.fill(bufArray, (byte) 0);

                int totalBytesRead = 0;
                int bytesRead = stream.read(bufArray, 0, Math.min(fileLength, GREP_BUF_SIZE));
                buf.limit(bytesRead);
                totalBytesRead += bytesRead;

                List<Map<String, Object>> initialMatches = new ArrayList<>();
                int initBufOffset = 0;
                int byteOffset = startByteOffset;
                byte[] beforeBytes = null;

                Map<String, Object> ret = new HashMap<>();
                while (true) {
                    SubstringSearchResult searchRet = bufferSubstringSearch(isDaemon, file, fileLength, byteOffset, initBufOffset,
                        stream, startByteOffset, totalBytesRead, buf, searchBytes, initialMatches, numMatches, beforeBytes);

                    List<Map<String, Object>> matches = searchRet.getMatches();
                    Integer newByteOffset = searchRet.getNewByteOffset();
                    byte[] newBeforeBytes = searchRet.getNewBeforeBytes();

                    if (matches.size() < numMatches && totalBytesRead + startByteOffset < fileLength) {
                        // The start index is positioned to find any possible
                        // occurrence search string that did not quite fit in the
                        // buffer on the previous read.
                        final int newBufOffset = Math.min(buf.limit(), GREP_MAX_SEARCH_SIZE) - searchBytes.length;

                        totalBytesRead = rotateGrepBuffer(buf, stream, totalBytesRead, fileLength);
                        if (totalBytesRead < 0) {
                            throw new InvalidRequestException("Cannot search past the end of the file");
                        }

                        initialMatches = matches;
                        initBufOffset = newBufOffset;
                        byteOffset = newByteOffset;
                        beforeBytes = newBeforeBytes;
                    } else {
                        ret.put("isDaemon", isDaemon ? "yes" : "no");
                        Integer nextByteOffset = null;
                        if (matches.size() >= numMatches || totalBytesRead < fileLength) {
                            nextByteOffset = (Integer) last(matches).get("byteOffset") + searchBytes.length;
                            if (fileLength <= nextByteOffset) {
                                nextByteOffset = null;
                            }
                        }
                        ret.putAll(mkGrepResponse(searchBytes, startByteOffset, matches, nextByteOffset));
                        break;
                    }
                }
                return ret;
            } catch (UnknownHostException | UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                numFileReadExceptions.mark();
                throw new RuntimeException(e);
            }
        } catch (IOException e) {
            numFileOpenExceptions.mark();
            throw new RuntimeException(e);
        }
    }