/** * */ package com.github.seanlinwang.tkv.hdfs; import java.io.IOException; import com.github.seanlinwang.tkv.DataStore; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; /** * @author sean.wang * @since Mar 7, 2012 */ public class HdfsDataStore implements DataStore { private long length = 0; private Path path; private FileSystem fs; private FSDataOutputStream output; private FSDataInputStream input; public HdfsDataStore() { } public HdfsDataStore(FileSystem fs, String hdfsFilename) throws IOException { this.path = new Path(fs.getWorkingDirectory(), hdfsFilename); this.fs = fs; } @Override public void append(byte b) throws IOException { synchronized (this.output) { this.output.write(b); this.length++; } } @Override public void append(byte[] bytes) throws IOException { synchronized (this.output) { this.output.write(bytes); this.length += bytes.length; } } //不支持随机写,只支持顺序写 @Override public void append(long offset, byte[] bytes) throws IOException { throw new UnsupportedOperationException("Hdfs unsupport random write!"); } @Override public void close() throws IOException { this.closeOutput(); this.closeInput(); this.closeFlieSystem(); } private void closeFlieSystem() throws IOException { if (this.fs != null) { this.fs.close(); this.fs = null; } } public void openOutput() throws IOException { if (this.output == null) { this.output = this.fs.create(this.path); } } public void flushAndCloseOutput() throws IOException { if (this.output != null) { this.output.flush(); this.closeOutput(); } } public void closeOutput() throws IOException { if (this.output != null) { this.output.close(); this.output = null; } } public void openInput() throws IOException { if (this.input == null) { this.input = this.fs.open(this.path, 1024); } } public void closeInput() throws IOException { if (this.input != null) { this.input.close(); this.input = null; } } //随机读是支持的 @Override public byte[] get(long offset, int length) throws IOException { FSDataInputStream in = this.input; if (in == null) { throw new IllegalStateException("input can't null"); } byte[] bytes = new byte[length]; synchronized (in) { in.seek(offset); int actual = in.read(bytes); if (actual != length) { throw new IOException(String.format("readed bytes expect %s actual %s", length, actual)); } } return bytes; } @Override public long length() throws IOException { return this.length; } @Override public boolean delete() throws IOException { boolean localDeleted = this.deleteLocal(); boolean remoteDeleted = this.deleteRemote(); return localDeleted && remoteDeleted; } public boolean deleteRemote() throws IOException { boolean remoteDeleted = false; if (this.fs != null) { remoteDeleted = this.fs.delete(path, false); } return remoteDeleted; } public boolean deleteLocal() { return true; } }