pull/2/head
Jeff Weston 2019-09-11 12:00:28 -04:00
parent 28c6631d92
commit 8a4e96c9c4
13 changed files with 349 additions and 166 deletions

View File

@ -1,5 +1,23 @@
NORM Version History NORM Version History
Version 1.4b2
=============
- Fixed bug where NormObjectCancel() usage could result in extra
"release" of reference to NormObject
(Thanks to Alan McKechnie)
- Fixed minor issue with "repeatcount" command of "normApp.cpp"
where only the abbreviated command "repeat" was accepted.
(Thanks to Deric Sullivan)
- Added NormSetTxRobustFactor(), NormSetDefaultRxRobustFactor(), and
NormNodeSetRobustFactor() API calls
- Fixed issue with CC_INACTIVE being prematurely declared and modified
NORM RxSocketHandler to read a maximum of 100 consecutive packets
from socket at a time (This makes sure that receivers service timeouts,
provide feedback more timely, etc)
(Thanks to Peter Lu)
- Fixed case when repair request for old NORM_OBJECT_STREAM segment could
lockup advancement of stream.
Version 1.4b1 Version 1.4b1
============= =============
- Fixed condition where receivers kept state for remote senders "stuck" - Fixed condition where receivers kept state for remote senders "stuck"

View File

@ -94,7 +94,7 @@ class NormInstance : public NormController
static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle) static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle)
{ {
if (NORM_NODE_INVALID == nodeHandle) return ((NormInstance*)NULL); if (NORM_NODE_INVALID == nodeHandle) return ((NormInstance*)NULL);
NormSession& session = ((NormNode*)nodeHandle)->GetSession(); NormSession& session = ((NormServerNode*)nodeHandle)->GetSession();
return static_cast<NormInstance*>(session.GetSessionMgr().GetController()); return static_cast<NormInstance*>(session.GetSessionMgr().GetController());
} }
static NormInstance* GetInstanceFromObject(NormObjectHandle objectHandle) static NormInstance* GetInstanceFromObject(NormObjectHandle objectHandle)
@ -1182,6 +1182,19 @@ void NormSetGroupSize(NormSessionHandle sessionHandle,
} }
} // end NormSetGroupSize() } // end NormSetGroupSize()
NORM_API_LINKAGE
void NormSetTxRobustFactor(NormSessionHandle sessionHandle,
int robustFactor)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
session->SetTxRobustFactor(robustFactor);
instance->dispatcher.ResumeThread();
}
} // end NormSetTxRobustFactor()
NORM_API_LINKAGE NORM_API_LINKAGE
NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* fileName, const char* fileName,
@ -1300,7 +1313,6 @@ unsigned int NormStreamWrite(NormObjectHandle streamHandle,
{ {
NormStreamObject* stream = NormStreamObject* stream =
static_cast<NormStreamObject*>((NormObject*)streamHandle); static_cast<NormStreamObject*>((NormObject*)streamHandle);
if (stream)
result = stream->Write(buffer, numBytes, false); result = stream->Write(buffer, numBytes, false);
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
@ -1317,13 +1329,10 @@ void NormStreamFlush(NormObjectHandle streamHandle,
{ {
NormStreamObject* stream = NormStreamObject* stream =
static_cast<NormStreamObject*>((NormObject*)streamHandle); static_cast<NormStreamObject*>((NormObject*)streamHandle);
if (stream)
{
NormStreamObject::FlushMode saveFlushMode = stream->GetFlushMode(); NormStreamObject::FlushMode saveFlushMode = stream->GetFlushMode();
stream->SetFlushMode((NormStreamObject::FlushMode)flushMode); stream->SetFlushMode((NormStreamObject::FlushMode)flushMode);
stream->Flush(eom); stream->Flush(eom);
stream->SetFlushMode(saveFlushMode); stream->SetFlushMode(saveFlushMode);
}
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
} // end NormStreamFlush() } // end NormStreamFlush()
@ -1410,6 +1419,18 @@ bool NormSetWatermark(NormSessionHandle sessionHandle,
return result; return result;
} // end NormSetWatermark() } // end NormSetWatermark()
NORM_API_LINKAGE
void NormCancelWatermark(NormSessionHandle sessionHandle)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
session->ServerCancelWatermark();
instance->dispatcher.ResumeThread();
}
} // end NormSetWatermark()
NORM_API_LINKAGE NORM_API_LINKAGE
bool NormAddAckingNode(NormSessionHandle sessionHandle, bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId) NormNodeId nodeId)
@ -1571,11 +1592,41 @@ NORM_API_LINKAGE
void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
NormRepairBoundary repairBoundary) NormRepairBoundary repairBoundary)
{ {
NormServerNode* node = static_cast<NormServerNode*>((NormNode*)nodeHandle); NormServerNode* node = static_cast<NormServerNode*>((NormServerNode*)nodeHandle);
if (node) if (node)
node->SetRepairBoundary((NormServerNode::RepairBoundary)repairBoundary); node->SetRepairBoundary((NormServerNode::RepairBoundary)repairBoundary);
} // end NormNodeSetRepairBoundary() } // end NormNodeSetRepairBoundary()
NORM_API_LINKAGE
void NormSetDefaultRxRobustFactor(NormSessionHandle sessionHandle,
int robustFactor)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
session->SetRxRobustFactor(robustFactor);
instance->dispatcher.ResumeThread();
}
} // end NormSetDefaultRxRobustFactor()
NORM_API_LINKAGE
void NormNodeSetRxRobustFactor(NormNodeHandle nodeHandle,
int robustFactor)
{
if (NORM_NODE_INVALID != nodeHandle)
{
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormServerNode* node = (NormServerNode*)nodeHandle;
node->SetRobustFactor(robustFactor);
instance->dispatcher.ResumeThread();
}
}
} // end NormNodeSetRxRobustFactor()
NORM_API_LINKAGE NORM_API_LINKAGE
bool NormStreamRead(NormObjectHandle streamHandle, bool NormStreamRead(NormObjectHandle streamHandle,
char* buffer, char* buffer,
@ -1801,8 +1852,8 @@ NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle)
NORM_API_LINKAGE NORM_API_LINKAGE
NormNodeId NormNodeGetId(NormNodeHandle nodeHandle) NormNodeId NormNodeGetId(NormNodeHandle nodeHandle)
{ {
NormNode* node = (NormNode*)nodeHandle; NormServerNode* node = (NormServerNode*)nodeHandle;
if (node) if (NULL != node)
return node->GetId(); return node->GetId();
else else
return NORM_NODE_NONE; return NORM_NODE_NONE;
@ -1820,7 +1871,7 @@ bool NormNodeGetAddress(NormNodeHandle nodeHandle,
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle); NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
if (instance && instance->dispatcher.SuspendThread()) if (instance && instance->dispatcher.SuspendThread())
{ {
NormNode* node = (NormNode*)nodeHandle; NormServerNode* node = (NormServerNode*)nodeHandle;
const ProtoAddress& nodeAddr = node->GetAddress(); const ProtoAddress& nodeAddr = node->GetAddress();
unsigned int addrLen = nodeAddr.GetLength(); unsigned int addrLen = nodeAddr.GetLength();
if (addrBuffer && bufferLen && (addrLen <= *bufferLen)) if (addrBuffer && bufferLen && (addrLen <= *bufferLen))

View File

@ -314,6 +314,10 @@ NORM_API_LINKAGE
void NormSetGroupSize(NormSessionHandle sessionHandle, void NormSetGroupSize(NormSessionHandle sessionHandle,
unsigned int groupSize); unsigned int groupSize);
NORM_API_LINKAGE
void NormSetTxRobustFactor(NormSessionHandle sessionHandle,
int robustFactor);
NORM_API_LINKAGE NORM_API_LINKAGE
NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* fileName, const char* fileName,
@ -365,6 +369,9 @@ NORM_API_LINKAGE
bool NormSetWatermark(NormSessionHandle sessionHandle, bool NormSetWatermark(NormSessionHandle sessionHandle,
NormObjectHandle objectHandle); NormObjectHandle objectHandle);
NORM_API_LINKAGE
void NormCancelWatermark(NormSessionHandle sessionHandle);
NORM_API_LINKAGE NORM_API_LINKAGE
bool NormAddAckingNode(NormSessionHandle sessionHandle, bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId); NormNodeId nodeId);
@ -423,6 +430,14 @@ NORM_API_LINKAGE
void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
NormRepairBoundary repairBoundary); NormRepairBoundary repairBoundary);
NORM_API_LINKAGE
void NormSetDefaultRxRobustFactor(NormSessionHandle sessionHandle,
int robustFactor);
NORM_API_LINKAGE
void NormNodeSetRxRobustFactor(NormNodeHandle nodeHandle,
int robustFactor);
NORM_API_LINKAGE NORM_API_LINKAGE
bool NormStreamRead(NormObjectHandle streamHandle, bool NormStreamRead(NormObjectHandle streamHandle,
char* buffer, char* buffer,

View File

@ -669,7 +669,7 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
return false; return false;
} }
} }
else if (!strncmp("repeat", cmd, len)) else if (!strncmp("repeatcount", cmd, len))
{ {
tx_repeat_count = atoi(val); tx_repeat_count = atoi(val);
} }

