com.google.code.or.binlog.impl.AbstractBinlogParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of open-replicator Show documentation
Show all versions of open-replicator Show documentation
Open Replicator is a high performance MySQL binlog parser written in Java.
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.code.or.binlog.impl;
import java.io.EOFException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.code.or.binlog.BinlogEventFilter;
import com.google.code.or.binlog.BinlogEventListener;
import com.google.code.or.binlog.BinlogEventParser;
import com.google.code.or.binlog.BinlogEventV4;
import com.google.code.or.binlog.BinlogParser;
import com.google.code.or.binlog.BinlogParserContext;
import com.google.code.or.binlog.BinlogParserListener;
import com.google.code.or.binlog.impl.event.RotateEvent;
import com.google.code.or.binlog.impl.event.TableMapEvent;
import com.google.code.or.binlog.impl.parser.NopEventParser;
import com.google.code.or.common.util.XThreadFactory;
/**
*
* @author Jingqi Xu
*/
public abstract class AbstractBinlogParser implements BinlogParser {
//
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractBinlogParser.class);
//
protected Thread worker;
protected ThreadFactory threadFactory;
protected BinlogEventFilter eventFilter;
protected BinlogEventListener eventListener;
protected boolean clearTableMapEventsOnRotate = true;
protected final List parserListeners;
protected final AtomicBoolean verbose = new AtomicBoolean(false);
protected final AtomicBoolean running = new AtomicBoolean(false);
protected final BinlogEventParser defaultParser = new NopEventParser();
protected final BinlogEventParser[] parsers = new BinlogEventParser[128];
protected String binlogFileName;
//
protected abstract void doParse() throws Exception;
protected abstract void doStart() throws Exception;
protected abstract void doStop(long timeout, TimeUnit unit) throws Exception;
/**
*
*/
public AbstractBinlogParser() {
this.threadFactory = new XThreadFactory("binlog-parser", false);
this.parserListeners = new CopyOnWriteArrayList();
}
/**
*
*/
public boolean isRunning() {
return this.running.get();
}
public void start() throws Exception {
//
if(!this.running.compareAndSet(false, true)) {
return;
}
//
doStart();
//
this.worker = this.threadFactory.newThread(new Task());
this.worker.start();
//
notifyOnStart();
}
public void stop(long timeout, TimeUnit unit) throws Exception {
//
if(!this.running.compareAndSet(true, false)) {
return;
}
//
try {
//
final long now = System.nanoTime();
doStop(timeout, unit);
timeout -= unit.convert(System.nanoTime() - now, TimeUnit.NANOSECONDS);
//
if(timeout > 0) {
unit.timedJoin(this.worker, timeout);
this.worker = null;
}
} finally {
notifyOnStop();
}
}
/**
*
*/
public boolean isVerbose() {
return this.verbose.get();
}
public void setVerbose(boolean verbose) {
this.verbose.set(verbose);
}
public ThreadFactory getThreadFactory() {
return threadFactory;
}
public void setThreadFactory(ThreadFactory tf) {
this.threadFactory = tf;
}
public BinlogEventFilter getEventFilter() {
return eventFilter;
}
public void setEventFilter(BinlogEventFilter filter) {
this.eventFilter = filter;
}
public BinlogEventListener getEventListener() {
return eventListener;
}
public void setEventListener(BinlogEventListener listener) {
this.eventListener = listener;
}
public boolean isClearTableMapEventsOnRotate() {
return clearTableMapEventsOnRotate;
}
public void setClearTableMapEventsOnRotate(boolean clearTableMapEventsOnRotate) {
this.clearTableMapEventsOnRotate = clearTableMapEventsOnRotate;
}
/**
*
*/
public void clearEventParsers() {
for(int i = 0; i < this.parsers.length; i++) {
this.parsers[i] = null;
}
}
public BinlogEventParser getEventParser(int type) {
return this.parsers[type];
}
public BinlogEventParser unregisterEventParser(int type) {
return this.parsers[type] = null;
}
public void registerEventParser(BinlogEventParser parser) {
this.parsers[parser.getEventType()] = parser;
}
// maintain backwards compat
@Deprecated
public void registgerEventParser(BinlogEventParser parser) {
this.registerEventParser(parser);
}
@Deprecated
public BinlogEventParser unregistgerEventParser(int type) {
return unregisterEventParser(type);
}
public void setEventParsers(List parsers) {
clearEventParsers();
if(parsers != null) {
for(BinlogEventParser parser : parsers) {
registerEventParser(parser);
}
}
}
/**
*
*/
public List getParserListeners() {
return new ArrayList(this.parserListeners);
}
public boolean addParserListener(BinlogParserListener listener) {
return this.parserListeners.add(listener);
}
public boolean removeParserListener(BinlogParserListener listener) {
return this.parserListeners.remove(listener);
}
public void setParserListeners(List listeners) {
this.parserListeners.clear();
if(listeners != null) this.parserListeners.addAll(listeners);
}
public String getBinlogFileName() {
return binlogFileName;
}
/**
*
*/
private void notifyOnStart() {
for(BinlogParserListener listener : this.parserListeners) {
listener.onStart(this);
}
}
private void notifyOnStop() {
for(BinlogParserListener listener : this.parserListeners) {
listener.onStop(this);
}
}
private void notifyOnException(Exception exception) {
for(BinlogParserListener listener : this.parserListeners) {
listener.onException(this, exception);
}
}
/**
*
*/
protected class Task implements Runnable {
public void run() {
try {
doParse();
} catch (EOFException e) {
} catch (Exception e) {
notifyOnException(e);
LOGGER.error("failed to parse binlog", e);
} finally {
try {
stop(0, TimeUnit.MILLISECONDS);
} catch(Exception e) {
LOGGER.error("failed to stop binlog parser", e);
}
}
}
}
protected class Context implements BinlogParserContext, BinlogEventListener {
//
private String binlogFileName;
private final Map tableMapEvents = new HashMap();
private boolean checksumEnabled;
/**
*
*/
public Context(AbstractBinlogParser parser) {
this.binlogFileName = parser.getBinlogFileName();
}
/**
*
*/
public final String getBinlogFileName() {
return binlogFileName;
}
public final void setBinlogFileName(String name) {
this.binlogFileName = name;
}
public final BinlogEventListener getEventListener() {
return this;
}
public final TableMapEvent getTableMapEvent(long tableId) {
return this.tableMapEvents.get(tableId);
}
/**
*
*/
public void onEvents(BinlogEventV4 event) {
//
if(event == null) {
return;
}
//
if(event instanceof TableMapEvent) {
final TableMapEvent tme = (TableMapEvent)event;
this.tableMapEvents.put(tme.getTableId(), tme);
} else if(event instanceof RotateEvent) {
final RotateEvent re = (RotateEvent)event;
this.binlogFileName = re.getBinlogFileName().toString();
if(isClearTableMapEventsOnRotate()) this.tableMapEvents.clear();
}
//
try {
AbstractBinlogParser.this.eventListener.onEvents(event);
} catch(Exception e) {
LOGGER.error("failed to notify binlog event listener, event: " + event, e);
}
}
public boolean getChecksumEnabled() {
return this.checksumEnabled;
}
public void setChecksumEnabled(boolean flag) {
this.checksumEnabled = flag;
}
}
}