@@ -86,6 +86,7 @@ public class PipesServer implements AutoCloseable {
8686 private static final Logger LOG = LoggerFactory .getLogger (PipesServer .class );
8787
8888 private final long heartbeatIntervalMs ;
89+ private final String pipesClientId ;
8990
9091 //this has to be some number not close to 0-3
9192 //it looks like the server crashes with exit value 3 on uncaught OOM, for example
@@ -151,6 +152,8 @@ public byte getByte() {
151152 private final PipesWorker .EMIT_STRATEGY emitStrategy ;
152153
153154 public static PipesServer load (int port , Path tikaConfigPath ) throws Exception {
155+ String pipesClientId = System .getProperty ("pipesClientId" , "unknown" );
156+ LOG .debug ("pipesClientId={}: connecting to client on port={}" , pipesClientId , port );
154157 Socket socket = new Socket ();
155158 socket .connect (new InetSocketAddress (InetAddress .getLoopbackAddress (), port ), PipesClient .SOCKET_CONNECT_TIMEOUT_MS );
156159
@@ -165,8 +168,9 @@ public static PipesServer load(int port, Path tikaConfigPath) throws Exception {
165168 socket .setSoTimeout ((int ) pipesConfig .getSocketTimeoutMs ());
166169
167170 MetadataFilter metadataFilter = tikaLoader .loadMetadataFilters ();
168- PipesServer pipesServer = new PipesServer (tikaLoader , pipesConfig , socket , dis , dos , metadataFilter );
171+ PipesServer pipesServer = new PipesServer (pipesClientId , tikaLoader , pipesConfig , socket , dis , dos , metadataFilter );
169172 pipesServer .initializeResources ();
173+ LOG .debug ("pipesClientId={}: PipesServer loaded and ready" , pipesClientId );
170174 return pipesServer ;
171175 } catch (Exception e ) {
172176 LOG .error ("Failed to start up" , e );
@@ -196,10 +200,11 @@ public static PipesServer load(int port, Path tikaConfigPath) throws Exception {
196200 }
197201 }
198202
199- public PipesServer (TikaLoader tikaLoader , PipesConfig pipesConfig , Socket socket , DataInputStream in ,
203+ public PipesServer (String pipesClientId , TikaLoader tikaLoader , PipesConfig pipesConfig , Socket socket , DataInputStream in ,
200204 DataOutputStream out , MetadataFilter metadataFilter ) throws TikaConfigException ,
201205 IOException {
202206
207+ this .pipesClientId = pipesClientId ;
203208 this .tikaLoader = tikaLoader ;
204209 this .pipesConfig = pipesConfig ;
205210 this .socket = socket ;
@@ -234,32 +239,51 @@ public PipesServer(TikaLoader tikaLoader, PipesConfig pipesConfig, Socket socket
234239 public static void main (String [] args ) throws Exception {
235240 int port = Integer .parseInt (args [0 ]);
236241 Path tikaConfig = Paths .get (args [1 ]);
237- LOG .debug ("starting pipes server on port={} with tikaConfig={}" , port , tikaConfig );
242+ String pipesClientId = System .getProperty ("pipesClientId" , "unknown" );
243+ LOG .debug ("pipesClientId={}: starting pipes server on port={}" , pipesClientId , port );
238244 try (PipesServer server = PipesServer .load (port , tikaConfig )) {
239- LOG .debug ("successfully started pipes server" );
240245 server .mainLoop ();
241246 } catch (Throwable t ) {
242- LOG .error ("crashed" , t );
247+ LOG .error ("pipesClientId={}: crashed" , pipesClientId , t );
243248 throw t ;
244249 } finally {
245- LOG .info ("server shutting down" );
250+ LOG .info ("pipesClientId={}: server shutting down" , pipesClientId );
246251 }
247252 }
248253
249254 public void mainLoop () {
250255 write (PROCESSING_STATUS .READY .getByte ());
256+ LOG .debug ("pipesClientId={}: sent READY, entering main loop" , pipesClientId );
251257 ArrayBlockingQueue <Metadata > intermediateResult = new ArrayBlockingQueue <>(1 );
252258
253- LOG .trace ("processing requests" );
254259 //main loop
255260 try {
256261 long start = System .currentTimeMillis ();
257262 while (true ) {
258263 int request = input .read ();
264+ LOG .trace ("pipesClientId={}: received command byte={}" , pipesClientId , HexFormat .of ().formatHex (new byte []{(byte )request }));
259265 if (request == -1 ) {
260266 LOG .warn ("received -1 from client; shutting down" );
261267 exit (0 );
262- } else if (request == PipesClient .COMMANDS .PING .getByte ()) {
268+ }
269+
270+ // Validate that we received a command byte, not a status/ACK byte
271+ if (request == PipesClient .COMMANDS .ACK .getByte ()) {
272+ String msg = String .format (Locale .ROOT ,
273+ "pipesClientId=%s: PROTOCOL ERROR - Received ACK (byte=0x%02x) when expecting a command. " +
274+ "This indicates a protocol synchronization issue where the server missed consuming an ACK. " +
275+ "Valid commands are: PING(0x%02x), NEW_REQUEST(0x%02x), SHUT_DOWN(0x%02x). " +
276+ "This is likely a bug in the server's message handling - check that all status messages " +
277+ "that trigger client ACKs are properly awaiting those ACKs." ,
278+ pipesClientId , (byte )request ,
279+ PipesClient .COMMANDS .PING .getByte (),
280+ PipesClient .COMMANDS .NEW_REQUEST .getByte (),
281+ PipesClient .COMMANDS .SHUT_DOWN .getByte ());
282+ LOG .error (msg );
283+ throw new IllegalStateException (msg );
284+ }
285+
286+ if (request == PipesClient .COMMANDS .PING .getByte ()) {
263287 writeNoAck (PipesClient .COMMANDS .PING .getByte ());
264288 } else if (request == PipesClient .COMMANDS .NEW_REQUEST .getByte ()) {
265289 intermediateResult .clear ();
@@ -284,8 +308,16 @@ public void mainLoop() {
284308 }
285309 System .exit (0 );
286310 } else {
287- LOG .error ("Unexpected request byte={}" , HexFormat .of ().formatHex (new byte []{(byte )request }));
288- throw new IllegalStateException ("Unexpected request" );
311+ String msg = String .format (Locale .ROOT ,
312+ "pipesClientId=%s: Unexpected byte 0x%02x in command position. " +
313+ "Expected one of: PING(0x%02x), ACK(0x%02x), NEW_REQUEST(0x%02x), SHUT_DOWN(0x%02x)" ,
314+ pipesClientId , (byte )request ,
315+ PipesClient .COMMANDS .PING .getByte (),
316+ PipesClient .COMMANDS .ACK .getByte (),
317+ PipesClient .COMMANDS .NEW_REQUEST .getByte (),
318+ PipesClient .COMMANDS .SHUT_DOWN .getByte ());
319+ LOG .error (msg );
320+ throw new IllegalStateException (msg );
289321 }
290322 output .flush ();
291323 }
@@ -346,7 +378,7 @@ private void loopUntilDone(FetchEmitTuple fetchEmitTuple, ExecutorCompletionServ
346378 long elapsed = System .currentTimeMillis () - start .toEpochMilli ();
347379 if (elapsed > mockProgressCounter * heartbeatIntervalMs ) {
348380 LOG .debug ("still processing: {}" , mockProgressCounter );
349- output . write (PROCESSING_STATUS .WORKING .getByte ());
381+ write (PROCESSING_STATUS .WORKING .getByte ());
350382 output .writeLong (mockProgressCounter ++);
351383 output .flush ();
352384 }
@@ -484,6 +516,7 @@ private void awaitAck() throws IOException {
484516 if (b == ACK .getByte ()) {
485517 return ;
486518 }
519+ LOG .error ("pipesClientId={}: expected ACK but got byte={}" , pipesClientId , HexFormat .of ().formatHex (new byte []{ (byte ) b }));
487520 throw new IOException ("Wasn't expecting byte=" + HexFormat .of ().formatHex (new byte []{ (byte ) b }));
488521 }
489522
@@ -503,7 +536,7 @@ private void write(byte b) {
503536 output .flush ();
504537 awaitAck ();
505538 } catch (IOException e ) {
506- LOG .error ("problem writing data (forking process shutdown?)" , e );
539+ LOG .error ("pipesClientId={}: problem writing data (forking process shutdown?)" , pipesClientId , e );
507540 exit (1 );
508541 }
509542 }
0 commit comments