View File

@ -21,8 +21,6 @@
const UINT8 NORM_PROTOCOL_VERSION = 1; const UINT8 NORM_PROTOCOL_VERSION = 1;
const int NORM_ROBUST_FACTOR = 20; // default robust factor
// This value is used in a couple places in the code as // This value is used in a couple places in the code as
// a safety check where some critical timeouts may be // a safety check where some critical timeouts may be
// less than expected operating system clock resolution // less than expected operating system clock resolution
@ -268,8 +266,8 @@ class NormHeaderExtension
protected: protected:
enum enum
{ {
TYPE_OFFSET = 0, TYPE_OFFSET = 0, // UINT8 offset
LENGTH_OFFSET = TYPE_OFFSET + 1 LENGTH_OFFSET = TYPE_OFFSET + 1 // UINT8 offset
}; };
UINT32* buffer; UINT32* buffer;
}; // end class NormHeaderExtension }; // end class NormHeaderExtension
@ -761,7 +759,7 @@ class NormCmdMsg : public NormMsg
enum enum
{ {
INSTANCE_ID_OFFSET = MSG_OFFSET/2, INSTANCE_ID_OFFSET = MSG_OFFSET/2,
GRTT_OFFSET = (INSTANCE_ID_OFFSET*2)+2, GRTT_OFFSET = (INSTANCE_ID_OFFSET+1)*2,
BACKOFF_OFFSET = GRTT_OFFSET + 1, BACKOFF_OFFSET = GRTT_OFFSET + 1,
GSIZE_OFFSET = BACKOFF_OFFSET, GSIZE_OFFSET = BACKOFF_OFFSET,
FLAVOR_OFFSET = GSIZE_OFFSET + 1 FLAVOR_OFFSET = GSIZE_OFFSET + 1
@ -1435,7 +1433,8 @@ class NormNackMsg : public NormMsg
grttResponse.tv_usec = ntohl(buffer[GRTT_RESPONSE_USEC_OFFSET]); grttResponse.tv_usec = ntohl(buffer[GRTT_RESPONSE_USEC_OFFSET]);
} }
//char* AccessRepairContent() {return (buffer + header_length);} //char* AccessRepairContent() {return (buffer + header_length);}
const UINT32* GetRepairContent() const {return (buffer + header_length/4);} const UINT32* GetRepairContent() const
{return (buffer + header_length/4);}
UINT16 GetRepairContentLength() const UINT16 GetRepairContentLength() const
{return ((length > header_length) ? length - header_length : 0);} {return ((length > header_length) ? length - header_length : 0);}
UINT16 UnpackRepairRequest(NormRepairRequest& request, UINT16 UnpackRepairRequest(NormRepairRequest& request,

View File

@ -54,8 +54,6 @@ NormServerNode::NormServerNode(class NormSession& theSession, NormNodeId nodeId)
nominal_packet_size(0), recv_total(0), recv_goodput(0), resync_count(0), nominal_packet_size(0), recv_total(0), recv_goodput(0), resync_count(0),
nack_count(0), suppress_count(0), completion_count(0), failure_count(0) nack_count(0), suppress_count(0), completion_count(0), failure_count(0)
{ {
repair_boundary = session.ClientGetDefaultRepairBoundary(); repair_boundary = session.ClientGetDefaultRepairBoundary();
default_nacking_mode = session.ClientGetDefaultNackingMode(); default_nacking_mode = session.ClientGetDefaultNackingMode();
unicast_nacks = session.ClientGetUnicastNacks(); unicast_nacks = session.ClientGetUnicastNacks();
@ -66,10 +64,10 @@ NormServerNode::NormServerNode(class NormSession& theSession, NormNodeId nodeId)
repair_timer.SetRepeat(1); repair_timer.SetRepeat(1);
activity_timer.SetListener(this, &NormServerNode::OnActivityTimeout); activity_timer.SetListener(this, &NormServerNode::OnActivityTimeout);
double activityInterval = 2*NormSession::DEFAULT_GRTT_ESTIMATE*NORM_ROBUST_FACTOR; double activityInterval = 2*NormSession::DEFAULT_GRTT_ESTIMATE*session.GetTxRobustFactor();
if (activityInterval < ACTIVITY_INTERVAL_MIN) activityInterval = ACTIVITY_INTERVAL_MIN; if (activityInterval < ACTIVITY_INTERVAL_MIN) activityInterval = ACTIVITY_INTERVAL_MIN;
activity_timer.SetInterval(activityInterval); activity_timer.SetInterval(activityInterval);
activity_timer.SetRepeat(NORM_ROBUST_FACTOR); activity_timer.SetRepeat(robust_factor);
cc_timer.SetListener(this, &NormServerNode::OnCCTimeout); cc_timer.SetListener(this, &NormServerNode::OnCCTimeout);
cc_timer.SetInterval(0.0); cc_timer.SetInterval(0.0);
@ -308,6 +306,18 @@ void NormServerNode::FreeBuffers()
segment_size = ndata = nparity = 0; segment_size = ndata = nparity = 0;
} // end NormServerNode::FreeBuffers() } // end NormServerNode::FreeBuffers()
void NormServerNode::SetRobustFactor(int value)
{
robust_factor = value;
// activity timer depends upon robust_factor
// (TBD) do a proper rescaling here instead?
double activityInterval = 2*session.GetTxRobustFactor()*grtt_estimate;
if (activityInterval < ACTIVITY_INTERVAL_MIN) activityInterval = ACTIVITY_INTERVAL_MIN;
activity_timer.SetInterval(activityInterval);
activity_timer.SetRepeat(robust_factor);
if (activity_timer.IsActive()) activity_timer.Reschedule();
} // end NormServerNode::SetRobustFactor()
void NormServerNode::UpdateGrttEstimate(UINT8 grttQuantized) void NormServerNode::UpdateGrttEstimate(UINT8 grttQuantized)
{ {
grtt_quantized = grttQuantized; grtt_quantized = grttQuantized;
@ -316,7 +326,7 @@ void NormServerNode::UpdateGrttEstimate(UINT8 grttQuantized)
LocalNodeId(), GetId(), grtt_estimate); LocalNodeId(), GetId(), grtt_estimate);
// activity timer depends upon sender's grtt estimate // activity timer depends upon sender's grtt estimate
// (TBD) do a proper rescaling here instead? // (TBD) do a proper rescaling here instead?
double activityInterval = 2*NORM_ROBUST_FACTOR*grtt_estimate; double activityInterval = 2*session.GetTxRobustFactor()*grtt_estimate;
if (activityInterval < ACTIVITY_INTERVAL_MIN) activityInterval = ACTIVITY_INTERVAL_MIN; if (activityInterval < ACTIVITY_INTERVAL_MIN) activityInterval = ACTIVITY_INTERVAL_MIN;
activity_timer.SetInterval(activityInterval); activity_timer.SetInterval(activityInterval);
if (activity_timer.IsActive()) activity_timer.Reschedule(); if (activity_timer.IsActive()) activity_timer.Reschedule();
@ -418,6 +428,9 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
// Respond immediately // Respond immediately
maxBackoff = 0.0; maxBackoff = 0.0;
if (cc_timer.IsActive()) cc_timer.Deactivate(); if (cc_timer.IsActive()) cc_timer.Deactivate();
cc_timer.ResetRepeat();
OnCCTimeout(cc_timer);
break;
} }
else else
{ {
@ -456,6 +469,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
DMSG(6, "NormServerNode::HandleCommand() node>%lu begin CC back-off: %lf sec)...\n", DMSG(6, "NormServerNode::HandleCommand() node>%lu begin CC back-off: %lf sec)...\n",
LocalNodeId(), backoffTime); LocalNodeId(), backoffTime);
session.ActivateTimer(cc_timer); session.ActivateTimer(cc_timer);
break;
} // end if (CC_RATE == ext.GetType()) } // end if (CC_RATE == ext.GetType())
} // end while (GetNextExtension()) } // end while (GetNextExtension())
// Disable CC feedback if sender doesn't want it // Disable CC feedback if sender doesn't want it
@ -809,9 +823,11 @@ void NormServerNode::CalculateGrttResponse(const struct timeval& currentTime,
void NormServerNode::DeleteObject(NormObject* obj) void NormServerNode::DeleteObject(NormObject* obj)
{ {
if (rx_table.Remove(obj)) if (rx_table.Remove(obj))
{
rx_pending_mask.Unset(obj->GetId()); rx_pending_mask.Unset(obj->GetId());
obj->Close(); obj->Close();
obj->Release(); obj->Release();
}
} // end NormServerNode::DeleteObject() } // end NormServerNode::DeleteObject()
NormBlock* NormServerNode::GetFreeBlock(NormObjectId objectId, NormBlockId blockId) NormBlock* NormServerNode::GetFreeBlock(NormObjectId objectId, NormBlockId blockId)
@ -1823,9 +1839,10 @@ void NormServerNode::Activate(bool isObjectMsg)
{ {
if (!activity_timer.IsActive()) if (!activity_timer.IsActive())
{ {
double activityInterval = 2*NORM_ROBUST_FACTOR*grtt_estimate; double activityInterval = 2*session.GetTxRobustFactor()*grtt_estimate;
if (activityInterval < ACTIVITY_INTERVAL_MIN) activityInterval = ACTIVITY_INTERVAL_MIN; if (activityInterval < ACTIVITY_INTERVAL_MIN) activityInterval = ACTIVITY_INTERVAL_MIN;
activity_timer.SetInterval(activityInterval); activity_timer.SetInterval(activityInterval);
activity_timer.SetRepeat(robust_factor);
session.ActivateTimer(activity_timer); session.ActivateTimer(activity_timer);
server_active = false; server_active = false;
session.Notify(NormController::REMOTE_SENDER_ACTIVE, this, NULL); session.Notify(NormController::REMOTE_SENDER_ACTIVE, this, NULL);
@ -2087,7 +2104,7 @@ bool NormServerNode::OnAckTimeout(ProtoTimer& /*theTimer*/)
NormAckingNode::NormAckingNode(class NormSession& theSession, NormNodeId nodeId) NormAckingNode::NormAckingNode(class NormSession& theSession, NormNodeId nodeId)
: NormNode(theSession, nodeId), ack_received(false), req_count(NORM_ROBUST_FACTOR) : NormNode(theSession, nodeId), ack_received(false), req_count(theSession.GetTxRobustFactor())
{ {
} }

View File

@ -145,13 +145,14 @@ class NormAckingNode : public NormNode
~NormAckingNode(); ~NormAckingNode();
bool IsPending() const bool IsPending() const
{return (!ack_received && (req_count > 0));} {return (!ack_received && (req_count > 0));}
void Reset(unsigned int maxAttempts = NORM_ROBUST_FACTOR) void Reset(unsigned int maxAttempts)
{ {
ack_received = false; ack_received = false;
req_count = maxAttempts; req_count = maxAttempts;
} }
void DecrementReqCount() {if (req_count > 0) req_count--;} void DecrementReqCount() {if (req_count > 0) req_count--;}
void ResetReqCount() {req_count = NORM_ROBUST_FACTOR;} void ResetReqCount(unsigned int maxAttempts)
{req_count = maxAttempts;}
unsigned int GetReqCount() const {return req_count;} unsigned int GetReqCount() const {return req_count;}
bool AckReceived() const {return ack_received;} bool AckReceived() const {return ack_received;}
void MarkAckReceived() {ack_received = true;} void MarkAckReceived() {ack_received = true;}
@ -225,6 +226,9 @@ class NormServerNode : public NormNode
void SetDefaultNackingMode(NormObject::NackingMode nackingMode) void SetDefaultNackingMode(NormObject::NackingMode nackingMode)
{default_nacking_mode = nackingMode;} {default_nacking_mode = nackingMode;}
// Should generally inherit NormSession::GetRxRobustFactor()
void SetRobustFactor(int value);
NormServerNode::RepairBoundary GetRepairBoundary() const NormServerNode::RepairBoundary GetRepairBoundary() const
{return repair_boundary;} {return repair_boundary;}
// (TBD) force an appropriate RepairCheck on boundary change??? // (TBD) force an appropriate RepairCheck on boundary change???
@ -263,7 +267,6 @@ class NormServerNode : public NormNode
void FreeBuffers(); void FreeBuffers();
void Activate(bool isObjectMsg); void Activate(bool isObjectMsg);
bool SyncTest(const NormObjectMsg& msg) const; bool SyncTest(const NormObjectMsg& msg) const;
void Sync(NormObjectId objectId); void Sync(NormObjectId objectId);
ObjectStatus UpdateSyncStatus(const NormObjectId& objectId); ObjectStatus UpdateSyncStatus(const NormObjectId& objectId);
@ -386,6 +389,7 @@ class NormServerNode : public NormNode
void HandleRepairContent(const UINT32* buffer, UINT16 bufferLen); void HandleRepairContent(const UINT32* buffer, UINT16 bufferLen);
UINT16 instance_id; UINT16 instance_id;
int robust_factor;
bool synchronized; bool synchronized;
NormObjectId sync_id; // only valid if(synchronized) NormObjectId sync_id; // only valid if(synchronized)
NormObjectId next_id; // only valid if(synchronized) NormObjectId next_id; // only valid if(synchronized)

View File

@ -375,9 +375,14 @@ bool NormObject::ActivateRepairs()
if (block) block->TxReset(GetBlockSize(nextId), nparity, autoParity, segment_size); if (block) block->TxReset(GetBlockSize(nextId), nparity, autoParity, segment_size);
// (TBD) This check can be eventually eliminated if everything else is done right // (TBD) This check can be eventually eliminated if everything else is done right
if (!pending_mask.Set(nextId)) if (!pending_mask.Set(nextId))
{
if (block) block->ClearPending();
DMSG(0, "NormObject::ActivateRepairs() pending_mask.Set(%lu) error 1!\n", (UINT32)nextId); DMSG(0, "NormObject::ActivateRepairs() pending_mask.Set(%lu) error 1!\n", (UINT32)nextId);
}
else else
{
repairsActivated = true; repairsActivated = true;
}
nextId++; nextId++;
} while (GetNextRepair(nextId)); } while (GetNextRepair(nextId));
repair_mask.Clear(); repair_mask.Clear();
@ -390,16 +395,20 @@ bool NormObject::ActivateRepairs()
{ {
if (block->ActivateRepairs(nparity)) if (block->ActivateRepairs(nparity))
{ {
//repairsActivated = true;
DMSG(6, "NormObject::ActivateRepairs() node>%lu obj>%hu activated blk>%lu segment repairs ...\n", DMSG(6, "NormObject::ActivateRepairs() node>%lu obj>%hu activated blk>%lu segment repairs ...\n",
LocalNodeId(), (UINT16)transport_id, (UINT32)block->GetId()); LocalNodeId(), (UINT16)transport_id, (UINT32)block->GetId());
// (TBD) This check can be eventually eliminated if everything else is done right // (TBD) This check can be eventually eliminated if everything else is done right
if (!pending_mask.Set(block->GetId())) if (!pending_mask.Set(block->GetId()))
{
block->ClearPending();
DMSG(0, "NormObject::ActivateRepairs() pending_mask.Set(%lu) error 2!\n", (UINT32)block->GetId()); DMSG(0, "NormObject::ActivateRepairs() pending_mask.Set(%lu) error 2!\n", (UINT32)block->GetId());
}
else else
{
repairsActivated = true; repairsActivated = true;
} }
} }
}
return repairsActivated; return repairsActivated;
} // end NormObject::ActivateRepairs() } // end NormObject::ActivateRepairs()
@ -1525,7 +1534,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
NormBlockId blockId; NormBlockId blockId;
if (!GetFirstPending(blockId)) if (!GetFirstPending(blockId))
{ {
// Attempt to advance stream (probably was repair-delayed) // Attempt to advance stream (probably had been repair-delayed)
if (IsStream()) if (IsStream())
{ {
static_cast<NormStreamObject*>(this)->StreamAdvance(); static_cast<NormStreamObject*>(this)->StreamAdvance();
@ -1588,7 +1597,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
{ {
NormBlock* b = block_buffer.Find(block_buffer.RangeLo()); NormBlock* b = block_buffer.Find(block_buffer.RangeLo());
ASSERT(NULL != b); ASSERT(NULL != b);
//ASSERT(!b->IsPending()); (TBD) ??? Why might "b" be pending? ASSERT(!b->IsPending());
bool push = static_cast<NormStreamObject*>(this)->GetPushMode(); bool push = static_cast<NormStreamObject*>(this)->GetPushMode();
if (!push && (b->IsRepairPending() || IsRepairSet(b->GetId()))) if (!push && (b->IsRepairPending() || IsRepairSet(b->GetId())))
{ {
@ -1609,8 +1618,9 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
} }
else if (IsStream()) else if (IsStream())
{ {
DMSG(4, "NormObject::NextServerMsg() node>%lu Warning! can't repair old block\n", LocalNodeId()); DMSG(3, "NormObject::NextServerMsg() node>%lu Warning! can't repair old stream block\n", LocalNodeId());
session.ServerPutFreeBlock(block); session.ServerPutFreeBlock(block);
repair_mask.Unset(blockId); // just in case
pending_mask.Unset(blockId); pending_mask.Unset(blockId);
// Unlock (set to non-pending status) the corresponding stream_buffer block // Unlock (set to non-pending status) the corresponding stream_buffer block
static_cast<NormStreamObject*>(this)->UnlockBlock(blockId); static_cast<NormStreamObject*>(this)->UnlockBlock(blockId);
@ -1640,11 +1650,33 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
if (0 == payloadLength) if (0 == payloadLength)
{ {
// (TBD) deal with read error // (TBD) deal with read error
//(for streams, it currently means the stream is non-pending) //(for streams, it currently means the stream is pending, but app hasn't yet written data)
if (!IsStream()) if (!IsStream())
{
DMSG(0, "NormObject::NextServerMsg() ReadSegment() error\n"); DMSG(0, "NormObject::NextServerMsg() ReadSegment() error\n");
return false; return false;
} }
else if (static_cast<NormStreamObject*>(this)->IsOldBlock(blockId))
{
DMSG(3, "NormObject::NextServerMsg() node>%lu Warning! can't repair old stream segment\n", LocalNodeId());
block->UnsetPending(segmentId);
if (!block->IsPending())
{
// End of old block reached
block->ResetParityCount(nparity);
pending_mask.Unset(blockId);
// for EMCON sending, mark NORM_INFO for re-transmission, if applicable
if (session.SndrEmcon() && HaveInfo())
pending_info = true;
}
return NextServerMsg(msg);
}
else
{
// App hasn't written data for this block yet
return false;
}
}
data->SetPayloadLength(payloadLength); data->SetPayloadLength(payloadLength);
// Perform incremental FEC encoding as needed // Perform incremental FEC encoding as needed
@ -1746,14 +1778,14 @@ void NormStreamObject::StreamAdvance()
} }
else else
{ {
DMSG(4, "NormStreamObject::StreamAdvance() warning: node>%lu pending segment repairs (blk>%lu) " DMSG(3, "NormStreamObject::StreamAdvance() warning: node>%lu pending segment repairs (blk>%lu) "
"delaying stream advance ...\n", LocalNodeId(), (UINT32)block->GetId()); "delaying stream advance ...\n", LocalNodeId(), (UINT32)block->GetId());
} }
} }
} }
else else
{ {
DMSG(4, "NormStreamObject::StreamAdvance() warning: node>%lu pending block repair delaying stream advance ...\n", DMSG(3, "NormStreamObject::StreamAdvance() warning: node>%lu pending block repair delaying stream advance ...\n",
LocalNodeId()); LocalNodeId());
} }
} // end NormStreamObject::StreamAdvance() } // end NormStreamObject::StreamAdvance()
@ -2469,7 +2501,8 @@ bool NormStreamObject::LockBlocks(NormBlockId firstId, NormBlockId lastId)
NormBlock* block = stream_buffer.Find(nextId); NormBlock* block = stream_buffer.Find(nextId);
if (block) if (block)
{ {
block->SetPending(0, ndata); UINT16 numData = GetBlockSize(nextId);
block->SetPending(0, numData);
} }
else else
{ {
@ -2618,11 +2651,13 @@ UINT16 NormStreamObject::ReadSegment(NormBlockId blockId,
if (!block) if (!block)
{ {
//DMSG(0, "NormStreamObject::ReadSegment() stream starved (1)\n"); //DMSG(0, "NormStreamObject::ReadSegment() stream starved (1)\n");
if (!stream_buffer.IsEmpty() && (blockId < stream_buffer.RangeLo()))
DMSG(0, "NormStreamObject::ReadSegment() error: attempted to read old block> %lu\n", (UINT32)blockId);
return false; return false;
} }
// (TBD) should we check to see if "blockId > write_index.block" ? // (TBD) should we check to see if "blockId > write_index.block" ?
if ((blockId == write_index.block) && if ((blockId == write_index.block) && (segmentId >= write_index.segment))
(segmentId >= write_index.segment))
{ {
//DMSG(0, "NormStreamObject::ReadSegment(blk>%lu seg>%hu) stream starved (2) (write_index>%lu:%hu)\n", //DMSG(0, "NormStreamObject::ReadSegment(blk>%lu seg>%hu) stream starved (2) (write_index>%lu:%hu)\n",
// (UINT32)blockId, (UINT16)segmentId, (UINT32)write_index.block, (UINT16)write_index.segment); // (UINT32)blockId, (UINT16)segmentId, (UINT32)write_index.block, (UINT16)write_index.segment);
@ -2850,7 +2885,7 @@ void NormStreamObject::Prune(NormBlockId blockId, bool updateStatus)
{ {
bool resync = false; bool resync = false;
NormBlock* block; NormBlock* block;
while ((block = block_buffer.Find(block_buffer.RangeLo()))) while (NULL != (block = block_buffer.Find(block_buffer.RangeLo())))
{ {
if (block->GetId() < blockId) if (block->GetId() < blockId)
{ {
@ -3469,7 +3504,6 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
} }
else else
{ {
//if (0 != nBytes)
session.TouchServer(); session.TouchServer();
} }
return nBytes; return nBytes;

View File

@ -402,6 +402,9 @@ class NormStreamObject : public NormObject
void SetPushMode(bool state) {push_mode = state;} void SetPushMode(bool state) {push_mode = state;}
bool GetPushMode() const {return push_mode;} bool GetPushMode() const {return push_mode;}
bool IsOldBlock(NormBlockId blockId) const
{return (!stream_buffer.IsEmpty() && (blockId < stream_buffer.RangeLo()));}
bool IsClosing() {return stream_closing;} bool IsClosing() {return stream_closing;}
bool HasVacancy() bool HasVacancy()
{return (stream_closing ? false : write_vacancy);} {return (stream_closing ? false : write_vacancy);}

View File

@ -245,8 +245,8 @@ class NormBlock
int flags; int flags;
UINT16 erasure_count; UINT16 erasure_count;
UINT16 parity_count; UINT16 parity_count; // how many fresh parity we are currently planning to send
UINT16 parity_offset; UINT16 parity_offset; // offset from where our fresh parity will be sent
UINT16 seg_size_max; UINT16 seg_size_max;
ProtoBitmask pending_mask; ProtoBitmask pending_mask;

View File

@ -16,20 +16,22 @@ const UINT16 NormSession::DEFAULT_NPARITY = 32;
const UINT16 NormSession::DEFAULT_TX_CACHE_MIN = 8; const UINT16 NormSession::DEFAULT_TX_CACHE_MIN = 8;
const UINT16 NormSession::DEFAULT_TX_CACHE_MAX = 256; const UINT16 NormSession::DEFAULT_TX_CACHE_MAX = 256;
const int NormSession::DEFAULT_ROBUST_FACTOR = 20; // default robust factor
NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId) NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
: session_mgr(sessionMgr), notify_pending(false), tx_port(0), : session_mgr(sessionMgr), notify_pending(false), tx_port(0),
tx_socket_actual(ProtoSocket::UDP), tx_socket(&tx_socket_actual), tx_socket_actual(ProtoSocket::UDP), tx_socket(&tx_socket_actual),
rx_socket(ProtoSocket::UDP), local_node_id(localNodeId), rx_socket(ProtoSocket::UDP), local_node_id(localNodeId),
ttl(DEFAULT_TTL), tos(0), loopback(false), rx_port_reuse(false), rx_addr_bind(false), ttl(DEFAULT_TTL), tos(0), loopback(false), rx_port_reuse(false), rx_addr_bind(false),
tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0), tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0),
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0), backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false),
tx_robust_factor(DEFAULT_ROBUST_FACTOR), instance_id(0),
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0), ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0),
sndr_emcon(false), encoder(NULL), sndr_emcon(false), encoder(NULL),
next_tx_object_id(0), next_tx_object_id(0),
tx_cache_count_min(DEFAULT_TX_CACHE_MIN), tx_cache_count_min(DEFAULT_TX_CACHE_MIN),
tx_cache_count_max(DEFAULT_TX_CACHE_MAX), tx_cache_count_max(DEFAULT_TX_CACHE_MAX),
tx_cache_size_max((UINT32)20*1024*1024), tx_cache_size_max((UINT32)20*1024*1024),
flush_count(NORM_ROBUST_FACTOR+1),
posted_tx_queue_empty(false), posted_tx_queue_empty(false),
acking_node_count(0), watermark_pending(false), tx_repair_pending(false), advertise_repairs(false), acking_node_count(0), watermark_pending(false), tx_repair_pending(false), advertise_repairs(false),
suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0), suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0),
@ -41,7 +43,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
grtt_decrease_delay_count(DEFAULT_GRTT_DECREASE_DELAY), grtt_decrease_delay_count(DEFAULT_GRTT_DECREASE_DELAY),
grtt_response(false), grtt_current_peak(0.0), grtt_age(0.0), grtt_response(false), grtt_current_peak(0.0), grtt_age(0.0),
cc_enable(false), cc_sequence(0), cc_slow_start(true), cc_active(false), cc_enable(false), cc_sequence(0), cc_slow_start(true), cc_active(false),
is_client(false), unicast_nacks(false), is_client(false), rx_robust_factor(DEFAULT_ROBUST_FACTOR), unicast_nacks(false),
client_silent(false), rcvr_ignore_info(false), rcvr_max_delay(-1), client_silent(false), rcvr_ignore_info(false), rcvr_max_delay(-1),
default_repair_boundary(NormServerNode::BLOCK_BOUNDARY), default_repair_boundary(NormServerNode::BLOCK_BOUNDARY),
default_nacking_mode(NormObject::NACK_NORMAL), default_nacking_mode(NormObject::NACK_NORMAL),
@ -279,7 +281,6 @@ void NormSession::SetTxRateInternal(double txRate)
else else
{ {
tx_timer.Deactivate(); tx_timer.Deactivate();
} }
} }
else if ((0.0 == tx_rate) && IsOpen()) else if ((0.0 == tx_rate) && IsOpen())
@ -298,7 +299,6 @@ void NormSession::SetTxRateInternal(double txRate)
grtt_quantized = NormQuantizeRtt(grtt_measured); grtt_quantized = NormQuantizeRtt(grtt_measured);
grtt_advertised = NormUnquantizeRtt(grtt_quantized); grtt_advertised = NormUnquantizeRtt(grtt_quantized);
// What do we do when "pktInterval" > "grtt_max"? // What do we do when "pktInterval" > "grtt_max"?
// We will take our lumps with some extra activity timeout NACKs when they happen? // We will take our lumps with some extra activity timeout NACKs when they happen?
if (grtt_advertised > grtt_max) if (grtt_advertised > grtt_max)
@ -329,7 +329,6 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
rateMax = temp; rateMax = temp;
} }
} }
if (rateMin < 0.0) if (rateMin < 0.0)
tx_rate_min = -1.0; tx_rate_min = -1.0;
else if (rateMin < 8.0) else if (rateMin < 8.0)
@ -437,7 +436,8 @@ bool NormSession::StartServer(UINT16 instanceId,
ndata = numData; ndata = numData;
nparity = numParity; nparity = numParity;
is_server = true; is_server = true;
flush_count = NORM_ROBUST_FACTOR+1; // (TBD) parameterize robust_factor
flush_count = (GetTxRobustFactor() < 0) ? 0 : (GetTxRobustFactor() + 1);
if (cc_enable) if (cc_enable)
{ {
@ -560,7 +560,16 @@ void NormSession::Serve()
ASSERT(obj); ASSERT(obj);
} }
// (TBD) Work on this whole watermark flush check logic! // (TBD) code to support app-defined commands will go here
/*
if (command_pending && !command_timer.IsActive())
{
SenderQueueAppCommand() xxx
}
*/
if (watermark_pending && !flush_timer.IsActive()) if (watermark_pending && !flush_timer.IsActive())
{ {
// Determine next message (objectId::blockId::segmentId) to be sent // Determine next message (objectId::blockId::segmentId) to be sent
@ -621,47 +630,6 @@ void NormSession::Serve()
(UINT16)watermark_object_id, (UINT32)watermark_block_id, (UINT16)watermark_segment_id, (UINT16)watermark_object_id, (UINT32)watermark_block_id, (UINT16)watermark_segment_id,
(UINT16)nextObjectId, (UINT32)nextBlockId, (UINT16)nextSegmentId); (UINT16)nextObjectId, (UINT32)nextBlockId, (UINT16)nextSegmentId);
} }
/*
// Get index (objectId::blockId::segmentId) of next repair pending segment
// (This seems like alot of work to do for each call to NormSession::Serve(). Yuk!
// (well when a watermark is pending ... which could be alot of the time
// i.e. iterating through the tx_table, looking for repair pending objects ...
// (TBD) Is there a better way such as keeping state elsewhere on minimum
// pending repairs to save doing the work here?jo
NormObjectId repairObjectId = next_tx_object_id;
NormBlockId repairBlockId = 0;
NormSegmentId repairSegmentId = 0;
if (!ServerGetFirstRepairPending(repairObjectId))
repairObjectId = next_tx_object_id;
NormObjectTable::Iterator iterator(tx_table);
while ((nextObj = iterator.GetNextObject()))
{
if (repairObjectId < nextObj->GetId())
{
nextObj = tx_table.Find(repairObjectId);
break;
}
else if (nextObj->IsRepairPending())
{
repairObjectId = nextObj->GetId();
break;
}
}
if (nextObj) nextObj->FindRepairIndex(repairBlockId, repairSegmentId);
// Get min of next transmit pending or repair pending segment
if ((repairObjectId < nextObjectId) ||
((repairObjectId == nextObjectId) &&
((repairBlockId < nextBlockId) ||
((repairBlockId == nextBlockId) &&
(repairSegmentId < nextSegmentId)))))
{
nextObjectId = repairObjectId;
nextBlockId = repairBlockId;
nextSegmentId = repairSegmentId;
}
*/
} // end if (tx_repair_pending) } // end if (tx_repair_pending)
if ((nextObjectId > watermark_object_id) || if ((nextObjectId > watermark_object_id) ||
@ -670,6 +638,7 @@ void NormSession::Serve()
((nextBlockId == watermark_block_id) && ((nextBlockId == watermark_block_id) &&
(nextSegmentId > watermark_segment_id))))) (nextSegmentId > watermark_segment_id)))))
{ {
// The sender tx position is > watermark
if (ServerQueueWatermarkFlush()) if (ServerQueueWatermarkFlush())
{ {
watermark_active = true; watermark_active = true;
@ -684,6 +653,7 @@ void NormSession::Serve()
} }
else else
{ {
// The sender tx position is < watermark
// Reset non-acked acking nodes since server has rewound // Reset non-acked acking nodes since server has rewound
if (watermark_active) if (watermark_active)
{ {
@ -692,7 +662,7 @@ void NormSession::Serve()
NormAckingNode* next; NormAckingNode* next;
while ((next = static_cast<NormAckingNode*>(iterator.GetNextNode()))) while ((next = static_cast<NormAckingNode*>(iterator.GetNextNode())))
{ {
next->ResetReqCount(); next->ResetReqCount(GetTxRobustFactor());
} }
} }
} }
@ -749,11 +719,11 @@ void NormSession::Serve()
// Queue flush message // Queue flush message
if (!flush_timer.IsActive()) if (!flush_timer.IsActive())
{ {
if (flush_count < NORM_ROBUST_FACTOR) if ((GetTxRobustFactor() < 0) || (flush_count < GetTxRobustFactor()))
{ {
ServerQueueFlush(); ServerQueueFlush();
} }
else if (NORM_ROBUST_FACTOR == flush_count) else if (GetTxRobustFactor() == flush_count)
{ {
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n", DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
LocalNodeId()); LocalNodeId());
@ -768,8 +738,9 @@ void NormSession::Serve()
} }
} }
} }
//ASSERT(stream->IsPending() || stream->IsRepairPending()); //ASSERT(stream->IsPending() || stream->IsRepairPending() || stream->IsClosing());
if (!posted_tx_queue_empty && stream->IsPending() && !stream->IsClosing()) if (!posted_tx_queue_empty && !stream->IsClosing() && stream->IsPending())
// post if pending || !repair_timer.IsActive() || (repair_timer.GetRepeatCount() == 0) ???
{ {
//data_active = false; //data_active = false;
posted_tx_queue_empty = true; posted_tx_queue_empty = true;
@ -802,7 +773,7 @@ void NormSession::Serve()
// (TBD) Was session deleted? // (TBD) Was session deleted?
return; return;
} }
if (flush_count < NORM_ROBUST_FACTOR) if ((GetTxRobustFactor() < 0) || (flush_count < GetTxRobustFactor()))
{ {
// Queue flush message // Queue flush message
if (!tx_repair_pending) // don't queue flush if repair pending if (!tx_repair_pending) // don't queue flush if repair pending
@ -811,7 +782,7 @@ void NormSession::Serve()
DMSG(8, "NormSession::Serve() node>%lu NORM_CMD(FLUSH) deferred by pending repairs ...\n", DMSG(8, "NormSession::Serve() node>%lu NORM_CMD(FLUSH) deferred by pending repairs ...\n",
LocalNodeId()); LocalNodeId());
} }
else if (flush_count == NORM_ROBUST_FACTOR) else if (GetTxRobustFactor() == flush_count)
{ {
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n", DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
LocalNodeId()); LocalNodeId());
@ -836,11 +807,17 @@ void NormSession::ServerSetWatermark(NormObjectId objectId,
// Reset acking_node_list // Reset acking_node_list
NormNodeTreeIterator iterator(acking_node_tree); NormNodeTreeIterator iterator(acking_node_tree);
NormNode* next; NormNode* next;
int robustFactor = GetTxRobustFactor();
while ((next = iterator.GetNextNode())) while ((next = iterator.GetNextNode()))
static_cast<NormAckingNode*>(next)->Reset(NORM_ROBUST_FACTOR); static_cast<NormAckingNode*>(next)->Reset(robustFactor);
PromptServer(); PromptServer();
} // end Norm::ServerSetWatermark() } // end Norm::ServerSetWatermark()
void NormSession::ServerCancelWatermark()
{
watermark_pending = false;
} // end NormSession::ServerCancelWatermark()
bool NormSession::ServerAddAckingNode(NormNodeId nodeId) bool NormSession::ServerAddAckingNode(NormNodeId nodeId)
{ {
NormAckingNode* theNode = static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(nodeId)); NormAckingNode* theNode = static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(nodeId));
@ -849,7 +826,7 @@ bool NormSession::ServerAddAckingNode(NormNodeId nodeId)
theNode = new NormAckingNode(*this, nodeId); theNode = new NormAckingNode(*this, nodeId);
if (NULL != theNode) if (NULL != theNode)
{ {
theNode->Reset(NORM_ROBUST_FACTOR); theNode->Reset(GetTxRobustFactor());
acking_node_tree.AttachNode(theNode); acking_node_tree.AttachNode(theNode);
acking_node_count++; acking_node_count++;
return true; return true;
@ -990,7 +967,8 @@ bool NormSession::ServerQueueWatermarkFlush()
} }
if (watermark_pending) if (watermark_pending)
{ {
if (flush_count < NORM_ROBUST_FACTOR) flush_count++; if ((GetTxRobustFactor() < 0) || (flush_count < GetTxRobustFactor()))
flush_count++;
QueueMessage(flush); QueueMessage(flush);
DMSG(8, "NormSession::ServeQueueWatermarkFlush() node>%lu cmd queued ...\n", DMSG(8, "NormSession::ServeQueueWatermarkFlush() node>%lu cmd queued ...\n",
LocalNodeId()); LocalNodeId());
@ -1055,7 +1033,8 @@ void NormSession::ServerQueueFlush()
flush->SetFecBlockLen(obj->GetBlockSize(blockId)); flush->SetFecBlockLen(obj->GetBlockSize(blockId));
flush->SetFecSymbolId(segmentId); flush->SetFecSymbolId(segmentId);
QueueMessage(flush); QueueMessage(flush);
if (flush_count < NORM_ROBUST_FACTOR) flush_count++; if ((GetTxRobustFactor() < 0) || (flush_count < GetTxRobustFactor()))
flush_count++;
DMSG(4, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n", DMSG(4, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n",
LocalNodeId(), flush_count); LocalNodeId(), flush_count);
} }
@ -1077,7 +1056,8 @@ void NormSession::ServerQueueFlush()
// if all tx object state is gone ... // if all tx object state is gone ...
if (ServerQueueSquelch(next_tx_object_id)) if (ServerQueueSquelch(next_tx_object_id))
{ {
if (flush_count < NORM_ROBUST_FACTOR) flush_count++; if ((GetTxRobustFactor() < 0) || (flush_count < GetTxRobustFactor()))
flush_count++;
DMSG(4, "NormSession::ServerQueueFlush() node>%lu squelch queued (flush_count:%u)...\n", DMSG(4, "NormSession::ServerQueueFlush() node>%lu squelch queued (flush_count:%u)...\n",
LocalNodeId(), flush_count); LocalNodeId(), flush_count);
} }
@ -1290,7 +1270,7 @@ bool NormSession::QueueTxObject(NormObject* obj)
if (oldest->IsRepairPending() || oldest->IsPending()) if (oldest->IsRepairPending() || oldest->IsPending())
{ {
DMSG(0, "NormSession::QueueTxObject() all held objects repair pending\n"); DMSG(0, "NormSession::QueueTxObject() all held objects repair pending\n");
//posted_tx_queue_empty = false; posted_tx_queue_empty = false;
return false; return false;
} }
else else
@ -1493,9 +1473,11 @@ void NormSession::TxSocketRecvHandler(ProtoSocket& /*theSocket*/,
} }
} // end NormSession::TxSocketRecvHandler() } // end NormSession::TxSocketRecvHandler()
void NormSession::RxSocketRecvHandler(ProtoSocket& /*theSocket*/, void NormSession::RxSocketRecvHandler(ProtoSocket& /*theSocket*/,
ProtoSocket::Event /*theEvent*/) ProtoSocket::Event /*theEvent*/)
{ {
unsigned int recvCount = 0;
NormMsg msg; NormMsg msg;
unsigned int msgLength = NormMsg::MAX_SIZE; unsigned int msgLength = NormMsg::MAX_SIZE;
while (rx_socket.RecvFrom(msg.AccessBuffer(), while (rx_socket.RecvFrom(msg.AccessBuffer(),
@ -1511,6 +1493,14 @@ void NormSession::RxSocketRecvHandler(ProtoSocket& /*theSocket*/,
{ {
DMSG(0, "NormSession::RxSocketRecvHandler() warning: received bad message\n"); DMSG(0, "NormSession::RxSocketRecvHandler() warning: received bad message\n");
} }
// If our system gets very busy reading sockets, we should occasionally
// execute any timeouts to keep protocol operation smooth
if (++recvCount >= 100)
{
break;
//session_mgr.DoSystemTimeout();
//recvCount = 0;
}
} }
} // end NormSession::RxSocketRecvHandler() } // end NormSession::RxSocketRecvHandler()
@ -1639,8 +1629,7 @@ void NormTrace(const struct timeval& currentTime,
} }
case NormCmdMsg::CC: case NormCmdMsg::CC:
{ {
const NormCmdCCMsg& cc = const NormCmdCCMsg& cc = static_cast<const NormCmdCCMsg&>(msg);
static_cast<const NormCmdCCMsg&>(msg);
DMSG(0, " seq>%u ", cc.GetCCSequence()); DMSG(0, " seq>%u ", cc.GetCCSequence());
NormHeaderExtension ext; NormHeaderExtension ext;
while (cc.GetNextExtension(ext)) while (cc.GetNextExtension(ext))
@ -2584,7 +2573,7 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
{ {
// Resource constrained, move on to next repair request // Resource constrained, move on to next repair request
DMSG(2, "NormSession::ServerHandleNackMessage() node>%lu " DMSG(2, "NormSession::ServerHandleNackMessage() node>%lu "
"Warning - server is resource contrained ...\n"); "Warning - server is resource constrained ...\n");
} }
continue; continue;
} }
@ -3020,7 +3009,7 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/) bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
{ {
tx_repair_pending = false; tx_repair_pending = false;
if (repair_timer.GetRepeatCount()) if (0 != repair_timer.GetRepeatCount())
{ {
// NACK aggregation period has ended. (incorporate accumulated repair requests) // NACK aggregation period has ended. (incorporate accumulated repair requests)
DMSG(4, "NormSession::OnRepairTimeout() node>%lu server NACK aggregation time ended.\n", DMSG(4, "NormSession::OnRepairTimeout() node>%lu server NACK aggregation time ended.\n",
@ -3041,7 +3030,7 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
obj->TxReset(); obj->TxReset();
tx_repair_mask.Unset(objectId); tx_repair_mask.Unset(objectId);
if (!tx_pending_mask.Set(objectId)) if (!tx_pending_mask.Set(objectId))
DMSG(0, "NormSession::OnRepairTimeout() rx_pending_mask.Set(%hu) error (1)\n", DMSG(0, "NormSession::OnRepairTimeout() tx_pending_mask.Set(%hu) error (1)\n",
(UINT16)objectId); (UINT16)objectId);
} }
else else
@ -3053,7 +3042,7 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
DMSG(6, "NormSession::OnRepairTimeout() node>%lu activated obj>%hu repairs ...\n", DMSG(6, "NormSession::OnRepairTimeout() node>%lu activated obj>%hu repairs ...\n",
LocalNodeId(), (UINT16)objectId); LocalNodeId(), (UINT16)objectId);
if (!tx_pending_mask.Set(objectId)) if (!tx_pending_mask.Set(objectId))
DMSG(0, "NormSession::OnRepairTimeout() rx_pending_mask.Set(%hu) error (2)\n", DMSG(0, "NormSession::OnRepairTimeout() tx_pending_mask.Set(%hu) error (2)\n",
(UINT16)objectId); (UINT16)objectId);
} }
} }
@ -3067,7 +3056,6 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
repair_timer.SetInterval(holdoffInterval); // repair holdoff interval = 1*GRTT repair_timer.SetInterval(holdoffInterval); // repair holdoff interval = 1*GRTT
DMSG(4, "NormSession::OnRepairTimeout() node>%lu starting server " DMSG(4, "NormSession::OnRepairTimeout() node>%lu starting server "
"NACK holdoff timer (%lf sec)...\n", LocalNodeId(), holdoffInterval); "NACK holdoff timer (%lf sec)...\n", LocalNodeId(), holdoffInterval);
} }
else else
{ {
@ -3385,6 +3373,7 @@ void NormSession::SetGrttProbingMode(ProbingMode probingMode)
} }
} // end NormSession::SetGrttProbingMode() } // end NormSession::SetGrttProbingMode()
bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/) bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
{ {
// 1) Temporarily kill probe_timer if CMD(CC) not yet tx'd // 1) Temporarily kill probe_timer if CMD(CC) not yet tx'd
@ -3528,9 +3517,13 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
{ {
UINT8 ccFlags = 0; UINT8 ccFlags = 0;
if (next->IsClr()) if (next->IsClr())
{
ccFlags |= (UINT8)NormCC::CLR; ccFlags |= (UINT8)NormCC::CLR;
}
else if (next->IsPlr()) else if (next->IsPlr())
{
ccFlags |= (UINT8)NormCC::PLR; ccFlags |= (UINT8)NormCC::PLR;
}
ccFlags |= (UINT8)NormCC::RTT; ccFlags |= (UINT8)NormCC::RTT;
UINT8 rttQuantized = NormQuantizeRtt(next->GetRtt()); UINT8 rttQuantized = NormQuantizeRtt(next->GetRtt());
if (cc_slow_start) ccFlags |= (UINT8)NormCC::START; if (cc_slow_start) ccFlags |= (UINT8)NormCC::START;
@ -3542,24 +3535,26 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
rttQuantized, rttQuantized,
rateQuantized); rateQuantized);
//if (!next->IsClr()) next->SetActive(false); //if (!next->IsClr()) next->SetActive(false);
// Deactivate any nodes who have stopped providing feedback // "Deactivate" any nodes who have stopped providing feedback
struct timeval feedbackTime = next->GetFeedbackTime(); struct timeval feedbackTime = next->GetFeedbackTime();
double feedbackAge = currentTime.tv_sec - feedbackTime.tv_sec; double feedbackAge = currentTime.tv_sec - feedbackTime.tv_sec;
if (currentTime.tv_usec > feedbackTime.tv_usec) feedbackAge += 1.0e-06 * ((double)((currentTime.tv_usec - feedbackTime.tv_usec)));
/*if (currentTime.tv_usec > feedbackTime.tv_usec)
feedbackAge += 1.0e-06*((double)(currentTime.tv_usec - feedbackTime.tv_usec)); feedbackAge += 1.0e-06*((double)(currentTime.tv_usec - feedbackTime.tv_usec));
else else
feedbackAge -= 1.0e-06*((double)(feedbackTime.tv_usec - currentTime.tv_usec)); feedbackAge -= 1.0e-06*((double)(feedbackTime.tv_usec - currentTime.tv_usec));*/
double maxFeedbackAge = 5 * MAX(grtt_advertised, next->GetRtt()); double maxFeedbackAge = 5 * MAX(grtt_advertised, next->GetRtt());
// Safety bound to compensate for computer clock coarseness // Safety bound to compensate for computer clock coarseness
// and possible sluggish feedback from slower machines // and possible sluggish feedback from slower machines
// at higher norm data rates (keeps rate from being // at higher norm data rates (keeps rate from being
// prematurely reduced) // prematurely reduced)
if (maxFeedbackAge <(10*NORM_TICK_MIN)) if (maxFeedbackAge <(10*NORM_TICK_MIN)) maxFeedbackAge = (10*NORM_TICK_MIN);
maxFeedbackAge = (10*NORM_TICK_MIN); unsigned int ccSeqDelta = cc_sequence - next->GetCCSequence() - 2;
if (feedbackAge > maxFeedbackAge) if ((feedbackAge > maxFeedbackAge) && (ccSeqDelta > 5))
{ {
DMSG(6, "Deactivating cc node feedbackAge:%lf sec maxAge:%lf sec\n", DMSG(4, "Deactivating cc node feedbackAge:%lf sec maxAge:%lf sec ccSeqDelta:%u\n",
feedbackAge, maxFeedbackAge); feedbackAge, maxFeedbackAge, ccSeqDelta);
next->SetActive(false); next->SetActive(false);
} }
} }

