Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions CodenameOne/src/com/codename1/io/ConnectionRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1544,10 +1544,16 @@ boolean performOperationComplete() throws IOException {
// copies them before it calls runCurrentRequest -- so a traceparent the
// app supplies as a default is seen here and kept, not replaced.
try {
tracerAttempt = tracer.beforeRequest(this,
tracer == tracerParentOwner ? tracerParent : null); //NOPMD CompareObjectsWithEquals
tracerOwner = tracerAttempt == null ? null : tracer;
tracerThread = Thread.currentThread();
Object parent;
synchronized (this) {
parent = tracer == tracerParentOwner ? tracerParent : null; //NOPMD CompareObjectsWithEquals
}
Object attempt = tracer.beforeRequest(this, parent);
synchronized (this) {
tracerAttempt = attempt;
tracerOwner = attempt == null ? null : tracer;
tracerThread = Thread.currentThread();
}
} catch (Throwable t) {
Log.e(t);
}
Expand Down
143 changes: 82 additions & 61 deletions CodenameOne/src/com/codename1/io/NetworkManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -1210,18 +1210,23 @@ public void run() {
/// attempt by the time this one reaches its finally, and that attempt is
/// not this thread's to end.
static void endTracerAttempt(ConnectionRequest req, Throwable failure) {
Object attempt = req.tracerAttempt;
NetworkTracer owner = req.tracerOwner;
if (attempt == null || owner == null
|| req.tracerThread != Thread.currentThread()) { //NOPMD CompareObjectsWithEquals
return;
Object attempt;
NetworkTracer owner;
synchronized (req) {
attempt = req.tracerAttempt;
owner = req.tracerOwner;
if (attempt == null || owner == null
|| req.tracerThread != Thread.currentThread()) { //NOPMD CompareObjectsWithEquals
return;
}
// Publish the ended attempt atomically with clearing the active one.
// An EDT retry must never observe a gap between the two states.
req.tracerLastAttempt = attempt;
req.tracerLastOwner = owner;
req.tracerAttempt = null;
req.tracerOwner = null;
req.tracerThread = null;
}
req.tracerAttempt = null;
req.tracerOwner = null;
req.tracerThread = null;
// Kept for a retry of a request queued with no parent: see addToQueue.
req.tracerLastAttempt = attempt;
req.tracerLastOwner = owner;
try {
// Only a status THIS attempt received: a reused request still holds
// the last one's.
Expand All @@ -1237,26 +1242,34 @@ static void endTracerAttempt(ConnectionRequest req, Throwable failure) {
/// queued there, unless the request was queued again in the meantime.
private static void scheduleTracerClear(final ConnectionRequest req, final int requeues) {
if (!Display.isInitialized()) {
clearTracerState(req);
synchronized (req) {
if (req.tracerRequeues == requeues) {
clearTracerState(req);
}
}
return;
}
Display.getInstance().callSerially(new Runnable() {
@Override
public void run() {
if (req.tracerRequeues == requeues) {
clearTracerState(req);
synchronized (req) {
if (req.tracerRequeues == requeues) {
clearTracerState(req);
}
}
}
});
}

/// Forgets every tracer object a finished request holds.
static void clearTracerState(ConnectionRequest req) {
req.tracerParent = null;
req.tracerParentOwner = null;
req.tracerParentChained = false;
req.tracerLastAttempt = null;
req.tracerLastOwner = null;
synchronized (req) {
req.tracerParent = null;
req.tracerParentOwner = null;
req.tracerParentChained = false;
req.tracerLastAttempt = null;
req.tracerLastOwner = null;
}
}

/// Adds the given network connection to the queue of execution
Expand All @@ -1282,33 +1295,35 @@ private void addToQueue(@Async.Schedule ConnectionRequest request, boolean retry
// here, on the thread that ran it, before the request is visible to
// anyone else.
endTracerAttempt(request, null);
request.tracerRequeues++;
// A request queued with no context -- the usual case for a generated
// client used outside Telemetry.run -- would start a NEW trace on every
// attempt: a 302 and the 200 it led to, or a failure and the retry that
// succeeded, came out as unrelated traces with separate sampling
// decisions, and the logical request could not be followed. So the
// attempt that just ended becomes the next one's parent: one trace,
// one decision, each attempt still its own span. A request that WAS
// queued inside an action keeps that action as every attempt's parent.
// A parent some OTHER tracer captured is as good as none: the tracer
// that ran this attempt will not use it (it only takes its own), and
// keeping it blocked the chain, so every retry started a new root.
// The attempt to continue from is the last one that ENDED -- or, when a
// listener retries from the EDT before the network thread has finished
// the attempt it is reacting to, that attempt, still in flight. Waiting
// for "ended" alone lost the race on a fast EDT, and the retry started
// an unrelated trace.
Object previous = request.tracerAttempt != null
? request.tracerAttempt : request.tracerLastAttempt;
NetworkTracer previousOwner = request.tracerAttempt != null
? request.tracerOwner : request.tracerLastOwner;
if ((request.tracerParent == null || request.tracerParentChained
|| request.tracerParentOwner != previousOwner) //NOPMD CompareObjectsWithEquals
&& previous != null) {
request.tracerParent = previous;
request.tracerParentOwner = previousOwner;
request.tracerParentChained = true;
synchronized (request) {
request.tracerRequeues++;
// A request queued with no context -- the usual case for a generated
// client used outside Telemetry.run -- would start a NEW trace on every
// attempt: a 302 and the 200 it led to, or a failure and the retry that
// succeeded, came out as unrelated traces with separate sampling
// decisions, and the logical request could not be followed. So the
// attempt that just ended becomes the next one's parent: one trace,
// one decision, each attempt still its own span. A request that WAS
// queued inside an action keeps that action as every attempt's parent.
// A parent some OTHER tracer captured is as good as none: the tracer
// that ran this attempt will not use it (it only takes its own), and
// keeping it blocked the chain, so every retry started a new root.
// The attempt to continue from is the last one that ENDED -- or, when a
// listener retries from the EDT before the network thread has finished
// the attempt it is reacting to, that attempt, still in flight. Waiting
// for "ended" alone lost the race on a fast EDT, and the retry started
// an unrelated trace.
Object previous = request.tracerAttempt != null
? request.tracerAttempt : request.tracerLastAttempt;
NetworkTracer previousOwner = request.tracerAttempt != null
? request.tracerOwner : request.tracerLastOwner;
if ((request.tracerParent == null || request.tracerParentChained
|| request.tracerParentOwner != previousOwner) //NOPMD CompareObjectsWithEquals
&& previous != null) {
request.tracerParent = previous;
request.tracerParentOwner = previousOwner;
request.tracerParentChained = true;
}
}
}
// Captured HERE, on the thread that asked for the request, so the span it
Expand Down Expand Up @@ -1368,17 +1383,19 @@ private void addToQueue(@Async.Schedule ConnectionRequest request, boolean retry
return;
}
}
request.tracerParent = queuedParent;
request.tracerParentOwner = queuedBy;
// A fresh enqueue is a new logical request, not a retry of the last.
// It advances the generation too: a cleanup the previous run queued
// on the EDT would otherwise still match, and clear the parent this
// enqueue just captured -- a listener can reuse a finished request
// with addToQueue before that cleanup runs.
request.tracerRequeues++;
request.tracerParentChained = false;
request.tracerLastAttempt = null;
request.tracerLastOwner = null;
synchronized (request) {
request.tracerParent = queuedParent;
request.tracerParentOwner = queuedBy;
// A fresh enqueue is a new logical request, not a retry of the last.
// It advances the generation too: a cleanup the previous run queued
// on the EDT would otherwise still match, and clear the parent this
// enqueue just captured -- a listener can reuse a finished request
// with addToQueue before that cleanup runs.
request.tracerRequeues++;
request.tracerParentChained = false;
request.tracerLastAttempt = null;
request.tracerLastOwner = null;
}
// And nothing of the last run's dealings with its authorizer: a request the
// application queues again gets its one renewal again. A retry mark the last
// run left unread goes too -- with nobody waiting on that run it was never
Expand Down Expand Up @@ -1917,9 +1934,13 @@ private boolean runCurrentRequest(@Async.Execute ConnectionRequest req) {
// Any tracer field, the owners included: a request queued outside an
// action holds only tracerParentOwner, and that alone pins the whole
// telemetry installation.
if (req.tracerRequeues == requeuesBefore && !req.authorizationPending
&& (req.tracerParent != null || req.tracerLastAttempt != null
|| req.tracerParentOwner != null || req.tracerLastOwner != null)) {
boolean clearTracer;
synchronized (req) {
clearTracer = req.tracerRequeues == requeuesBefore && !req.authorizationPending
&& (req.tracerParent != null || req.tracerLastAttempt != null
|| req.tracerParentOwner != null || req.tracerLastOwner != null);
}
if (clearTracer) {
// Nothing queued this request again YET. Its tracer state has
// to go once it is done -- the parent and the last attempt are
// the tracer's own objects, a span and through it the whole
Expand All @@ -1929,7 +1950,7 @@ private boolean runCurrentRequest(@Async.Execute ConnectionRequest req) {
// call retry(), which needs the last attempt to continue its
// trace. So the clear is queued on the EDT behind those
// listener callbacks, and skipped if one of them retried.
scheduleTracerClear(req, req.tracerRequeues);
scheduleTracerClear(req, requeuesBefore);
}
NetworkGuard guard = getNetworkGuard();
if (guard != null && req.hasGuardResponse()) {
Expand Down
42 changes: 28 additions & 14 deletions CodenameOne/src/com/codename1/io/gzip/Deflate.java
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,8 @@ void scanTree(short[] tree, // the tree to be scanned
if (++count < maxCount && curlen == nextlen) { //NOPMD AssignmentInOperand
continue;
} else if (count < minCount) {
blTree[curlen * 2] += count;
// At most HEAP_SIZE code lengths are counted, well below Short.MAX_VALUE.
blTree[curlen * 2] = (short) (blTree[curlen * 2] + count);
} else if (curlen != 0) {
if (curlen != prevlen) {
blTree[curlen * 2]++;
Expand Down Expand Up @@ -632,7 +633,7 @@ boolean trTally(int dist, // distance of matched string

if ((lastLit & 0x1fff) == 0 && level > 2) {
// Compute an upper bound for the compressed length
int outLength = lastLit * 8;
long outLength = (long) lastLit * 8;
int inLength = strStart - blockStart;
int dcode;
for (dcode = 0; dcode < D_CODES; dcode++) {
Expand Down Expand Up @@ -1489,25 +1490,38 @@ int deflateParams(int levelParam, int strategyParam) {
}

int deflateSetDictionary(byte[] dictionary, int dictLength) {
int length = dictLength;
int index = 0;

if (dictionary == null || status != INIT_STATE) {
// Raw DEFLATE begins in BUSY_STATE because it has no zlib header.
// A preset dictionary is still valid before any input is compressed.
if (dictionary == null || (status != INIT_STATE &&
!(wrap == 0 && status == BUSY_STATE && strm.totalIn == 0))) {
return Z_STREAM_ERROR;
}

strm.adler.update(dictionary, 0, dictLength);
if (wrap != 0) {
strm.adler.update(dictionary, 0, dictLength);
}

// Repeated calls append to the history, while the Adler checksum
// above covers every supplied byte. Keep only the usable window tail.
int capacity = wSize - MIN_LOOKAHEAD;
int copied = Math.min(dictLength, capacity);
int retained = Math.min(strStart, capacity - copied);
System.arraycopy(window, strStart - retained, window, 0, retained);
System.arraycopy(dictionary, dictLength - copied, window, retained, copied);
int length = retained + copied;
strStart = length;
blockStart = length;
// The window has moved, so no hash chain may retain its old offsets.
for (int n = 0; n < head.length; n++) {
head[n] = 0;
}
for (int n = 0; n < prev.length; n++) {
prev[n] = 0;
}
if (length < MIN_MATCH) {
insH = 0;
return Z_OK;
}
if (length > wSize - MIN_LOOKAHEAD) {
length = wSize - MIN_LOOKAHEAD;
index = dictLength - length; // use the tail of the dictionary
}
System.arraycopy(dictionary, index, window, 0, length);
strStart = length;
blockStart = length;

// Insert all strings in the hash table (except for the last two bytes).
// s->lookahead stays null, so s->ins_h will be recomputed at the next
Expand Down
6 changes: 3 additions & 3 deletions CodenameOne/src/com/codename1/io/gzip/Inflate.java
Original file line number Diff line number Diff line change
Expand Up @@ -602,9 +602,9 @@ int inflateSetDictionary(byte[] dictionary, int dictLength) {

if (this.mode == DICT0) {
long adlerNeed = z.adler.getValue();
z.adler.reset();
z.adler.update(dictionary, 0, dictLength);
if (z.adler.getValue() != adlerNeed) {
Adler32 candidate = new Adler32();
candidate.update(dictionary, 0, dictLength);
if (candidate.getValue() != adlerNeed) {
return Z_DATA_ERROR;
}
}
Expand Down
7 changes: 5 additions & 2 deletions CodenameOne/src/com/codename1/io/gzip/Tree.java
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ void genBitLen(Deflate s) {
bits--;
}
s.blCount[bits]--; // move one leaf down the tree
s.blCount[bits + 1] += 2; // move one overflow item as its brother
// Counts are bounded by the number of tree leaves (at most L_CODES).
s.blCount[bits + 1] = (short) (s.blCount[bits + 1] + 2); // move its brother
s.blCount[maxLength]--;
// The brother of the overflow item also moves one step up,
// but this does not affect bl_count[maxLength]
Expand All @@ -275,7 +276,9 @@ void genBitLen(Deflate s) {
continue;
}
if (tree[m * 2 + 1] != bits) {
s.optLen += ((long) bits - (long) tree[m * 2 + 1]) * (long) tree[m * 2];
// Code lengths are at most 15 and frequencies at most 32767;
// this block cost correction fits in an int.
s.optLen += (bits - tree[m * 2 + 1]) * tree[m * 2];
tree[m * 2 + 1] = (short) bits;
}
n--;
Expand Down
Loading
Loading