blob: 12dbd789ed0a510ff66cff6cce3090ed68550194 [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.je.rep.impl.networkRestore;
import java.nio.ByteBuffer;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.log.LogUtils;
import com.sleepycat.je.rep.impl.node.NameIdPair;
import com.sleepycat.je.rep.utilint.BinaryProtocol;
import com.sleepycat.je.utilint.VLSN;
/**
* The protocol used to obtain backup files from a LF Feeder. The message
* exchange is always initiated by the client.
*
* The following describes the request/response messages exchanged between the
* two nodes:
*
* {@literal
* FeederInfoReq -> FeederInfoResp
*
* FileListReq -> FileListResp
*
* FileInfoReq -> FileInfoResp
*
* FileReq -> FileStart <byte stream> FileEnd
*
* Done
* }
*
* So a complete sequence of successful request messages looks like:
*
* FeederInfoReq FileListReq [[FileInfoReq] [FileReq] ]+ Done
*
* A response sequence would look like:
*
* FeederInfoResp FileListResp [[FileInfoResp] [FileStart <i>byte stream</i> FileEnd] ]+
*
* The client may abandon its interaction with the server if it decides the
* server is overloaded.
*
* The client tries to minimize the number of files it actually requests based
* upon its current state.
*
* When a FileReq is received by the server, other files previously requested
* (using FileReq) may be deleted by the server. These previously requested
* files must not be requested again using FileReq or FileReqInfo.
*/
public class Protocol extends BinaryProtocol {
static public final int VERSION = 2;
/* The messages defined by this class. */
public final MessageOp FEEDER_INFO_REQ =
new MessageOp((short)1, FeederInfoReq.class);
public final MessageOp FEEDER_INFO_RESP =
new MessageOp((short)2, FeederInfoResp.class);
public final MessageOp FILE_LIST_REQ =
new MessageOp((short)3, FileListReq.class);
public final MessageOp FILE_LIST_RESP =
new MessageOp((short)4, FileListResp.class);
public final MessageOp FILE_REQ =
new MessageOp((short)5, FileReq.class);
public final MessageOp FILE_START =
new MessageOp((short)6, FileStart.class);
public final MessageOp FILE_END =
new MessageOp((short)7, FileEnd.class);
public final MessageOp FILE_INFO_REQ =
new MessageOp((short)8, FileInfoReq.class);
public final MessageOp FILE_INFO_RESP =
new MessageOp((short)9, FileInfoResp.class);
public final MessageOp DONE =
new MessageOp((short)10, Done.class);
public Protocol(NameIdPair nameIdPair,
int configuredVersion,
EnvironmentImpl envImpl) {
super(nameIdPair, VERSION, configuredVersion, envImpl);
initializeMessageOps(new MessageOp[]
{FEEDER_INFO_REQ,
FEEDER_INFO_RESP,
FILE_LIST_REQ,
FILE_LIST_RESP,
FILE_INFO_REQ,
FILE_INFO_RESP,
FILE_REQ,
FILE_START,
FILE_END,
DONE});
}
/* Requests the list of log files that need to be backed up. */
public class FeederInfoReq extends SimpleMessage {
public FeederInfoReq() {
super();
}
@SuppressWarnings("unused")
public FeederInfoReq(ByteBuffer buffer) {
super();
}
@Override
public MessageOp getOp() {
return FEEDER_INFO_REQ;
}
}
public class FeederInfoResp extends SimpleMessage {
/* The number of feeders that are currently busy at this server. */
private final int activeFeeders;
/* The vlsn range covered by this server if it's a rep node. */
private final VLSN rangeFirst;
private final VLSN rangeLast;
public FeederInfoResp(int activeFeeders,
VLSN rangeFirst,
VLSN rangeLast) {
super();
this.activeFeeders = activeFeeders;
this.rangeFirst = rangeFirst;
this.rangeLast = rangeLast;
}
public FeederInfoResp(ByteBuffer buffer) {
super();
activeFeeders = LogUtils.readInt(buffer);
rangeFirst = getVLSN(buffer);
rangeLast = getVLSN(buffer);
}
@Override
public MessageOp getOp() {
return FEEDER_INFO_RESP;
}
@Override
public ByteBuffer wireFormat() {
return wireFormat(activeFeeders, rangeFirst, rangeLast);
}
public int getActiveFeeders() {
return activeFeeders;
}
public VLSN getRangeFirst() {
return rangeFirst;
}
public VLSN getRangeLast() {
return rangeLast;
}
}
/* Requests the list of log files that need to be backed up. */
public class FileListReq extends SimpleMessage {
public FileListReq() {
super();
}
@SuppressWarnings("unused")
public FileListReq(ByteBuffer buffer) {
super();
}
@Override
public MessageOp getOp() {
return FILE_LIST_REQ;
}
}
/* Response to the above containing the list of files. */
public class FileListResp extends SimpleMessage {
private final String[] fileNames;
public FileListResp(String[] fileNames) {
super();
this.fileNames = fileNames;
}
public FileListResp(ByteBuffer buffer) {
fileNames = getStringArray(buffer);
}
@Override
public MessageOp getOp() {
return FILE_LIST_RESP;
}
@Override
public ByteBuffer wireFormat() {
return wireFormat((Object)fileNames);
}
public String[] getFileNames() {
return fileNames;
}
}
/**
* Requests that a specific file be sent to the client.
*/
public class FileReq extends SimpleMessage {
protected final String fileName;
public FileReq(String fileName) {
super();
this.fileName = fileName;
}
public FileReq(ByteBuffer buffer) {
fileName = getString(buffer);
}
@Override
public MessageOp getOp() {
return FILE_REQ;
}
@Override
public ByteBuffer wireFormat() {
return wireFormat(fileName);
}
public String getFileName() {
return fileName;
}
}
/**
* Requests information about a specific log file.
*/
public class FileInfoReq extends FileReq {
private final boolean needSHA1;
public FileInfoReq(String fileName, boolean needSHA1) {
super(fileName);
this.needSHA1 = needSHA1;
}
public FileInfoReq(ByteBuffer buffer) {
super(buffer);
needSHA1 = getBoolean(buffer);
}
@Override
public MessageOp getOp() {
return FILE_INFO_REQ;
}
@Override
public ByteBuffer wireFormat() {
return super.wireFormat(fileName, needSHA1);
}
public boolean getNeedSHA1() {
return needSHA1;
}
}
/*
* The Response for information about a specific log file.
*/
public class FileInfoResp extends FileStart {
private final byte[] digestSHA1;
public FileInfoResp(String fileName,
long fileLength,
long lastModifiedTime,
byte[] digestSHA1) {
super(fileName, fileLength, lastModifiedTime);
this.digestSHA1 = digestSHA1;
}
public FileInfoResp(ByteBuffer buffer) {
super(buffer);
this.digestSHA1 = getByteArray(buffer);
}
@Override
public MessageOp getOp() {
return FILE_INFO_RESP;
}
@Override
public ByteBuffer wireFormat() {
return wireFormat(fileName,
fileLength,
lastModifiedTime,
digestSHA1);
}
/**
* Returns the SHA1 value if it was requested, or a zero length byte
* array if it was not requested.
*/
public byte[] getDigestSHA1() {
return digestSHA1;
}
}
/**
* The message starting the response triple:
*
* FileStart <i>byte stream</i> FileEnd
*/
public class FileStart extends SimpleMessage {
/* Must match the request name. */
protected final String fileName;
/* The actual file length in bytes on disk */
protected final long fileLength;
protected final long lastModifiedTime;
public FileStart(String fileName,
long fileLength,
long lastModifiedTime) {
super();
this.fileName = fileName;
this.fileLength = fileLength;
this.lastModifiedTime = lastModifiedTime;
}
public FileStart(ByteBuffer buffer) {
fileName = getString(buffer);
fileLength = LogUtils.readLong(buffer);
lastModifiedTime = LogUtils.readLong(buffer);
}
@Override
public MessageOp getOp() {
return FILE_START;
}
@Override
public ByteBuffer wireFormat() {
return wireFormat(fileName, fileLength, lastModifiedTime);
}
public long getFileLength() {
return fileLength;
}
public long getLastModifiedTime() {
return lastModifiedTime;
}
}
/**
* The message ending the response triple:
*
* FileStart <i>byte stream</i> FileEnd
*/
public class FileEnd extends FileInfoResp {
public FileEnd(String fileName,
long fileLength,
long lastModifiedTime,
byte[] digestSHA1) {
super(fileName, fileLength, lastModifiedTime, digestSHA1);
}
public FileEnd(ByteBuffer buffer) {
super(buffer);
}
@Override
public MessageOp getOp() {
return FILE_END;
}
@Override
public ByteBuffer wireFormat() {
return super.wireFormat();
}
}
/**
* Message from client indicating it's done with all the files it needs and
* that the connection can be terminated.
*/
public class Done extends SimpleMessage {
public Done() {
super();
}
@SuppressWarnings("unused")
public Done(ByteBuffer buffer) {
super();
}
@Override
public MessageOp getOp() {
return DONE;
}
}
}