package org.commoncrawl.util;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.commoncrawl.async.EventLoop;
import org.commoncrawl.async.Timer;
import org.commoncrawl.io.NIOBufferList;
import org.commoncrawl.io.NIOHttpConnection;
import org.commoncrawl.io.NIOHttpConnection.State;
public class S3BulkUploader implements NIOHttpConnection.Listener {
EventLoop _theEventLoop;
FileSystem _fileSystem;
Path _uploadCandidates[];
int _bandwidthPerUploader;
S3Uploader _uploaders[];
String _s3Bucket;
String _s3AccessId;
String _s3SecretKey;
Timer _timer;
S3BulkUploader.Callback _callback;
int _lastUploaderId = 0;
/** logging **/
static final Log LOG = LogFactory.getLog(S3BulkUploader.class);
/** default polling interval **/
private static final int DEFAULT_POLL_INTERVAL = 500;
public static class UploadCandidate {
public UploadCandidate(Path path,String uploadName,String mimeType,String acl) {
_path = path;
_uploadName = uploadName;
_mimeType = mimeType;
_acl = acl;
}
public Path _path;
public String _uploadName;
public String _mimeType;
public String _acl;
}
public static interface Callback {
/** get next upload candidate **/
public S3BulkUploader.UploadCandidate getNextUploadCandidate();
/** the upload failed ... return true if we should retry the item **/
public void uploadFailed(Path path,IOException e);
/** the upload succeeded for the specified item **/
public void uploadComplete(Path path,String bandwidthStats);
}
public S3BulkUploader(EventLoop eventLoop,FileSystem fileSystem,S3BulkUploader.Callback callback,String s3Bucket,String s3AccessId, String s3SecretKey,int bandwidthPerUploader,int maxUploaders) {
_theEventLoop = eventLoop;
_fileSystem = fileSystem;
_bandwidthPerUploader = bandwidthPerUploader;
_uploaders = new S3Uploader[maxUploaders];
_s3Bucket = s3Bucket;
_s3AccessId = s3AccessId;
_s3SecretKey = s3SecretKey;
_callback = callback;
}
public void startUpload() {
_timer = new Timer(DEFAULT_POLL_INTERVAL,true,new Timer.Callback() {
public void timerFired(Timer timer) {
fillSlots();
}
});
_theEventLoop.setTimer(_timer);
}
private void fillSlots() {
for (int i=0;i<_uploaders.length;++i) {
// if empty slot found ...
if (_uploaders[i] == null) {
S3BulkUploader.UploadCandidate uploadCandidate = _callback.getNextUploadCandidate();
if (uploadCandidate != null) {
LOG.info("Queuing: " + uploadCandidate._path.toString() + " for Upload");
_uploaders[i] = new S3Uploader(++_lastUploaderId,_theEventLoop,_fileSystem,uploadCandidate._path,
_bandwidthPerUploader,_s3Bucket,uploadCandidate._uploadName,uploadCandidate._mimeType,_s3AccessId,_s3SecretKey,uploadCandidate._acl);
_uploaders[i].setSlot(i);
try {
_uploaders[i].startUpload(this);
}
catch (IOException e) {
LOG.error ("Upload for : " + uploadCandidate._path.toString() + " FAILED with Exception:" + CCStringUtils.stringifyException(e));
// notify controller through callback ...
_callback.uploadFailed(uploadCandidate._path, e);
}
}
}
}
}
public void HttpConnectionStateChanged(NIOHttpConnection theConnection,State oldState, State state) {
// extract the reference to the uploader based on
S3Uploader uploader = (S3Uploader) theConnection.getContext();
System.out.println("HttpConnection for: " + uploader.getPath() + " transitioned:" + oldState + " to " + state );
// get the associated slot ...
int slotIndex = uploader.getSlot();
if (state == State.ERROR || state == State.DONE) {
boolean failed = true;
if (state == State.DONE) {
int resultCode = NIOHttpConnection.getHttpResponseCode(theConnection.getResponseHeaders());
if (resultCode == 200) {
failed = false;
BandwidthUtils.BandwidthStats stats = new BandwidthUtils.BandwidthStats();
uploader._rateLimiter.getStats(stats);
_callback.uploadComplete(uploader.getPath(),"DownloadSpeed:" + stats.scaledBitsPerSecond + " " + stats.scaledBitsUnits);
}
}
// if the get failed ...
if (failed) {
// check to see if we have a cached exception ...
IOException failureException = uploader.getException();
if (failureException == null) {
// if not ... construct one from the result (if present)....
if (theConnection.getContentBuffer().available() != 0) {
failureException = S3Uploader.failureExceptionFromContent(theConnection);
}
}
_callback.uploadFailed(uploader.getPath(), failureException);
LOG.info("Returned from uploadFailed");
}
if (failed)
LOG.info("Calling uploader.shutdown");
// shutdown the uploader ...
uploader.shutdown();
if (failed)
LOG.info("Post uploader.shutdown");
// empty the slot ...
_uploaders[slotIndex] = null;
if (failed)
LOG.info("Calling fill Slots");
// and fill slots ...
fillSlots();
if (failed)
LOG.info("Post fill Slots");
}
}
public void HttpContentAvailable(NIOHttpConnection theConnection,NIOBufferList contentBuffer) {
// TODO Auto-generated method stub
}
}