View File

@ -73,6 +73,9 @@ class NormSessionMgr
ProtoTimerMgr& GetTimerMgr() const {return timer_mgr;} ProtoTimerMgr& GetTimerMgr() const {return timer_mgr;}
ProtoSocket::Notifier& GetSocketNotifier() const {return socket_notifier;} ProtoSocket::Notifier& GetSocketNotifier() const {return socket_notifier;}
void DoSystemTimeout()
{timer_mgr.DoSystemTimeout();}
NormController* GetController() const {return controller;} NormController* GetController() const {return controller;}
private: private:
ProtoTimerMgr& timer_mgr; ProtoTimerMgr& timer_mgr;
@ -103,6 +106,7 @@ class NormSession
static const UINT16 DEFAULT_NPARITY; static const UINT16 DEFAULT_NPARITY;
static const UINT16 DEFAULT_TX_CACHE_MIN; static const UINT16 DEFAULT_TX_CACHE_MIN;
static const UINT16 DEFAULT_TX_CACHE_MAX; static const UINT16 DEFAULT_TX_CACHE_MAX;
static const int DEFAULT_ROBUST_FACTOR;
enum ProbingMode {PROBE_NONE, PROBE_PASSIVE, PROBE_ACTIVE}; enum ProbingMode {PROBE_NONE, PROBE_PASSIVE, PROBE_ACTIVE};
enum AckingStatus enum AckingStatus
@ -235,11 +239,22 @@ class NormSession
void ServerSetWatermark(NormObjectId objectId, void ServerSetWatermark(NormObjectId objectId,
NormBlockId blockId, NormBlockId blockId,
NormSegmentId segmentId); NormSegmentId segmentId);
void ServerCancelWatermark();
bool ServerAddAckingNode(NormNodeId nodeId); bool ServerAddAckingNode(NormNodeId nodeId);
void ServerRemoveAckingNode(NormNodeId nodeId); void ServerRemoveAckingNode(NormNodeId nodeId);
AckingStatus ServerGetAckingStatus(NormNodeId nodeId); AckingStatus ServerGetAckingStatus(NormNodeId nodeId);
// robust factor
void SetTxRobustFactor(int value)
{tx_robust_factor = value;}
int GetTxRobustFactor() const
{return tx_robust_factor;}
void SetRxRobustFactor(int value)
{rx_robust_factor = value;}
int GetRxRobustFactor() const
{return rx_robust_factor;}
UINT16 ServerSegmentSize() const {return segment_size;} UINT16 ServerSegmentSize() const {return segment_size;}
UINT16 ServerBlockSize() const {return ndata;} UINT16 ServerBlockSize() const {return ndata;}
UINT16 ServerNumParity() const {return nparity;} UINT16 ServerNumParity() const {return nparity;}
@ -449,6 +464,7 @@ class NormSession
// Server parameters and state // Server parameters and state
bool is_server; bool is_server;
int tx_robust_factor;
UINT16 instance_id; UINT16 instance_id;
UINT16 segment_size; UINT16 segment_size;
UINT16 ndata; UINT16 ndata;
@ -528,6 +544,7 @@ class NormSession
// Receiver parameters // Receiver parameters
bool is_client; bool is_client;
int rx_robust_factor;
NormNodeTree server_tree; NormNodeTree server_tree;
unsigned long remote_server_buffer_size; unsigned long remote_server_buffer_size;
bool unicast_nacks; bool unicast_nacks;

