diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7074f4b --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/src/main/java/com/intellij/rt/debugger/agent/CaptureAgent.java b/src/main/java/com/intellij/rt/debugger/agent/CaptureAgent.java index c71e27e..c1dffc0 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/CaptureAgent.java +++ b/src/main/java/com/intellij/rt/debugger/agent/CaptureAgent.java @@ -13,7 +13,7 @@ import java.security.ProtectionDomain; import java.util.*; -@SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "rawtypes"}) +@SuppressWarnings("rawtypes") public final class CaptureAgent { private static Instrumentation ourInstrumentation; private static final Set mySkipped = new HashSet<>(); @@ -122,7 +122,7 @@ public byte[] transform(ClassLoader loader, static void storeClassForDebug(String className, byte[] bytes) { if (CaptureStorage.DEBUG) { try { - FileOutputStream stream = new FileOutputStream("instrumented_" + className.replaceAll("/", "_") + ".class"); + FileOutputStream stream = new FileOutputStream("instrumented_" + className.replace("/", "_") + ".class"); try { stream.write(bytes); } diff --git a/src/main/java/com/intellij/rt/debugger/agent/CaptureStorage.java b/src/main/java/com/intellij/rt/debugger/agent/CaptureStorage.java index 560bfbf..3dd820c 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/CaptureStorage.java +++ b/src/main/java/com/intellij/rt/debugger/agent/CaptureStorage.java @@ -12,7 +12,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -@SuppressWarnings({"UseOfSystemOutOrSystemErr"}) public final class CaptureStorage { public static final String GENERATED_INSERT_METHOD_POSTFIX = "$$$capture"; private static final ConcurrentIdentityWeakHashMap STORAGE_GENERAL = new ConcurrentIdentityWeakHashMap<>(); @@ -32,6 +31,7 @@ protected Deque initialValue() { ); static final double DEFAULT_OVERHEAD_PERCENT = 50; + private static final String PACKAGE_PREFIX = CaptureStorage.class.getPackage().getName(); private static OverheadDetector ourOverheadDetector = new OverheadDetector(DEFAULT_OVERHEAD_PERCENT, true); static void init(Properties properties) { @@ -645,12 +645,11 @@ public static void setEnabled(boolean enabled) { private static void handleException(Throwable e) { ENABLED = false; System.err.println("Critical error in IDEA Async Stacktraces instrumenting agent. Agent is now disabled. Please report to IDEA support:"); - //noinspection CallToPrintStackTrace e.printStackTrace(); } static boolean isAgentFrame(StackTraceElement elem) { - return elem.getClassName().startsWith(CaptureStorage.class.getPackage().getName()); + return elem.getClassName().startsWith(PACKAGE_PREFIX); } static List getCurrentStackTraceWithoutAgentFrames() { diff --git a/src/main/java/com/intellij/rt/debugger/agent/CapturedStackDeduplicator.java b/src/main/java/com/intellij/rt/debugger/agent/CapturedStackDeduplicator.java index 7979099..ca26682 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/CapturedStackDeduplicator.java +++ b/src/main/java/com/intellij/rt/debugger/agent/CapturedStackDeduplicator.java @@ -29,21 +29,19 @@ private StackRef(int id, List stack) { private final List events; private final int maxStackDepth; - private final ArrayList> stacks; + private final ArrayList> stacks = new ArrayList<>(); private final int[] throwableStackIds; private final int[] capturedStackIds; - private final IdentityHashMap throwableStacks; - private final IdentityHashMap capturedStacks; + private final IdentityHashMap throwableStacks = new IdentityHashMap<>(); + private final IdentityHashMap capturedStacks = new IdentityHashMap<>(); private CapturedStackDeduplicator(List events, int maxStackDepth) { this.events = events; this.maxStackDepth = maxStackDepth; + int eventCount = events.size(); - stacks = new ArrayList<>(); throwableStackIds = new int[eventCount]; capturedStackIds = new int[eventCount]; - throwableStacks = new IdentityHashMap<>(); - capturedStacks = new IdentityHashMap<>(); } static StackDictionary createStackDictionary(List events, int maxStackDepth) { diff --git a/src/main/java/com/intellij/rt/debugger/agent/CollectionBreakpointInstrumentor.java b/src/main/java/com/intellij/rt/debugger/agent/CollectionBreakpointInstrumentor.java index ea220c1..c0c3656 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/CollectionBreakpointInstrumentor.java +++ b/src/main/java/com/intellij/rt/debugger/agent/CollectionBreakpointInstrumentor.java @@ -18,7 +18,7 @@ import static com.intellij.rt.debugger.agent.CaptureAgent.getInternalClsName; -@SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "rawtypes"}) +@SuppressWarnings("rawtypes") public class CollectionBreakpointInstrumentor { private static final String OBJECT_TYPE = "Ljava/lang/Object;"; private static final String STRING_TYPE = "Ljava/lang/String;"; @@ -139,13 +139,9 @@ private static void processFailedToInstrumentError(String className, Exception e private static void writeDebugInfo(String className, byte[] bytes) { try { System.out.println("instrumented: " + className); - FileOutputStream stream = new FileOutputStream("instrumented_" + className.replaceAll("/", "_") + ".class"); - try { - stream.write(bytes); - } - finally { - stream.close(); - } + try (FileOutputStream stream = new FileOutputStream("instrumented_" + className.replace("/", "_") + ".class")) { + stream.write(bytes); + } } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/com/intellij/rt/debugger/agent/DebuggerAgent.java b/src/main/java/com/intellij/rt/debugger/agent/DebuggerAgent.java index fa1a7f8..faf993d 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/DebuggerAgent.java +++ b/src/main/java/com/intellij/rt/debugger/agent/DebuggerAgent.java @@ -14,7 +14,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; -@SuppressWarnings("UseOfSystemOutOrSystemErr") public class DebuggerAgent { private static final String KEEP_SUFFIX = "[keep]"; diff --git a/src/main/java/com/intellij/rt/debugger/agent/LogCaptureStorage.java b/src/main/java/com/intellij/rt/debugger/agent/LogCaptureStorage.java index 581b436..b06bbae 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/LogCaptureStorage.java +++ b/src/main/java/com/intellij/rt/debugger/agent/LogCaptureStorage.java @@ -10,6 +10,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.zip.Deflater; import java.util.zip.GZIPOutputStream; public class LogCaptureStorage { @@ -27,36 +28,57 @@ protected Boolean initialValue() { static final String BATCHING_ENABLED_PROPERTY = "logCaptureBatchingEnabled"; static final String BATCHING_FLUSH_PERIOD_PROPERTY = "logCaptureBatchingFlushPeriod"; static final String BATCHING_BUFFER_SIZE_PROPERTY = "logCaptureBatchingBufferSize"; - private static final long DEFAULT_BUFFER_SIZE = calculateDefaultBufferSize(); - private static final int ESTIMATED_THROWABLE_BYTES = 3000; + static final String FORCE_BATCHING_BUFFER_SIZE_PROPERTY = "logCaptureForceBatchingBufferSize"; + private static final int ESTIMATED_THROWABLE_BYTES = 3000; // See the comment at the top of ThrowableCapacityOverhead private static boolean BATCHING_ENABLED; private static long BUFFER_SIZE; private static boolean STDOUT_CAPTURE_ENABLED; - // It's used by the debugger. + // The debugger reads this value via evaluation to learn how many events have been created by the agent. + // The agent owns all writes. static final AtomicLong EVENT_COUNTER = new AtomicLong(); + /** + * The debugger writes the greatest event id that was received and decoded successfully via the {@link #packBatchedData()} call. + * The confirmation is done outside the method itself because it can be called multiple times (see javadoc). + * The confirmation is not guaranteed, it is used only as an optimization against repeated sending of the same events. + *

+ * The agent checks the flushed state based on this field and {@link #LAST_FLUSHED_EVENT_ID}. + */ + static volatile long CONFIRMED_FLUSHED_EVENT_ID = -1; + // It contains raw events that are waiting to be packed. // New ones could be added concurrently. - // Raw or packed data can be flushed concurrently, leading to sending the same events multiple times. - // It's ok and is handled by the debugger using IDs. static final ConcurrentLinkedQueue EVENTS = new ConcurrentLinkedQueue<>(); static final AtomicLong EVENTS_PAYLOAD_BYTES = new AtomicLong(); + + // It contains packed batches that are waiting to be sent. + // New ones could be added concurrently. static final ConcurrentLinkedQueue PACKED_BATCHES = new ConcurrentLinkedQueue<>(); static final AtomicLong PACKED_BATCHES_BYTES = new AtomicLong(); + // Raw or packed data can be flushed concurrently, leading to sending the same events multiple times. + // It's ok and is handled by the debugger using IDs. static final AtomicLong LAST_FLUSHED_EVENT_ID = new AtomicLong(-1); static final AtomicLong LAST_PACKED_EVENT_ID = new AtomicLong(-1); static final AtomicLong LAST_LOGGING_BREAKPOINT_EVENT_ID = new AtomicLong(-1); - private interface MemoryFootprintEstimate { - int memoryFootprintEstimate(); + private abstract static class MemoryFootprintEstimate { + private final AtomicBoolean removed = new AtomicBoolean(); + + public abstract int memoryFootprintEstimate(); - boolean markRemoved(); + /** Returns true if the event was removed for the first time. */ + public boolean markRemoved() { + return removed.compareAndSet(false, true); + } } - static class Event implements MemoryFootprintEstimate { + /** + * A single event. + */ + static class Event extends MemoryFootprintEstimate { public static final byte STD_OUTPUT_TYPE = 0; public static final byte LOGGING_BREAKPOINT_TYPE = 1; @@ -65,7 +87,6 @@ static class Event implements MemoryFootprintEstimate { public final byte[] payload; public final Throwable throwable; public final CaptureStorage.CapturedStack stack; - private final AtomicBoolean removed = new AtomicBoolean(); public Event(long id, byte type, byte[] payload, Throwable throwable, CaptureStorage.CapturedStack stack) { this.id = id; @@ -81,15 +102,26 @@ public int memoryFootprintEstimate() { } @Override - public boolean markRemoved() { - return removed.compareAndSet(false, true); + public int hashCode() { + // This override is not necessary for correctness, but it is a bit faster than Object.hashCode. + return (int) (id ^ (id >>> 32)); + } + + @Override + public final boolean equals(Object o) { + if (!(o instanceof Event)) return false; + + Event event = (Event) o; + return id == event.id; } } - static class PackedBatch implements MemoryFootprintEstimate { + /** + * Multiple events, compressed and packed. Batch is prepared to be sent to the debugger. + */ + static class PackedBatch extends MemoryFootprintEstimate { public final byte[] data; public final long lastEventId; - private final AtomicBoolean removed = new AtomicBoolean(); public PackedBatch(byte[] data, long lastEventId) { this.data = data; @@ -100,11 +132,6 @@ public PackedBatch(byte[] data, long lastEventId) { public int memoryFootprintEstimate() { return data.length; } - - @Override - public boolean markRemoved() { - return removed.compareAndSet(false, true); - } } private static final FileDescriptor FD_OUT = FileDescriptor.out; @@ -120,8 +147,7 @@ public static boolean init(Properties properties, boolean logCaptureEnabled) { ENABLED = true; STDOUT_CAPTURE_ENABLED = logCaptureEnabled; BATCHING_ENABLED = Boolean.parseBoolean(properties.getProperty(BATCHING_ENABLED_PROPERTY, "true")); - // Split in 2 halves for raw events and compressed batches. - BUFFER_SIZE = getBufferSize(properties) / 2; + BUFFER_SIZE = getBufferSize(properties); if (BATCHING_ENABLED && !batchingSchedulerStarted) { batchingSchedulerStarted = true; @@ -150,16 +176,17 @@ public void run() { return true; } - static long calculateDefaultBufferSize() { - long defaultMax = 5L * 1024L * 1024L; // 5 MB - long runtimeMax = Runtime.getRuntime().maxMemory() / 100; // 1% of max heap - return Math.min(defaultMax, runtimeMax); - } - static long getBufferSize(Properties properties) { - return Long.parseLong(properties.getProperty( - BATCHING_BUFFER_SIZE_PROPERTY, - String.valueOf(DEFAULT_BUFFER_SIZE))); + String forcedBufferSize = properties.getProperty(FORCE_BATCHING_BUFFER_SIZE_PROPERTY); + if (forcedBufferSize != null) { + return Long.parseLong(forcedBufferSize); + } + String stringMaxSize = properties.getProperty(BATCHING_BUFFER_SIZE_PROPERTY); + long maxBufferSize = stringMaxSize == null + ? 5 * 1024L * 1024L // 5MB + : Long.parseLong(stringMaxSize); + long runtimeMax = Runtime.getRuntime().maxMemory() / 100; // 1% of max heap + return Math.min(maxBufferSize, runtimeMax); } private static long createNextEventId(int eventType) { @@ -234,6 +261,7 @@ private static void handleException(Throwable e) { * before it appears on the debugger side. The clearing happens in the periodic flush cycle. */ static String packBatchedData() throws IOException { + clearConfirmedBatches(); packRawEvents(); List packedBatchesSnapshot = new ArrayList<>(PACKED_BATCHES); if (packedBatchesSnapshot.isEmpty()) return null; @@ -271,24 +299,52 @@ private static void enqueuePackedBatch(List events) throws IOException { } private static void flushBatchedData(boolean forceOutput) throws IOException { - if (forceOutput || currentEventsEstimatedBytes() > BUFFER_SIZE) { + clearConfirmedBatches(); + if (forceOutput) { packRawEvents(); + } else { + long eventsBytes = currentEventsEstimatedBytes(); + long packedBytes = PACKED_BATCHES_BYTES.get(); + if (eventsBytes + packedBytes <= BUFFER_SIZE) { + return; + } + packRawEvents(); + packedBytes = PACKED_BATCHES_BYTES.get(); + // We will zip too often if there is little space for raw events. + if (packedBytes <= BUFFER_SIZE * 9 / 10) { + return; + } } - if (!forceOutput && PACKED_BATCHES_BYTES.get() <= BUFFER_SIZE) return; List packedBatchesSnapshot = new ArrayList<>(PACKED_BATCHES); if (packedBatchesSnapshot.isEmpty()) return; outputWritten(packBatches(packedBatchesSnapshot)); - long removedBytes = removeItems(PACKED_BATCHES, packedBatchesSnapshot); + markBatchesFlushed(packedBatchesSnapshot); + } + + private static void markBatchesFlushed(Collection batches) { + long removedBytes = removeItems(PACKED_BATCHES, batches); PACKED_BATCHES_BYTES.addAndGet(-removedBytes); - setIfGreater(LAST_FLUSHED_EVENT_ID, findMaxPackedEventId(packedBatchesSnapshot)); + setIfGreater(LAST_FLUSHED_EVENT_ID, findMaxPackedEventId(batches)); + } + + private static void clearConfirmedBatches() { + long confirmedId = CONFIRMED_FLUSHED_EVENT_ID; + if (confirmedId <= LAST_FLUSHED_EVENT_ID.get()) return; + Set alreadyConfirmed = new HashSet<>(); + for (PackedBatch batch : PACKED_BATCHES) { + if (batch.lastEventId <= confirmedId) { + alreadyConfirmed.add(batch); + } + } + markBatchesFlushed(alreadyConfirmed); } private static byte[] packBytes(List events) throws IOException { assert !events.isEmpty(); ByteArrayOutputStream bas = new ByteArrayOutputStream(); // no need to close it - try (GZIPOutputStream gos = new GZIPOutputStream(bas); + try (GZIPOutputStream gos = new FastGzipOutputStream(bas); DataOutputStream dos = new DataOutputStream(gos)) { CapturedStackDeduplicator.StackDictionary stackDictionary = CapturedStackDeduplicator.createStackDictionary(events, MAX_STACK_DEPTH); @@ -316,6 +372,13 @@ private static byte[] packBytes(List events) throws IOException { return bas.toByteArray(); } + private static class FastGzipOutputStream extends GZIPOutputStream { + FastGzipOutputStream(ByteArrayOutputStream out) throws IOException { + super(out); + def.setLevel(Deflater.BEST_SPEED); + } + } + private static byte[] packStack(List stackTrace) throws IOException { ByteArrayOutputStream bas = new ByteArrayOutputStream(); // no need to close it try (DataOutputStream dos = new DataOutputStream(bas)) { @@ -387,7 +450,7 @@ private static long findMaxPackedEventId(Collection packedBatches) } private static long removeItems(ConcurrentLinkedQueue queue, Collection items) { - Set itemsToRemove = new HashSet<>(items); + Set itemsToRemove = items instanceof Set ? (Set) items : new HashSet<>(items); long removedBytes = 0; for (Iterator queueIterator = queue.iterator(); queueIterator.hasNext(); ) { diff --git a/src/main/java/com/intellij/rt/debugger/agent/ThrowableInterner.java b/src/main/java/com/intellij/rt/debugger/agent/ThrowableInterner.java index 5ac9f33..3c4de4e 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/ThrowableInterner.java +++ b/src/main/java/com/intellij/rt/debugger/agent/ThrowableInterner.java @@ -61,7 +61,7 @@ static Throwable intern(Throwable throwable, Object backtrace) { // The raw VM backtrace is captured by new Throwable(), unlike StackTraceElement[] which is // created lazily and relatively expensively by getStackTrace(). - BacktraceKey key = new BacktraceKey(throwable, backtrace); + BacktraceKey key = new BacktraceKey(backtrace); Throwable interned = INTERNED_THROWABLES.putIfAbsent(key, throwable); return interned == null ? throwable : interned; } @@ -79,20 +79,12 @@ static void disable(String message) { } private static final class BacktraceKey { - private final Class myThrowableClass; private final Object myBacktrace; private final int myHashCode; - private BacktraceKey(Throwable throwable, Object backtrace) { - myThrowableClass = throwable.getClass(); + private BacktraceKey(Object backtrace) { myBacktrace = backtrace; - myHashCode = computeHashCode(myThrowableClass, backtrace); - } - - private static int computeHashCode(Class throwableClass, Object backtrace) { - int result = throwableClass.hashCode(); - result = 31 * result + backtraceHashCode(backtrace); - return result; + myHashCode = backtraceHashCode(backtrace); } @Override @@ -102,7 +94,6 @@ public boolean equals(Object obj) { BacktraceKey key = (BacktraceKey) obj; return myHashCode == key.myHashCode && - myThrowableClass == key.myThrowableClass && backtracesEqual(myBacktrace, key.myBacktrace); } diff --git a/src/main/java/com/intellij/rt/debugger/agent/ThrowableTransformer.java b/src/main/java/com/intellij/rt/debugger/agent/ThrowableTransformer.java index c651e64..41fbbaa 100644 --- a/src/main/java/com/intellij/rt/debugger/agent/ThrowableTransformer.java +++ b/src/main/java/com/intellij/rt/debugger/agent/ThrowableTransformer.java @@ -9,6 +9,15 @@ import java.lang.instrument.ClassFileTransformer; import java.security.ProtectionDomain; +/** + * Achieves two extra behaviors: + *

    + *
  • each created throwable is registered in {@link CaptureStorage#captureThrowable(Throwable)} + * to be able to access the async stack trace in {@code printStackTrace} methods via {@link CaptureStorage#getAsyncStackTrace(Throwable)};
  • + *
  • the raw VM backtrace is extracted and passed to {@link ThrowableInterner} + * through {@link CaptureStorage#captureThrowableBacktrace(Object)}.
  • + *
+ */ class ThrowableTransformer implements ClassFileTransformer { static final String THROWABLE_NAME = CaptureAgent.getInternalClsName(Throwable.class); @@ -26,12 +35,18 @@ public byte[] transform(ClassLoader loader, return transformer.accept(new ClassVisitor(Opcodes.API_VERSION, transformer.writer) { private String myBacktraceFieldName; private String myBacktraceFieldDescriptor; + private boolean myMultipleBacktraceFields; @Override public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { if (isBacktraceField(name, descriptor)) { - myBacktraceFieldName = name; - myBacktraceFieldDescriptor = descriptor; + if (myBacktraceFieldName == null) { + myBacktraceFieldName = name; + myBacktraceFieldDescriptor = descriptor; + } else { + myMultipleBacktraceFields = true; + ThrowableInterner.disable("Capture agent: cannot capture Throwable backtrace, ambiguous backtrace fields found"); + } } return super.visitField(access, name, descriptor, signature, value); } @@ -41,19 +56,21 @@ public MethodVisitor visitMethod(final int access, String name, String descripto MethodVisitor superMethodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions); switch (name) { case "": - // Insert CaptureStorage calls in the end of constructors. + // Insert extra calls at the end of constructors. return new MethodVisitor(api, superMethodVisitor) { @Override public void visitInsn(int opcode) { if (opcode == Opcodes.RETURN) { - if (myBacktraceFieldName != null) { + if (myBacktraceFieldName != null && !myMultipleBacktraceFields) { + // Extract backtrace. mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, THROWABLE_NAME, myBacktraceFieldName, myBacktraceFieldDescriptor); CaptureAgent.invokeStorageMethod(mv, "captureThrowableBacktrace"); } else { - ThrowableInterner.disable("Capture agent: cannot capture Throwable backtrace, no supported backtrace field was found"); + ThrowableInterner.disable("Capture agent: cannot capture Throwable backtrace, no supported backtrace field was found before the constructor"); } + // Perform async stack trace capture. mv.visitVarInsn(Opcodes.ALOAD, 0); CaptureAgent.invokeStorageMethod(mv, "captureThrowable"); } @@ -85,7 +102,6 @@ public void visitMethodInsn(int opcode, String owner, String name, String descri } catch (Exception e) { System.out.println("Capture agent: failed to instrument " + className); - //noinspection CallToPrintStackTrace e.printStackTrace(); } } @@ -93,7 +109,10 @@ public void visitMethodInsn(int opcode, String owner, String name, String descri } private static boolean isBacktraceField(String name, String descriptor) { - if (!"backtrace".equals(name) && !"walkback".equals(name)) return false; - return descriptor.startsWith("L") || descriptor.startsWith("["); + // HotSpot: Object backtrace + // OpenJ9: Object walkback + // Moreover, we accept any reference type just to be ready for any variations. + return ("backtrace".equals(name) || "walkback".equals(name)) && + (descriptor.startsWith("L") || descriptor.startsWith("[")); } } diff --git a/src/test/java/com/intellij/rt/debugger/agent/LogCaptureEncodingTest.java b/src/test/java/com/intellij/rt/debugger/agent/LogCaptureEncodingTest.java index 699dac5..4cd5983 100644 --- a/src/test/java/com/intellij/rt/debugger/agent/LogCaptureEncodingTest.java +++ b/src/test/java/com/intellij/rt/debugger/agent/LogCaptureEncodingTest.java @@ -221,17 +221,6 @@ public void exceededRawEventBufferThresholdPacksEvents() throws Exception { assertEquals("packed batches use the same buffer threshold and are sent immediately", 1, LogCaptureStorage.outputWrittenDumpForTests.size()); } - @Test - public void rawEventsUseHalfOfBufferSizeAsThreshold() throws Exception { - properties.put(LogCaptureStorage.BATCHING_BUFFER_SIZE_PROPERTY, String.valueOf(2 * 3000)); - LogCaptureStorage.init(properties, true); - - capture(FileDescriptor.out, "a\n"); - - assertEquals("raw event bytes are packed after exceeding half the buffer size", 0, LogCaptureStorage.EVENTS.size()); - assertEquals(0, LogCaptureStorage.EVENTS_PAYLOAD_BYTES.get()); - } - @Test public void packBatchedDataPacksPendingRawEventsBeforeReturning() throws Exception { properties.put(LogCaptureStorage.BATCHING_BUFFER_SIZE_PROPERTY, LARGE_BUFFER_SIZE); diff --git a/src/test/java/com/intellij/rt/debugger/agent/ThrowableCapacityOverhead.java b/src/test/java/com/intellij/rt/debugger/agent/ThrowableCapacityOverhead.java index 0a92767..f8b6198 100644 --- a/src/test/java/com/intellij/rt/debugger/agent/ThrowableCapacityOverhead.java +++ b/src/test/java/com/intellij/rt/debugger/agent/ThrowableCapacityOverhead.java @@ -143,7 +143,7 @@ private static void measureAfterBatchZipping(int stackDepth, int repeats) throws Properties properties = new Properties(); properties.put(LogCaptureStorage.BATCHING_ENABLED_PROPERTY, "true"); properties.put(LogCaptureStorage.BATCHING_FLUSH_PERIOD_PROPERTY, "999999999"); - properties.put(LogCaptureStorage.BATCHING_BUFFER_SIZE_PROPERTY, String.valueOf(Long.MAX_VALUE)); + properties.put(LogCaptureStorage.FORCE_BATCHING_BUFFER_SIZE_PROPERTY, String.valueOf(Long.MAX_VALUE)); LogCaptureStorage.init(properties, true); recursiveCapture(stackDepth, repeats, "stdout message\n".getBytes(StandardCharsets.UTF_8));