Skip to content

Commit cde39ae

Browse files
Merge branch 'bugfixtm' of https://github.com/cap-java/sdm into bugfixtm
2 parents adf3e3d + 11ce6bc commit cde39ae

2 files changed

Lines changed: 62 additions & 48 deletions

File tree

sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import static com.sap.cds.sdm.constants.SDMConstants.TECHNICAL_USER_FLOW;
55

66
import com.sap.cds.feature.attachments.service.model.servicehandler.AttachmentCreateEventContext;
7-
import com.sap.cds.reflect.CdsEntity;
8-
import com.sap.cds.reflect.CdsModel;
97
import com.sap.cds.sdm.constants.SDMConstants;
108
import com.sap.cds.sdm.constants.SDMErrorMessages;
119
import com.sap.cds.sdm.handler.TokenHandler;
@@ -67,9 +65,6 @@ public JSONObject createDocument(
6765
}
6866
long totalSize = cmisDocument.getContentLength();
6967
int chunkSize = SDMConstants.CHUNK_SIZE;
70-
CdsModel model = eventContext.getModel();
71-
Optional<CdsEntity> attachmentDraftEntity =
72-
model.findEntity(eventContext.getAttachmentEntity() + "_drafts");
7368
cmisDocument.setUploadStatus(SDMConstants.UPLOAD_STATUS_IN_PROGRESS);
7469
if (totalSize <= 400 * 1024 * 1024) {
7570

@@ -278,15 +273,27 @@ private JSONObject uploadLargeFileInChunks(
278273

279274
// Step 7: Append Chunk. Call cmis api to append content stream
280275
if (bytesRead > 0) {
281-
responseBody =
282-
appendContentStream(
283-
cmisDocument,
284-
sdmUrl,
285-
chunkBuffer,
286-
bytesRead,
287-
isLastChunk,
288-
chunkIndex,
289-
isSystemUser);
276+
// Only capture response from the last chunk to avoid unnecessary object allocation
277+
if (isLastChunk) {
278+
responseBody =
279+
appendContentStream(
280+
cmisDocument,
281+
sdmUrl,
282+
chunkBuffer,
283+
bytesRead,
284+
isLastChunk,
285+
chunkIndex,
286+
isSystemUser);
287+
} else {
288+
appendContentStream(
289+
cmisDocument,
290+
sdmUrl,
291+
chunkBuffer,
292+
bytesRead,
293+
isLastChunk,
294+
chunkIndex,
295+
isSystemUser);
296+
}
290297
}
291298

292299
long endChunkUploadTime = System.currentTimeMillis();

sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
import com.sap.cds.sdm.constants.SDMConstants;
44
import com.sap.cds.sdm.service.exceptions.InsufficientDataException;
5-
import io.reactivex.Flowable;
65
import java.io.*;
7-
import java.util.List;
86
import java.util.concurrent.*;
97
import java.util.concurrent.atomic.AtomicBoolean;
108
import java.util.concurrent.atomic.AtomicLong;
@@ -25,7 +23,8 @@ public class ReadAheadInputStream extends InputStream {
2523
private final ExecutorService executor =
2624
Executors.newFixedThreadPool(2); // Thread pool to Read next chunk
2725
private final BlockingQueue<byte[]> chunkQueue =
28-
new LinkedBlockingQueue<>(50); // Next chunk is read to a queue
26+
new LinkedBlockingQueue<>(
27+
4); // Reduced from 50 to 4 (80MB) - balances read-ahead performance with heap constraints
2928

3029
public ReadAheadInputStream(InputStream inputStream, long totalSize) throws IOException {
3130
if (inputStream == null) {
@@ -91,42 +90,50 @@ private void preloadChunks() {
9190

9291
private void readChunk(AtomicReference<byte[]> bufferRef, AtomicLong bytesReadAtomic)
9392
throws IOException {
93+
int maxRetries = 5;
94+
int retryCount = 0;
95+
9496
while (bytesReadAtomic.get() < CHUNK_SIZE) {
9597
try {
96-
List<Integer> results =
97-
Flowable.fromCallable(
98-
() -> {
99-
byte[] buffer = bufferRef.get();
100-
// Read from stream and update bytesReadAtomic
101-
int result =
102-
originalStream.read(
103-
buffer,
104-
(int) bytesReadAtomic.get(),
105-
CHUNK_SIZE - (int) bytesReadAtomic.get());
106-
if (result > 0) {
107-
bytesReadAtomic.addAndGet(result);
108-
} else if (result == 0) {
109-
throw new InsufficientDataException("Read returned 0 bytes");
110-
}
111-
return result;
112-
})
113-
.retryWhen(RetryUtils.retryLogic(5)) // Apply retry logic with 5 attempts
114-
.toList()
115-
.blockingGet();
116-
117-
if (results == null || results.isEmpty())
118-
throw new IOException("Failed to read chunk: results is null or empty");
119-
// Check if the read was successful
120-
121-
int readAttempt = results.get(0);
122-
123-
if (readAttempt == -1) {
98+
byte[] buffer = bufferRef.get();
99+
int result =
100+
originalStream.read(
101+
buffer, (int) bytesReadAtomic.get(), CHUNK_SIZE - (int) bytesReadAtomic.get());
102+
103+
if (result > 0) {
104+
bytesReadAtomic.addAndGet(result);
105+
retryCount = 0; // Reset retry count on successful read
106+
} else if (result == -1) {
124107
logger.info("EOF reached while reading the stream.");
125108
break;
109+
} else if (result == 0) {
110+
// Treat 0 bytes read as InsufficientDataException (matches original behavior)
111+
throw new InsufficientDataException("Read returned 0 bytes");
112+
}
113+
} catch (EOFException | InsufficientDataException e) {
114+
// These exceptions should be retried (matching RetryUtils.shouldRetry())
115+
retryCount++;
116+
if (retryCount >= maxRetries) {
117+
logger.error("Failed to read chunk after {} retries: {}", maxRetries, e.getMessage(), e);
118+
throw new IOException("Failed to read chunk after retries", e);
119+
}
120+
long delaySeconds =
121+
(long) Math.pow(2, retryCount); // Exponential backoff: 2, 4, 8, 16, 32 seconds
122+
logger.info(
123+
"Retry attempt {} failed. Retrying in {} seconds. Error: {}",
124+
retryCount,
125+
delaySeconds,
126+
e.getMessage());
127+
try {
128+
Thread.sleep(delaySeconds * 1000); // Convert to milliseconds
129+
} catch (InterruptedException ie) {
130+
Thread.currentThread().interrupt();
131+
throw new IOException("Interrupted during retry backoff", ie);
126132
}
127-
} catch (Exception e) {
128-
logger.error("Failed to read chunk after retries: {}", e.getMessage(), e);
129-
throw new IOException("Failed to read chunk", e);
133+
} catch (IOException e) {
134+
// Other IOExceptions should fail immediately (not retried in original)
135+
logger.error("Non-retryable IOException: {}", e.getMessage(), e);
136+
throw e;
130137
}
131138
}
132139
}

0 commit comments

Comments
 (0)