#pragma once #include #include #include class StorageTarget; /** * Contains common data needed by implementations of the network protocol * that send data to the client. */ struct ReadStateBase { const char* logContext; uint64_t toBeRead; SessionLocalFile* sessionLocalFile; ssize_t readRes; ReadStateBase(const char* logContext, uint64_t toBeRead, SessionLocalFile* sessionLocalFile) { this->logContext = logContext; this->toBeRead = toBeRead; this->sessionLocalFile = sessionLocalFile; } }; template class ReadLocalFileMsgExBase : public Msg { public: bool processIncoming(NetMessage::ResponseContext& ctx); private: SessionLocalFileStore* sessionLocalFiles; FhgfsOpsErr openFile(const StorageTarget& target, SessionLocalFile* sessionLocalFile); void checkAndStartReadAhead(SessionLocalFile* sessionLocalFile, ssize_t readAheadTriggerSize, off_t currentOffset, off_t readAheadSize); int64_t incrementalReadStatefulAndSendV2(NetMessage::ResponseContext& ctx, SessionLocalFile* sessionLocalFile); inline void sendLengthInfo(Socket* sock, int64_t lengthInfo) { static_cast(*this).sendLengthInfo(sock, lengthInfo); } inline bool readStateInit(ReadState& rs) { return static_cast(*this).readStateInit(rs); } inline ssize_t readStateSendData(Socket* sock, ReadState& rs, char* buf, bool isFinal) { return static_cast(*this).readStateSendData(sock, rs, buf, isFinal); } inline bool readStateNext(ReadState& rs) { return static_cast(*this).readStateNext(rs); } inline ssize_t getReadLength(ReadState& rs, ssize_t len) { return static_cast(*this).getReadLength(rs, len); } inline size_t getBuffers(NetMessage::ResponseContext& ctx, char** dataBuf, char** sendBuf) { return static_cast(*this).getBuffers(ctx, dataBuf, sendBuf); } public: inline unsigned getMsgHeaderUserID() const { return static_cast(*this).getMsgHeaderUserID(); } inline bool isMsgHeaderFeatureFlagSet(unsigned flag) const { return static_cast(*this).isMsgHeaderFeatureFlagSet(flag); } inline uint16_t getTargetID() const { return static_cast(*this).getTargetID(); } inline int64_t getOffset() const { return static_cast(*this).getOffset(); } inline int64_t getCount() const { return static_cast(*this).getCount(); } inline const char* getFileHandleID() { return static_cast(*this).getFileHandleID(); } inline NumNodeID getClientNumID() const { return static_cast(*this).getClientNumID(); } inline unsigned getAccessFlags() const { return static_cast(*this).getAccessFlags(); } inline PathInfo* getPathInfo () { return static_cast(*this).getPathInfo(); } inline bool isMsgValid() const { return static_cast(*this).isMsgValid(); } }; /** * Implements the Version 2 send protocol. It uses a preceding length info for each chunk. */ class ReadLocalFileV2MsgSender : public ReadLocalFileV2Msg { /* note on protocol: this works by sending an int64 before each data chunk, which contains the length of the next data chunk; or a zero if no more data can be read; or a negative fhgfs error code in case of an error */ public: struct ReadState : public ReadStateBase { ReadState(const char* logContext, uint64_t toBeRead, SessionLocalFile* sessionLocalFile) : ReadStateBase(logContext, toBeRead, sessionLocalFile) {} }; private: friend class ReadLocalFileMsgExBase; static std::string logContextPref; /** * Send only length information without a data packet. Typically used for the final length * info at the end of the requested data. */ inline void sendLengthInfo(Socket* sock, int64_t lengthInfo) { lengthInfo = HOST_TO_LE_64(lengthInfo); sock->send(&lengthInfo, sizeof(int64_t), 0); } /** * No-op for this implementation. */ inline bool readStateInit(ReadState& rs) { return true; } /** * Send length information and the corresponding data packet buffer. * * Note: rs.readRes is used to compute buf length for send() * * @param rs.readRes must not be negative * @param buf the buffer with a preceding gap for the length info * @param isFinal true if this is the last send, i.e. we have read all data */ inline ssize_t readStateSendData(Socket* sock, ReadState& rs, char* buf, bool isFinal) { ssize_t sendRes; { Serializer ser(buf, sizeof(int64_t)); ser % rs.readRes; } if (isFinal) { Serializer ser(buf + sizeof(int64_t) + rs.readRes, sizeof(int64_t)); ser % int64_t(0); sendRes = sock->send(buf, (2*sizeof(int64_t) ) + rs.readRes, 0); } else { sendRes = sock->send(buf, sizeof(int64_t) + rs.readRes, 0); } return sendRes; } /** * No-op for this implementation. */ inline bool readStateNext(ReadState& rs) { return true; } inline ssize_t getReadLength(ReadState& rs, ssize_t len) { return len; } size_t getBuffers(ResponseContext& ctx, char** dataBuf, char** sendBuf); }; typedef ReadLocalFileMsgExBase ReadLocalFileV2MsgEx;