void startAsyncDataSerivce() { if (asyncDataServiceStarted) { return; } fileContextCache.start(); this.asyncDataService = new AsyncDataService(); asyncDataServiceStarted = true; }
void shutdownAsyncDataService() { if (!asyncDataServiceStarted) { return; } asyncDataServiceStarted = false; asyncDataService.shutdown(); fileContextCache.shutdown(); }
void handleCommit( DFSClient dfsClient, FileHandle fileHandle, long commitOffset, Channel channel, int xid, Nfs3FileAttributes preOpAttr) { int status; OpenFileCtx openFileCtx = fileContextCache.get(fileHandle); if (openFileCtx == null) { LOG.info( "No opened stream for fileId:" + fileHandle.getFileId() + " commitOffset=" + commitOffset + ". Return success in this case."); status = Nfs3Status.NFS3_OK; } else { COMMIT_STATUS ret = openFileCtx.checkCommit(dfsClient, commitOffset, channel, xid, preOpAttr, false); switch (ret) { case COMMIT_FINISHED: case COMMIT_INACTIVE_CTX: status = Nfs3Status.NFS3_OK; break; case COMMIT_INACTIVE_WITH_PENDING_WRITE: case COMMIT_ERROR: status = Nfs3Status.NFS3ERR_IO; break; case COMMIT_WAIT: // Do nothing. Commit is async now. return; case COMMIT_SPECIAL_WAIT: status = Nfs3Status.NFS3ERR_JUKEBOX; break; case COMMIT_SPECIAL_SUCCESS: status = Nfs3Status.NFS3_OK; break; default: LOG.error("Should not get commit return code:" + ret.name()); throw new RuntimeException("Should not get commit return code:" + ret.name()); } } // Send out the response Nfs3FileAttributes postOpAttr = null; try { postOpAttr = getFileAttr(dfsClient, new FileHandle(preOpAttr.getFileId()), iug); } catch (IOException e1) { LOG.info("Can't get postOpAttr for fileId: " + preOpAttr.getFileId(), e1); } WccData fileWcc = new WccData(Nfs3Utils.getWccAttr(preOpAttr), postOpAttr); COMMIT3Response response = new COMMIT3Response(status, fileWcc, Nfs3Constant.WRITE_COMMIT_VERF); Nfs3Utils.writeChannelCommit( channel, response.serialize(new XDR(), xid, new VerifierNone()), xid); }
/** If the file is in cache, update the size based on the cached data size */ Nfs3FileAttributes getFileAttr( DFSClient client, FileHandle fileHandle, IdMappingServiceProvider iug) throws IOException { String fileIdPath = Nfs3Utils.getFileIdPath(fileHandle); Nfs3FileAttributes attr = Nfs3Utils.getFileAttr(client, fileIdPath, iug); if (attr != null) { OpenFileCtx openFileCtx = fileContextCache.get(fileHandle); if (openFileCtx != null) { attr.setSize(openFileCtx.getNextOffset()); attr.setUsed(openFileCtx.getNextOffset()); } } return attr; }
Nfs3FileAttributes getFileAttr(DFSClient client, FileHandle dirHandle, String fileName) throws IOException { String fileIdPath = Nfs3Utils.getFileIdPath(dirHandle) + "/" + fileName; Nfs3FileAttributes attr = Nfs3Utils.getFileAttr(client, fileIdPath, iug); if ((attr != null) && (attr.getType() == NfsFileType.NFSREG.toValue())) { OpenFileCtx openFileCtx = fileContextCache.get(new FileHandle(attr.getFileId())); if (openFileCtx != null) { attr.setSize(openFileCtx.getNextOffset()); attr.setUsed(openFileCtx.getNextOffset()); } } return attr; }
// Do a possible commit before read request in case there is buffered data // inside DFSClient which has been flushed but not synced. int commitBeforeRead(DFSClient dfsClient, FileHandle fileHandle, long commitOffset) { int status; OpenFileCtx openFileCtx = fileContextCache.get(fileHandle); if (openFileCtx == null) { if (LOG.isDebugEnabled()) { LOG.debug( "No opened stream for fileId:" + fileHandle.getFileId() + " commitOffset=" + commitOffset + ". Return success in this case."); } status = Nfs3Status.NFS3_OK; } else { COMMIT_STATUS ret = openFileCtx.checkCommit(dfsClient, commitOffset, null, 0, null, true); switch (ret) { case COMMIT_FINISHED: case COMMIT_INACTIVE_CTX: status = Nfs3Status.NFS3_OK; break; case COMMIT_INACTIVE_WITH_PENDING_WRITE: case COMMIT_ERROR: status = Nfs3Status.NFS3ERR_IO; break; case COMMIT_WAIT: case COMMIT_SPECIAL_WAIT: /** * This should happen rarely in some possible cases, such as read request arrives before * DFSClient is able to quickly flush data to DN, or Prerequisite writes is not available. * Won't wait since we don't want to block read. */ status = Nfs3Status.NFS3ERR_JUKEBOX; break; case COMMIT_SPECIAL_SUCCESS: // Read beyond eof could result in partial read status = Nfs3Status.NFS3_OK; break; default: LOG.error("Should not get commit return code:" + ret.name()); throw new RuntimeException("Should not get commit return code:" + ret.name()); } } return status; }
boolean addOpenFileStream(FileHandle h, OpenFileCtx ctx) { return fileContextCache.put(h, ctx); }
void handleWrite( DFSClient dfsClient, WRITE3Request request, Channel channel, int xid, Nfs3FileAttributes preOpAttr) throws IOException { int count = request.getCount(); byte[] data = request.getData().array(); if (data.length < count) { WRITE3Response response = new WRITE3Response(Nfs3Status.NFS3ERR_INVAL); Nfs3Utils.writeChannel(channel, response.serialize(new XDR(), xid, new VerifierNone()), xid); return; } FileHandle handle = request.getHandle(); if (LOG.isDebugEnabled()) { LOG.debug("handleWrite " + request); } // Check if there is a stream to write FileHandle fileHandle = request.getHandle(); OpenFileCtx openFileCtx = fileContextCache.get(fileHandle); if (openFileCtx == null) { LOG.info("No opened stream for fileId:" + fileHandle.getFileId()); String fileIdPath = Nfs3Utils.getFileIdPath(fileHandle.getFileId()); HdfsDataOutputStream fos = null; Nfs3FileAttributes latestAttr = null; try { int bufferSize = config.getInt( CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_KEY, CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_DEFAULT); fos = dfsClient.append(fileIdPath, bufferSize, null, null); latestAttr = Nfs3Utils.getFileAttr(dfsClient, fileIdPath, iug); } catch (RemoteException e) { IOException io = e.unwrapRemoteException(); if (io instanceof AlreadyBeingCreatedException) { LOG.warn( "Can't append file:" + fileIdPath + ". Possibly the file is being closed. Drop the request:" + request + ", wait for the client to retry..."); return; } throw e; } catch (IOException e) { LOG.error("Can't apapend to file:" + fileIdPath, e); if (fos != null) { fos.close(); } WccData fileWcc = new WccData(Nfs3Utils.getWccAttr(preOpAttr), preOpAttr); WRITE3Response response = new WRITE3Response( Nfs3Status.NFS3ERR_IO, fileWcc, count, request.getStableHow(), Nfs3Constant.WRITE_COMMIT_VERF); Nfs3Utils.writeChannel( channel, response.serialize(new XDR(), xid, new VerifierNone()), xid); return; } // Add open stream String writeDumpDir = config.get( NfsConfigKeys.DFS_NFS_FILE_DUMP_DIR_KEY, NfsConfigKeys.DFS_NFS_FILE_DUMP_DIR_DEFAULT); openFileCtx = new OpenFileCtx( fos, latestAttr, writeDumpDir + "/" + fileHandle.getFileId(), dfsClient, iug, aixCompatMode, config); if (!addOpenFileStream(fileHandle, openFileCtx)) { LOG.info("Can't add new stream. Close it. Tell client to retry."); try { fos.close(); } catch (IOException e) { LOG.error("Can't close stream for fileId:" + handle.getFileId(), e); } // Notify client to retry WccData fileWcc = new WccData(latestAttr.getWccAttr(), latestAttr); WRITE3Response response = new WRITE3Response( Nfs3Status.NFS3ERR_JUKEBOX, fileWcc, 0, request.getStableHow(), Nfs3Constant.WRITE_COMMIT_VERF); Nfs3Utils.writeChannel( channel, response.serialize(new XDR(), xid, new VerifierNone()), xid); return; } if (LOG.isDebugEnabled()) { LOG.debug("Opened stream for appending file:" + fileHandle.getFileId()); } } // Add write into the async job queue openFileCtx.receivedNewWrite(dfsClient, request, channel, xid, asyncDataService, iug); return; }