NORM-mirror/common/normObject.h

564 lines
22 KiB
C++

#ifndef _NORM_OBJECT
#define _NORM_OBJECT
#include "normSegment.h" // NORM segmentation classes
#include "normEncoder.h"
#include "normFile.h"
#include <stdio.h>
class NormObject
{
friend class NormObjectTable;
public:
enum Type
{
NONE,
DATA,
FILE,
STREAM
};
enum CheckLevel
{
TO_OBJECT,
THRU_INFO,
TO_BLOCK,
THRU_SEGMENT,
THRU_BLOCK,
THRU_OBJECT
};
enum NackingMode
{
NACK_NONE,
NACK_INFO_ONLY,
NACK_NORMAL
};
virtual ~NormObject();
void Retain();
void Release();
unsigned int GetReferenceCount() {return reference_count;}
// This must be reset after each update
void SetNotifyOnUpdate(bool state)
{notify_on_update = state;}
// Object information
NormObject::Type GetType() const {return type;}
const NormObjectId& GetId() const {return transport_id;}
const NormObjectSize& GetSize() const {return object_size;}
bool HaveInfo() const {return (info_len > 0);}
bool HasInfo() const {return (NULL != info_ptr);}
const char* GetInfo() const {return info_ptr;}
UINT16 GetInfoLength() const {return info_len;}
bool IsStream() const {return (STREAM == type);}
class NormSession& GetSession() const {return session;}
NormNodeId LocalNodeId() const;
class NormServerNode* GetServer() const {return server;}
NormNodeId GetServerNodeId() const;
bool IsOpen() {return (0 != segment_size);}
// Opens (inits) object for tx operation
bool Open(const NormObjectSize& objectSize,
const char* infoPtr,
UINT16 infoLen,
UINT16 segmentSize,
UINT16 numData,
UINT16 numParity);
// Opens (inits) object for rx operation
bool Open(const NormObjectSize& objectSize,
bool hasInfo,
UINT16 segmentSize,
UINT16 numData,
UINT16 numParity)
{
return Open(objectSize, (char*)NULL, hasInfo ? 1 : 0,
segmentSize, numData, numParity);
}
void Close();
virtual bool WriteSegment(NormBlockId blockId,
NormSegmentId segmentId,
const char* buffer,
bool msgStart) = 0;
virtual UINT16 ReadSegment(NormBlockId blockId,
NormSegmentId segmentId,
char* buffer,
bool* msgStart = NULL) = 0;
virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId) = 0;
NackingMode GetNackingMode() const {return nacking_mode;}
void SetNackingMode(NackingMode nackingMode)
{
nacking_mode = nackingMode;
// (TBD) initiate an appropriate NormServerNode::RepairCheck
// to prompt repair process if needed
}
// These are only valid after object is open
NormBlockId GetFinalBlockId() const {return final_block_id;}
UINT32 GetBlockSize(NormBlockId blockId) const
{
return (((UINT32)blockId < large_block_count) ? large_block_size :
small_block_size);
}
bool IsPending(bool flush = true) const;
bool IsRepairPending() const;
bool IsPendingInfo() {return pending_info;}
bool GetFirstPending(NormBlockId& blockId) const
{
UINT32 index = 0;
bool result = pending_mask.GetFirstSet(index);
blockId = NormBlockId(index);
return result;
}
bool GetNextPending(NormBlockId& blockId) const
{
UINT32 index = (UINT32)blockId;
bool result = pending_mask.GetNextSet(index);
blockId = NormBlockId(index);
return result;
}
bool GetLastPending(NormBlockId& blockId) const
{
UINT32 index = 0;
bool result = pending_mask.GetLastSet(index);
blockId = NormBlockId(index);
return result;
}
bool GetFirstRepair(NormBlockId& blockId) const
{
UINT32 index = 0;
bool result = repair_mask.GetFirstSet(index);
blockId = NormBlockId(index);
return result;
}
bool GetNextRepair(NormBlockId& blockId) const
{
UINT32 index = (UINT32)blockId;
bool result = repair_mask.GetNextSet(index);
blockId = NormBlockId(index);
return result;
}
bool GetLastRepair(NormBlockId& blockId) const
{
UINT32 index = 0;
bool result = repair_mask.GetLastSet(index);
blockId = NormBlockId(index);
return result;
}
bool FindRepairIndex(NormBlockId& blockId, NormSegmentId& segmentId) const;
// Methods available to server for transmission
bool NextServerMsg(NormObjectMsg* msg);
NormBlock* ServerRecoverBlock(NormBlockId blockId);
bool CalculateBlockParity(NormBlock* block);
bool TxReset(NormBlockId firstBlock = NormBlockId(0));
bool TxResetBlocks(NormBlockId nextId, NormBlockId lastId);
bool TxUpdateBlock(NormBlock* theBlock,
NormSegmentId firstSegmentId,
NormSegmentId lastSegmentId,
UINT16 numErasures)
{
NormBlockId blockId = theBlock->GetId();
bool result = theBlock->TxUpdate(firstSegmentId, lastSegmentId,
GetBlockSize(blockId), nparity,
numErasures);
ASSERT(result ? pending_mask.Set(blockId) : true);
result = result ? pending_mask.Set(blockId) : false;
return result;
}
bool HandleInfoRequest();
bool HandleBlockRequest(NormBlockId nextId, NormBlockId lastId);
bool SetPending(NormBlockId blockId) {return pending_mask.Set(blockId);}
NormBlock* FindBlock(NormBlockId blockId) {return block_buffer.Find(blockId);}
bool ActivateRepairs();
bool IsRepairSet(NormBlockId blockId) {return repair_mask.Test(blockId);}
bool IsPendingSet(NormBlockId blockId) {return pending_mask.Test(blockId);}
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd);
NormBlockId GetMaxPendingBlockId() const {return max_pending_block;}
NormSegmentId GetMaxPendingSegmentId() const {return max_pending_segment;}
// Used by sender for resource management scheme
NormBlock* StealNonPendingBlock(bool excludeBlock, NormBlockId excludeId = 0);
// Methods available to client for reception
bool Accepted() {return accepted;}
void HandleObjectMessage(const NormObjectMsg& msg,
NormMsg::Type msgType,
NormBlockId blockId,
NormSegmentId segmentId);
// Used by receiver for resource management scheme
NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0);
NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0);
bool ReclaimSourceSegments(NormSegmentPool& segmentPool);
bool PassiveRepairCheck(NormBlockId blockId,
NormSegmentId segmentId);
bool ClientRepairCheck(CheckLevel level,
NormBlockId blockId,
NormSegmentId segmentId,
bool timerActive,
bool holdoffPhase = false);
bool IsRepairPending(bool flush);
bool AppendRepairRequest(NormNackMsg& nack, bool flush);
void SetRepairInfo() {repair_info = true;}
bool SetRepairs(NormBlockId first, NormBlockId last)
{
return (first == last) ? repair_mask.Set(first) :
repair_mask.SetBits(first, last-first+1);
}
protected:
NormObject(Type theType,
class NormSession& theSession,
class NormServerNode* theServer,
const NormObjectId& objectId);
void Accept() {accepted = true;}
NormObject::Type type;
class NormSession& session;
class NormServerNode* server; // NULL value indicates local (tx) object
unsigned int reference_count;
NormObjectId transport_id;
NormObjectSize object_size;
UINT16 segment_size;
UINT16 ndata;
UINT16 nparity;
NormBlockBuffer block_buffer;
bool pending_info; // set when we need to send or recv info
NormSlidingMask pending_mask;
bool repair_info; // client: set when
NormSlidingMask repair_mask;
NormBlockId current_block_id; // for suppression
NormSegmentId next_segment_id; // for suppression
NormBlockId max_pending_block; // for NACK construction
NormSegmentId max_pending_segment; // for NACK construction
UINT32 large_block_count;
UINT32 large_block_size;
UINT32 small_block_count;
UINT32 small_block_size;
NormBlockId final_block_id;
UINT16 final_segment_size;
NackingMode nacking_mode;
char* info_ptr;
UINT16 info_len;
// Here are some members used to let us know
// our status with respect to the rest of the world
bool accepted;
bool notify_on_update;
NormObject* next;
}; // end class NormObject
class NormFileObject : public NormObject
{
public:
NormFileObject(class NormSession& theSession,
class NormServerNode* theServer,
const NormObjectId& objectId);
~NormFileObject();
bool Open(const char* thePath,
const char* infoPtr = NULL,
UINT16 infoLen = 0);
bool Accept(const char* thePath);
void Close();
const char* GetPath() {return path;}
bool Rename(const char* newPath)
{
bool result = file.Rename(path, newPath);
result ? strncpy(path, newPath, PATH_MAX) : NULL;
return result;
}
virtual bool WriteSegment(NormBlockId blockId,
NormSegmentId segmentId,
const char* buffer,
bool msgStart);
virtual UINT16 ReadSegment(NormBlockId blockId,
NormSegmentId segmentId,
char* buffer,
bool* msgStart = NULL);
virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId);
private:
char path[PATH_MAX];
NormFile file;
NormObjectSize large_block_length;
NormObjectSize small_block_length;
}; // end class NormFileObject
class NormDataObject : public NormObject
{
// (TBD) allow support of greater than 4GB size data objects
public:
NormDataObject(class NormSession& theSession,
class NormServerNode* theServer,
const NormObjectId& objectId);
~NormDataObject();
bool Open(char* dataPtr,
UINT32 dataLen,
bool dataRelease,
const char* infoPtr = NULL,
UINT16 infoLen = 0);
bool Accept(char* dataPtr, UINT32 dataMax, bool dataRelease);
void Close();
const char* GetData() {return data_ptr;}
char* DetachData()
{
char* dataPtr = data_ptr;
data_ptr = NULL;
return dataPtr;
}
virtual bool WriteSegment(NormBlockId blockId,
NormSegmentId segmentId,
const char* buffer,
bool msgStart);
virtual UINT16 ReadSegment(NormBlockId blockId,
NormSegmentId segmentId,
char* buffer,
bool* msgStart = NULL);
virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId);
private:
NormObjectSize large_block_length;
NormObjectSize small_block_length;
char* data_ptr;
UINT32 data_max;
bool data_released; // when true, data_ptr is deleted
// on NormDataObject destruction
}; // end class NormDataObject
class NormStreamObject : public NormObject
{
public:
NormStreamObject(class NormSession& theSession,
class NormServerNode* theServer,
const NormObjectId& objectId);
~NormStreamObject();
bool Open(UINT32 bufferSize,
const char* infoPtr = NULL,
UINT16 infoLen = 0);
void Close();
bool Accept(UINT32 bufferSize);
enum FlushMode
{
FLUSH_NONE, // no flush action taken
FLUSH_PASSIVE, // pending queued data is transmitted, but no CMD(FLUSH) sent
FLUSH_ACTIVE // pending queued data is transmitted, _and_ active CMD(FLUSH)
};
void SetFlushMode(FlushMode flushMode) {flush_mode = flushMode;}
void Flush(bool eom = false)
{
FlushMode oldFlushMode = flush_mode;
SetFlushMode((FLUSH_ACTIVE == oldFlushMode) ? FLUSH_ACTIVE : FLUSH_PASSIVE);
Write(NULL, 0, eom);
SetFlushMode(oldFlushMode);
}
void SetPushMode(bool state) {push_mode = state;}
bool Read(char* buffer, unsigned int* buflen, bool findMsgStart = false);
UINT32 Write(const char* buffer, UINT32 len, bool eom = false);
bool SyncOffsetIsValid() {return sync_offset_valid;}
UINT32 GetSyncOffset() {return sync_offset;}
UINT32 GetCurrentReadOffset() {return read_offset;}
bool StreamUpdateStatus(NormBlockId blockId);
void StreamResync(NormBlockId nextBlockId)
{
stream_next_id = nextBlockId;
}
void StreamAdvance();
virtual bool WriteSegment(NormBlockId blockId,
NormSegmentId segmentId,
const char* buffer,
bool msgStart);
virtual UINT16 ReadSegment(NormBlockId blockId,
NormSegmentId segmentId,
char* buffer,
bool* msgStart = NULL);
virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId);
// For receive stream, we can rewind to earliest buffered offset
void Rewind();
bool LockBlocks(NormBlockId nextId, NormBlockId lastId);
bool LockSegments(NormBlockId blockId, NormSegmentId firstId,
NormSegmentId lastId);
NormBlockId StreamBufferLo() {return stream_buffer.RangeLo();}
void Prune(NormBlockId blockId);
bool IsFlushPending() {return flush_pending;}
NormBlockId FlushBlockId()
{return (write_index.segment ? write_index.block :
(NormBlockId((UINT32)write_index.block-1)));}
NormSegmentId FlushSegmentId()
{return (write_index.segment ? (write_index.segment-1) :
(ndata-1));}
NormBlockId GetNextBlockId() const
{return (server ? read_index.block : write_index.block);}
NormSegmentId GetNextSegmentId() const
{return (server ? read_index.segment : write_index.segment);}
UINT32 GetBlockPoolCount() {return block_pool.GetCount();}
void SetBlockPoolThreshold(UINT32 value)
{block_pool_threshold = value;}
private:
class Index
{
public:
NormBlockId block;
NormSegmentId segment;
};
// Extra state for STREAM objects
bool stream_sync;
NormBlockId stream_sync_id;
NormBlockId stream_next_id;
UINT32 sync_offset;
bool sync_offset_valid;
NormBlockPool block_pool;
NormSegmentPool segment_pool;
NormBlockBuffer stream_buffer;
Index write_index;
UINT32 write_offset;
bool read_init;
Index read_index;
UINT32 read_offset;
bool flush_pending;
bool msg_start;
FlushMode flush_mode;
bool push_mode;
// For threaded API purposes
UINT32 block_pool_threshold;
}; // end class NormStreamObject
#ifdef SIMULATE
// This class is used to simulate file objects in the
// network simulation build of NORM
class NormSimObject : public NormObject
{
public:
NormSimObject(class NormSession& theSession,
class NormServerNode* theServer,
const NormObjectId& objectId);
~NormSimObject();
bool Open(UINT32 objectSize,
const char* infoPtr = NULL,
UINT16 infoLen = 0);
bool Accept() {NormObject::Accept(); return true;}
void Close() {NormObject::Close();}
virtual bool WriteSegment(NormBlockId blockId,
NormSegmentId segmentId,
const char* buffer,
bool msgStart) {return true;}
virtual UINT16 ReadSegment(NormBlockId blockId,
NormSegmentId segmentId,
char* buffer,
bool* msgStart = NULL);
virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId);
}; // end class NormSimObject
#endif // SIMULATE
class NormObjectTable
{
public:
class Iterator;
friend class NormObjectTable::Iterator;
NormObjectTable();
~NormObjectTable();
bool Init(UINT16 rangeMax, UINT16 tableSize = 256);
void Destroy();
bool IsInited() const {return (NULL != table);}
bool CanInsert(NormObjectId objectId) const;
bool Insert(NormObject* theObject);
bool Remove(const NormObject* theObject);
NormObject* Find(const NormObjectId& objectId) const;
NormObjectId RangeLo() const {return range_lo;}
NormObjectId RangeHi() const {return range_hi;}
bool IsEmpty() const {return (0 == range);}
UINT32 Count() const {return count;}
const NormObjectSize& Size() const {return size;}
class Iterator
{
public:
Iterator(const NormObjectTable& objectTable);
NormObject* GetNextObject();
NormObject* GetPrevObject();
void Reset() {reset = true;}
private:
const NormObjectTable& table;
bool reset;
NormObjectId index;
bool backwards;
};
private:
NormObject* Next(NormObject* o) const {return o->next;}
NormObject** table;
UINT16 hash_mask;
UINT16 range_max; // max range of objects that can be kept
UINT16 range; // zero if "object table" is empty
NormObjectId range_lo;
NormObjectId range_hi;
UINT16 count;
NormObjectSize size;
}; // end class NormObjectTable
#endif // _NORM_OBJECT