View File

@ -81,7 +81,7 @@ NormThreadApp::NormThreadApp()
tx_msg_length(0), tx_msg_index(0) tx_msg_length(0), tx_msg_index(0)
{ {
tx_msg_timer.SetListener(this, &NormThreadApp::OnTxTimeout); tx_msg_timer.SetListener(this, &NormThreadApp::OnTxTimeout);
tx_msg_timer.SetInterval(0.0015); tx_msg_timer.SetInterval(0.00001);
tx_msg_timer.SetRepeat(-1); tx_msg_timer.SetRepeat(-1);
worker_thread_dispatcher.SetPromptCallback(DoWorkerEvent, this); worker_thread_dispatcher.SetPromptCallback(DoWorkerEvent, this);
@ -107,7 +107,7 @@ bool NormThreadApp::OnStartup(int argc, const char*const* argv)
norm_instance = NormCreateInstance(); norm_instance = NormCreateInstance();
ASSERT(NORM_INSTANCE_INVALID != norm_instance); ASSERT(NORM_INSTANCE_INVALID != norm_instance);
SetDebugLevel(2); SetDebugLevel(3);
// Set a callback that will call NormGetNextEvent() // Set a callback that will call NormGetNextEvent()
if (!dispatcher.InstallGenericInput(NormGetDescriptor(norm_instance), DoNormEvent, this)) if (!dispatcher.InstallGenericInput(NormGetDescriptor(norm_instance), DoNormEvent, this))
@ -157,9 +157,24 @@ bool NormThreadApp::OnStartup(int argc, const char*const* argv)
localId); localId);
ASSERT(NORM_SESSION_INVALID != norm_session); ASSERT(NORM_SESSION_INVALID != norm_session);
if(!NormSetMulticastInterface(norm_session,"eth0"))
{
fprintf(stderr, "normTest: Unable to set multicast interface to \"eth0\"\n");
//return false;
}
NormSetGrttEstimate(norm_session, 0.250); // 1 msec initial grtt NormSetGrttEstimate(norm_session, 0.250); // 1 msec initial grtt
NormSetTransmitRate(norm_session, 10.0e+06); // in bits/second NormSetTransmitRate(norm_session, 80.0e+06); // in bits/second
NormSetTransmitRateBounds(norm_session, 10.0e+06, 10.0e+06);
NormSetCongestionControl(norm_session, true);
NormSetTxLoss(norm_session, 2.0);
//NormSetMessageTrace(norm_session, true);
//NormSetLoopback(norm_session, true); //NormSetLoopback(norm_session, true);
@ -169,8 +184,8 @@ bool NormThreadApp::OnStartup(int argc, const char*const* argv)
{ {
NormSessionId sessionId = (NormSessionId)rand(); NormSessionId sessionId = (NormSessionId)rand();
//NormStartSender(norm_session, sessionId, 1024*1024, 1400, 64, 8); //NormStartSender(norm_session, sessionId, 1024*1024, 1400, 64, 8);
NormStartSender(norm_session, sessionId, 1024*1024, 1400, 64, 0); NormStartSender(norm_session, sessionId, 2000000, 1400, 64, 8);
norm_tx_stream = NormStreamOpen(norm_session, 1024*1024); norm_tx_stream = NormStreamOpen(norm_session, 1800000);
// Activate tx timer and force first message transmission // Activate tx timer and force first message transmission
ActivateTimer(tx_msg_timer); ActivateTimer(tx_msg_timer);
@ -181,9 +196,8 @@ bool NormThreadApp::OnStartup(int argc, const char*const* argv)
// 6) If receiver, start receiver // 6) If receiver, start receiver
if (receiver) if (receiver)
{ {
NormStartReceiver(norm_session, 1024*1024);
worker_thread_dispatcher.StartThread(); worker_thread_dispatcher.StartThread();
NormStartReceiver(norm_session, 2000000);
} }
return true; return true;
@ -207,6 +221,8 @@ void NormThreadApp::OnShutdown()
bool NormThreadApp::OnTxTimeout(ProtoTimer& /*timer*/) bool NormThreadApp::OnTxTimeout(ProtoTimer& /*timer*/)
{ {
//TRACE("enter NormThreadApp::OnTxTimeout() ...\n"); //TRACE("enter NormThreadApp::OnTxTimeout() ...\n");
while (1)
{
if (0 == tx_msg_length) if (0 == tx_msg_length)
{ {
// Send a new message // Send a new message
@ -229,9 +245,15 @@ bool NormThreadApp::OnTxTimeout(ProtoTimer& /*timer*/)
} }
else else
{ {
if (0 == bytesWritten)
{
TRACE("ZERO bytes written\n");
}
// We filled the stream buffer // We filled the stream buffer
tx_msg_index += bytesWritten; tx_msg_index += bytesWritten;
tx_msg_timer.Deactivate(); if (tx_msg_timer.IsActive()) tx_msg_timer.Deactivate();
break;
}
} }
return true; return true;
} // end NormThreadApp::OnTxTimeout() } // end NormThreadApp::OnTxTimeout()
@ -261,7 +283,7 @@ void NormThreadApp::OnNormEvent()
TRACE("NORM_TX_QUEUE_EMPTY ...\n");*/ TRACE("NORM_TX_QUEUE_EMPTY ...\n");*/
if (!tx_msg_timer.IsActive()) if (!tx_msg_timer.IsActive())
{ {
ActivateTimer(tx_msg_timer); //ActivateTimer(tx_msg_timer);
OnTxTimeout(tx_msg_timer); OnTxTimeout(tx_msg_timer);
} }
break; break;
@ -269,6 +291,14 @@ void NormThreadApp::OnNormEvent()
case NORM_GRTT_UPDATED: case NORM_GRTT_UPDATED:
break; break;
case NORM_CC_ACTIVE:
TRACE("NORM_CC_ACTIVE ...\n");
break;
case NORM_CC_INACTIVE:
TRACE("NORM_CC_INACTIVE ...\n");
break;
case NORM_REMOTE_SENDER_NEW: case NORM_REMOTE_SENDER_NEW:
case NORM_REMOTE_SENDER_ACTIVE: case NORM_REMOTE_SENDER_ACTIVE:
break; break;
@ -281,7 +311,7 @@ void NormThreadApp::OnNormEvent()
case NORM_RX_OBJECT_UPDATED: case NORM_RX_OBJECT_UPDATED:
//TRACE("NORM_RX_OBJECT_UPDATED ...\n"); //TRACE("NORM_RX_OBJECT_UPDATED ...\n");
updateCount++; updateCount++;
if ((updateCount % 100) == 0) if ((updateCount % 1000) == 0)
TRACE("updateCount:%lu\n", updateCount); TRACE("updateCount:%lu\n", updateCount);
worker_thread_dispatcher.PromptThread(); worker_thread_dispatcher.PromptThread();
break; break;
@ -321,7 +351,7 @@ void NormThreadApp::WorkerReadStream()
if (0 != bytesRead) if (0 != bytesRead)
{ {
readCount++; readCount++;
if ((readCount % 100) == 0) if ((readCount % 1000) == 0)
TRACE("readCount:%lu\n", readCount); TRACE("readCount:%lu\n", readCount);
bytesRead = 1400; bytesRead = 1400;
} }