/** * In case an error print out the trail file context. Because of the XML reader buffering, we can * only get the block (8K). It has to be visually inspected */ protected void printErrorContext(PrintStream errOut) throws IOException { final File file = _inputStream.getCurrentFile(); final long position = _inputStream.getCurrentPosition(); File lastFile = new File(file.getParentFile(), getLastFileName()); errOut.println( "error between " + lastFile + " @ " + getLastPosition() + " and " + _inputStream.getCurrentFile() + " @ " + _inputStream.getCurrentPosition()); RandomAccessFile f = new RandomAccessFile(file, "r"); try { long startPos = lastFile.equals(file) ? getLastPosition() : 0; long endPos = position + ERROR_CONTEXT_LEN; int contextSize = (int) (endPos - startPos); byte[] context = new byte[contextSize]; f.seek(startPos); if (f.read(context, 0, contextSize) > 0) { errOut.println("context: " + new String(context, "ISO-8859-1")); } else { errOut.println("unable to read XML error context"); } } finally { f.close(); } }
/** @see java.lang.Runnable#run() */ @Override public void run() { long lastReportTs = 0; long lastReportedPosition = _lastPosition; long savePos = _lastPosition; try { while (!_shutdownRequested.get() && _xmlStreamReader.hasNext()) { int eventType = _xmlStreamReader.next(); switch (eventType) { case XMLStreamConstants.START_ELEMENT: processStartElement(); break; case XMLStreamConstants.END_ELEMENT: processEndElement(); break; // case XMLStreamConstants.ATTRIBUTE: processAttribute(); break; default: break; // do nothing -- just log progress } File curFile = _inputStream.getCurrentFile(); if (null != curFile && !_inputStream.isClosed()) { String curFileName = curFile.getName(); long currentTs = System.currentTimeMillis(); long curPos = _inputStream.getCurrentPosition(); if (curPos != savePos) { // the XML reader seems to do internal buffering which makes it harder to // guess the position where a problem happened. // At any point the parser is processing between the bytes [_lastPosition, curPos). _lastPosition = savePos; savePos = curPos; } if (!curFileName.equals(_lastFileName) || (curPos - lastReportedPosition) >= POSITION_REPORT_GAP || (currentTs - lastReportTs) >= POSITION_REPORT_TIME_MS) { lastReportedPosition = curPos; lastReportTs = currentTs; _log.info("file: " + curFileName + "; pos: " + curPos); logTablesSeen(); } _lastFileName = curFileName; } } } catch (XMLStreamException e) { _log.error("xml stream error: " + e, e); _lastError = e; } catch (RuntimeException e) { _log.error("runtime error: " + e, e); _lastError = e; } }
@Override public void run() { ConcurrentAppendableCompositeFileInputStream compositeInputStream = null; try { if (_xmlCallback == null) _xmlCallback = new HandleXmlCallback(); String xmlDir = GGEventGenerationFactory.uriToGGDir(_pConfig.getUri()); String xmlPrefix = GGEventGenerationFactory.uriToXmlPrefix(_pConfig.getUri()); File file = new File(xmlDir); if (!file.exists() || !file.isDirectory()) { _log.fatal( "Unable to load the directory: " + xmlDir + " it doesn't seem to be a valid directory"); throw new DatabusException("Invalid trail file directory"); } boolean parseError = false; do { try { _log.info( "Using xml directory : " + xmlDir + " and using the xml Prefix : " + xmlPrefix); compositeInputStream = locateScnInTrailFile(xmlDir, xmlPrefix); compositeInputStream.setGGParserStats(_ggParserStats); _log.info("Attempting to start the parser..."); // Not a retry, first time the producer is started, in which case, start the eventBuffer // with the appropriate scn if (!parseError) { _log.info("Starting dbusEventBuffer with _scn : " + _startPrevScn.get()); getEventBuffer().start(_startPrevScn.get()); } else { _log.warn( "Umm, looks like the parser had failed, this is an retry attempt using _scn: " + _scn.get()); _log.info("CompositeInputStream used:" + compositeInputStream); } StaxBuilder builder = new StaxBuilder( _schemaRegistryService, wrapStreamWithXmlTags(compositeInputStream), _pConfig, _xmlCallback); if (_log.isDebugEnabled()) _log.debug("CompositeInputStream used:" + compositeInputStream); _parser = builder.getParser(); builder .processXml(); // --> The call doesn't return after this (it starts processing the // xml trail files), unless a shutdown is requested or an exception // is thrown. parseError = false; // --> If this code path is executed, then the shutdown has been requested } catch (XMLStreamException e) { _ggParserStats.addParsingError(); // If the parser was in the middle of execution and an shutdown was issued, then an // xmlstream exception is expected. if (_shutdownRequested) { parseError = false; } else { _log.error("Error while parsing the xml, will retry loading the parser", e); _log.info("Last scn seen before the crash: " + _scn.get()); _log.info("CompositeInputStream used:" + compositeInputStream); parseError = true; } } finally { if (compositeInputStream != null) compositeInputStream.close(); } } while (parseError); // TODO && retry count (add config to control number of retires) } catch (RuntimeException e) { _log.info("CompositeInputStream used:" + compositeInputStream); _log.error("Error while parsing data, compositeInputStream shutting down the relay", e); _currentState = GoldenGateEventProducer.State.SHUTDOWN; throw e; } catch (Exception e) { _log.info("CompositeInputStream used:" + compositeInputStream); _log.error("Error while parsing data, compositeInputStream shutting down the relay", e); _currentState = GoldenGateEventProducer.State.SHUTDOWN; return; } }