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);
}
}