v1.1b6
parent
25676f4b00
commit
4244ba41d1
|
|
@ -928,7 +928,7 @@ void NormApp::Notify(NormController::Event event,
|
||||||
if (silent_client)
|
if (silent_client)
|
||||||
size = NormObjectSize((UINT32)rx_buffer_size);
|
size = NormObjectSize((UINT32)rx_buffer_size);
|
||||||
else
|
else
|
||||||
size = object->Size();
|
size = object->GetSize();
|
||||||
|
|
||||||
if (((NormStreamObject*)object)->Accept(size.LSB()))
|
if (((NormStreamObject*)object)->Accept(size.LSB()))
|
||||||
{
|
{
|
||||||
|
|
@ -993,7 +993,7 @@ void NormApp::Notify(NormController::Event event,
|
||||||
strncpy(fileName, rx_cache_path, PATH_MAX);
|
strncpy(fileName, rx_cache_path, PATH_MAX);
|
||||||
UINT16 pathLen = strlen(rx_cache_path);
|
UINT16 pathLen = strlen(rx_cache_path);
|
||||||
pathLen = MIN(pathLen, PATH_MAX);
|
pathLen = MIN(pathLen, PATH_MAX);
|
||||||
UINT16 len = object->InfoLength();
|
UINT16 len = object->GetInfoLength();
|
||||||
len = MIN(len, (PATH_MAX - pathLen));
|
len = MIN(len, (PATH_MAX - pathLen));
|
||||||
strncat(fileName, object->GetInfo(), len);
|
strncat(fileName, object->GetInfo(), len);
|
||||||
// Convert '/' in file info to directory delimiters
|
// Convert '/' in file info to directory delimiters
|
||||||
|
|
|
||||||
|
|
@ -262,49 +262,51 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
|
||||||
{
|
{
|
||||||
is_clr = is_plr = false;
|
is_clr = is_plr = false;
|
||||||
}
|
}
|
||||||
if (is_clr || is_plr)
|
double maxBackoff;
|
||||||
|
if (is_clr || is_plr || !session->Address().IsMulticast())
|
||||||
{
|
{
|
||||||
// Respond immediately
|
// Respond immediately
|
||||||
|
maxBackoff = 0.0;
|
||||||
if (cc_timer.IsActive()) cc_timer.Deactivate();
|
if (cc_timer.IsActive()) cc_timer.Deactivate();
|
||||||
cc_timer.ResetRepeat();
|
|
||||||
OnCCTimeout(cc_timer);
|
|
||||||
}
|
}
|
||||||
else if (!cc_timer.IsActive())
|
else
|
||||||
{
|
{
|
||||||
|
if (cc_timer.IsActive()) break;
|
||||||
double backoffFactor = backoff_factor;
|
double backoffFactor = backoff_factor;
|
||||||
backoffFactor = MAX(backoffFactor, 4.0);
|
backoffFactor = MAX(backoffFactor, 4.0);
|
||||||
double maxBackoff = grtt_estimate*backoffFactor;
|
maxBackoff = grtt_estimate*backoffFactor;
|
||||||
// (TBD) don't backoff for unicast sessions
|
|
||||||
double backoffTime = (maxBackoff > 0.0) ?
|
|
||||||
ExponentialRand(maxBackoff, gsize_estimate) : 0.0;
|
|
||||||
// Bias backoff timeout based on our rate
|
|
||||||
double r;
|
|
||||||
if (slow_start)
|
|
||||||
{
|
|
||||||
r = recv_rate / send_rate;
|
|
||||||
cc_rate = 2.0 * recv_rate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cc_rate = NormSession::CalculateRate(nominal_packet_size,
|
|
||||||
rtt_estimate,
|
|
||||||
LossEstimate());
|
|
||||||
r = cc_rate / send_rate;
|
|
||||||
r = MIN(r, 0.9);
|
|
||||||
r = MAX(r, 0.5);
|
|
||||||
r = (r - 0.5) / 0.4;
|
|
||||||
}
|
|
||||||
//TRACE("NormServerNode::HandleCommand(CC) node>%lu bias:%lf recv_rate:%lf send_rate:%lf "
|
|
||||||
// "grtt:%lf gsize:%lf\n",
|
|
||||||
// LocalNodeId(), r, recv_rate*(8.0/1000.0), send_rate*(8.0/1000.0),
|
|
||||||
//
|
|
||||||
|
|
||||||
backoffTime = 0.25 * r * maxBackoff + 0.75 * backoffTime;
|
|
||||||
cc_timer.SetInterval(backoffTime);
|
|
||||||
DMSG(4, "NormServerNode::HandleCommand() node>%lu begin CC back-off: %lf sec)...\n",
|
|
||||||
LocalNodeId(), backoffTime);
|
|
||||||
session->ActivateTimer(cc_timer);
|
|
||||||
}
|
}
|
||||||
|
double backoffTime = (maxBackoff > 0.0) ?
|
||||||
|
ExponentialRand(maxBackoff, gsize_estimate) :
|
||||||
|
0.0;
|
||||||
|
// Bias backoff timeout based on our rate
|
||||||
|
double r;
|
||||||
|
if (slow_start)
|
||||||
|
{
|
||||||
|
r = recv_rate / send_rate;
|
||||||
|
cc_rate = 2.0 * recv_rate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cc_rate = NormSession::CalculateRate(nominal_packet_size,
|
||||||
|
rtt_estimate,
|
||||||
|
LossEstimate());
|
||||||
|
r = cc_rate / send_rate;
|
||||||
|
r = MIN(r, 0.9);
|
||||||
|
r = MAX(r, 0.5);
|
||||||
|
r = (r - 0.5) / 0.4;
|
||||||
|
}
|
||||||
|
//DMSG(0, "NormServerNode::HandleCommand(CC) node>%lu bias:%lf recv_rate:%lf send_rate:%lf "
|
||||||
|
// "grtt:%lf gsize:%lf\n",
|
||||||
|
// LocalNodeId(), r, recv_rate*(8.0/1000.0), send_rate*(8.0/1000.0),
|
||||||
|
//
|
||||||
|
|
||||||
|
backoffTime = 0.25 * r * maxBackoff + 0.75 * backoffTime;
|
||||||
|
cc_timer.SetInterval(backoffTime);
|
||||||
|
DMSG(6, "NormServerNode::HandleCommand() node>%lu begin CC back-off: %lf sec)...\n",
|
||||||
|
LocalNodeId(), backoffTime);
|
||||||
|
session->ActivateTimer(cc_timer);
|
||||||
} // end if (CC_RATE == ext.GetType())
|
} // end if (CC_RATE == ext.GetType())
|
||||||
} // end while (GetNextExtension())
|
} // end while (GetNextExtension())
|
||||||
break;
|
break;
|
||||||
|
|
@ -598,7 +600,7 @@ void NormServerNode::DeleteObject(NormObject* obj)
|
||||||
// (TBD) Notify app of object's closing/demise?
|
// (TBD) Notify app of object's closing/demise?
|
||||||
obj->Close();
|
obj->Close();
|
||||||
rx_table.Remove(obj);
|
rx_table.Remove(obj);
|
||||||
rx_pending_mask.Unset(obj->Id());
|
rx_pending_mask.Unset(obj->GetId());
|
||||||
delete obj;
|
delete obj;
|
||||||
} // end NormServerNode::DeleteObject()
|
} // end NormServerNode::DeleteObject()
|
||||||
|
|
||||||
|
|
@ -615,13 +617,13 @@ NormBlock* NormServerNode::GetFreeBlock(NormObjectId objectId, NormBlockId block
|
||||||
NormObject* obj;
|
NormObject* obj;
|
||||||
while ((obj = iterator.GetNextObject()))
|
while ((obj = iterator.GetNextObject()))
|
||||||
{
|
{
|
||||||
if (obj->Id() > objectId)
|
if (obj->GetId() > objectId)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (obj->Id() < objectId)
|
if (obj->GetId() < objectId)
|
||||||
b = obj->StealOldestBlock(false);
|
b = obj->StealOldestBlock(false);
|
||||||
else
|
else
|
||||||
b = obj->StealOldestBlock(true, blockId);
|
b = obj->StealOldestBlock(true, blockId);
|
||||||
|
|
@ -640,13 +642,13 @@ NormBlock* NormServerNode::GetFreeBlock(NormObjectId objectId, NormBlockId block
|
||||||
NormObject* obj;
|
NormObject* obj;
|
||||||
while ((obj = iterator.GetPrevObject()))
|
while ((obj = iterator.GetPrevObject()))
|
||||||
{
|
{
|
||||||
if (obj->Id() < objectId)
|
if (obj->GetId() < objectId)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (obj->Id() > objectId)
|
if (obj->GetId() > objectId)
|
||||||
b = obj->StealNewestBlock(false);
|
b = obj->StealNewestBlock(false);
|
||||||
else
|
else
|
||||||
b = obj->StealNewestBlock(true, blockId);
|
b = obj->StealNewestBlock(true, blockId);
|
||||||
|
|
@ -930,7 +932,7 @@ void NormServerNode::Sync(NormObjectId objectId)
|
||||||
{
|
{
|
||||||
NormObject* obj;
|
NormObject* obj;
|
||||||
while ((obj = rx_table.Find(rx_table.RangeLo())) &&
|
while ((obj = rx_table.Find(rx_table.RangeLo())) &&
|
||||||
(obj->Id() < objectId))
|
(obj->GetId() < objectId))
|
||||||
{
|
{
|
||||||
DeleteObject(obj);
|
DeleteObject(obj);
|
||||||
failure_count++;
|
failure_count++;
|
||||||
|
|
@ -1367,28 +1369,30 @@ bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/)
|
||||||
|
|
||||||
void NormServerNode::UpdateRecvRate(const struct timeval& currentTime, unsigned short msgSize)
|
void NormServerNode::UpdateRecvRate(const struct timeval& currentTime, unsigned short msgSize)
|
||||||
{
|
{
|
||||||
double interval;
|
|
||||||
if (prev_update_time.tv_sec || prev_update_time.tv_usec)
|
if (prev_update_time.tv_sec || prev_update_time.tv_usec)
|
||||||
{
|
{
|
||||||
interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec);
|
double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec);
|
||||||
if (currentTime.tv_usec > prev_update_time.tv_sec)
|
if (currentTime.tv_usec > prev_update_time.tv_sec)
|
||||||
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec);
|
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec);
|
||||||
else
|
else
|
||||||
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
|
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
recv_rate = ((double)msgSize) / grtt_estimate;
|
|
||||||
interval = 0.0;
|
|
||||||
prev_update_time = currentTime;
|
|
||||||
}
|
|
||||||
if (interval < grtt_estimate)
|
|
||||||
{
|
|
||||||
recv_accumulator += msgSize;
|
recv_accumulator += msgSize;
|
||||||
}
|
|
||||||
|
double rttEstimate = rtt_confirmed ? rtt_estimate : grtt_estimate;
|
||||||
|
|
||||||
|
if (interval >= rttEstimate)
|
||||||
|
{
|
||||||
|
recv_rate = ((double)(recv_accumulator)) / interval;
|
||||||
|
prev_update_time = currentTime;
|
||||||
|
recv_accumulator = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
recv_rate = ((double)(recv_accumulator+msgSize)) / interval;
|
if (send_rate > 0.0)
|
||||||
|
recv_rate = send_rate;
|
||||||
|
else
|
||||||
|
recv_rate = ((double)msgSize) / grtt_estimate;
|
||||||
prev_update_time = currentTime;
|
prev_update_time = currentTime;
|
||||||
recv_accumulator = 0;
|
recv_accumulator = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1497,7 +1501,7 @@ bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/)
|
||||||
rtt_estimate, ccLoss);
|
rtt_estimate, ccLoss);
|
||||||
ext.SetCCRate(NormQuantizeRate(ccRate));
|
ext.SetCCRate(NormQuantizeRate(ccRate));
|
||||||
}
|
}
|
||||||
//TRACE("NormServerNode::OnCCTimeout() node>%lu sending ACK rate:%lf kbps (rtt:%lf loss:%lf s:%lf recvRate:%lf) slow_start:%d\n",
|
//DMSG(0, "NormServerNode::OnCCTimeout() node>%lu sending ACK rate:%lf kbps (rtt:%lf loss:%lf s:%lf recvRate:%lf) slow_start:%d\n",
|
||||||
// LocalNodeId(), NormUnquantizeRate(ext.GetCCRate()) * (8.0/1000.0),
|
// LocalNodeId(), NormUnquantizeRate(ext.GetCCRate()) * (8.0/1000.0),
|
||||||
// rtt_estimate, ccLoss, nominal_packet_size, recv_rate*(8.0/1000.), slow_start);
|
// rtt_estimate, ccLoss, nominal_packet_size, recv_rate*(8.0/1000.), slow_start);
|
||||||
ext.SetCCSequence(cc_sequence);
|
ext.SetCCSequence(cc_sequence);
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
NormObject::NormObject(NormObject::Type theType,
|
NormObject::NormObject(NormObject::Type theType,
|
||||||
class NormSession* theSession,
|
class NormSession* theSession,
|
||||||
class NormServerNode* theServer,
|
class NormServerNode* theServer,
|
||||||
const NormObjectId& objectId)
|
const NormObjectId& transportId)
|
||||||
: type(theType), session(theSession), server(theServer),
|
: type(theType), session(theSession), server(theServer),
|
||||||
id(objectId), segment_size(0), pending_info(false), repair_info(false),
|
transport_id(transportId), segment_size(0), pending_info(false), repair_info(false),
|
||||||
current_block_id(0), next_segment_id(0),
|
current_block_id(0), next_segment_id(0),
|
||||||
max_pending_block(0), max_pending_segment(0),
|
max_pending_block(0), max_pending_segment(0),
|
||||||
info(NULL), info_len(0), accepted(false)
|
info(NULL), info_len(0), accepted(false)
|
||||||
|
|
@ -35,8 +35,6 @@ NormNodeId NormObject::LocalNodeId() const
|
||||||
return session->LocalNodeId();
|
return session->LocalNodeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool NormObject::Open(const NormObjectSize& objectSize,
|
bool NormObject::Open(const NormObjectSize& objectSize,
|
||||||
const char* infoPtr,
|
const char* infoPtr,
|
||||||
UINT16 infoLen)
|
UINT16 infoLen)
|
||||||
|
|
@ -248,7 +246,7 @@ bool NormObject::TxReset(NormBlockId firstBlock)
|
||||||
NormBlock* block;
|
NormBlock* block;
|
||||||
while ((block = iterator.GetNextBlock()))
|
while ((block = iterator.GetNextBlock()))
|
||||||
{
|
{
|
||||||
NormBlockId blockId = block->Id();
|
NormBlockId blockId = block->GetId();
|
||||||
if (blockId >= firstBlock)
|
if (blockId >= firstBlock)
|
||||||
{
|
{
|
||||||
increasedRepair |= block->TxReset(GetBlockSize(blockId),
|
increasedRepair |= block->TxReset(GetBlockSize(blockId),
|
||||||
|
|
@ -274,7 +272,7 @@ bool NormObject::TxResetBlocks(NormBlockId nextId, NormBlockId lastId)
|
||||||
}
|
}
|
||||||
NormBlock* block = block_buffer.Find(nextId);
|
NormBlock* block = block_buffer.Find(nextId);
|
||||||
if (block)
|
if (block)
|
||||||
increasedRepair |= block->TxReset(GetBlockSize(block->Id()), nparity, autoParity, segment_size);
|
increasedRepair |= block->TxReset(GetBlockSize(block->GetId()), nparity, autoParity, segment_size);
|
||||||
nextId++;
|
nextId++;
|
||||||
}
|
}
|
||||||
return increasedRepair;
|
return increasedRepair;
|
||||||
|
|
@ -297,7 +295,7 @@ bool NormObject::ActivateRepairs()
|
||||||
NormBlockId lastId;
|
NormBlockId lastId;
|
||||||
ASSERT(GetLastRepair(lastId));
|
ASSERT(GetLastRepair(lastId));
|
||||||
DMSG(6, "NormObject::ActivateRepairs() node>%lu obj>%hu activating blk>%lu->%lu repairs\n",
|
DMSG(6, "NormObject::ActivateRepairs() node>%lu obj>%hu activating blk>%lu->%lu repairs\n",
|
||||||
LocalNodeId(), (UINT16)id, (UINT32)nextId, (UINT32)lastId);
|
LocalNodeId(), (UINT16)transport_id, (UINT32)nextId, (UINT32)lastId);
|
||||||
repairsActivated = true;
|
repairsActivated = true;
|
||||||
UINT16 autoParity = session->ServerAutoParity();
|
UINT16 autoParity = session->ServerAutoParity();
|
||||||
do
|
do
|
||||||
|
|
@ -320,10 +318,10 @@ bool NormObject::ActivateRepairs()
|
||||||
{
|
{
|
||||||
repairsActivated = true;
|
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)id, (UINT32)block->Id());
|
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->Id()))
|
if (!pending_mask.Set(block->GetId()))
|
||||||
DMSG(0, "NormObject::ActivateRepairs() pending_mask.Set(%lu) error!\n", (UINT32)block->Id());
|
DMSG(0, "NormObject::ActivateRepairs() pending_mask.Set(%lu) error!\n", (UINT32)block->GetId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return repairsActivated;
|
return repairsActivated;
|
||||||
|
|
@ -408,13 +406,13 @@ bool NormObject::AppendRepairAdv(NormCmdRepairAdvMsg& cmd)
|
||||||
ASSERT(0); // can't happen
|
ASSERT(0); // can't happen
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::ITEMS:
|
case NormRepairRequest::ITEMS:
|
||||||
req.AppendRepairItem(id, firstId, ndata, 0);
|
req.AppendRepairItem(transport_id, firstId, GetBlockSize(firstId), 0);
|
||||||
if (2 == blockCount)
|
if (2 == blockCount)
|
||||||
req.AppendRepairItem(id, currentId, ndata, 0);
|
req.AppendRepairItem(transport_id, currentId, GetBlockSize(currentId), 0);
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::RANGES:
|
case NormRepairRequest::RANGES:
|
||||||
req.AppendRepairRange(id, firstId, ndata, 0,
|
req.AppendRepairRange(transport_id, firstId, GetBlockSize(firstId), 0,
|
||||||
id, currentId, ndata, 0);
|
transport_id, currentId, GetBlockSize(currentId), 0);
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::ERASURES:
|
case NormRepairRequest::ERASURES:
|
||||||
// erasure counts not used
|
// erasure counts not used
|
||||||
|
|
@ -432,7 +430,7 @@ bool NormObject::AppendRepairAdv(NormCmdRepairAdvMsg& cmd)
|
||||||
cmd.PackRepairRequest(req); // (TBD) error check
|
cmd.PackRepairRequest(req); // (TBD) error check
|
||||||
prevForm = NormRepairRequest::INVALID;
|
prevForm = NormRepairRequest::INVALID;
|
||||||
}
|
}
|
||||||
block->AppendRepairAdv(cmd, id, repair_info, ndata, segment_size); // (TBD) error check
|
block->AppendRepairAdv(cmd, transport_id, repair_info, GetBlockSize(currentId), segment_size); // (TBD) error check
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end while(nextId < endId)
|
} // end while(nextId < endId)
|
||||||
|
|
@ -736,7 +734,7 @@ bool NormObject::AppendRepairRequest(NormNackMsg& nack,
|
||||||
NormBlockId lastId;
|
NormBlockId lastId;
|
||||||
ASSERT(GetLastPending(lastId));
|
ASSERT(GetLastPending(lastId));
|
||||||
DMSG(6, "NormObject::AppendRepairRequest() node>%lu obj>%hu, blk>%lu->%lu (maxPending:%lu)\n",
|
DMSG(6, "NormObject::AppendRepairRequest() node>%lu obj>%hu, blk>%lu->%lu (maxPending:%lu)\n",
|
||||||
LocalNodeId(), (UINT16)id,
|
LocalNodeId(), (UINT16)transport_id,
|
||||||
(UINT32)nextId, (UINT32)lastId, (UINT32)max_pending_block);
|
(UINT32)nextId, (UINT32)lastId, (UINT32)max_pending_block);
|
||||||
bool appendRequest = false;
|
bool appendRequest = false;
|
||||||
NormBlock* block = iterating ? block_buffer.Find(nextId) : NULL;
|
NormBlock* block = iterating ? block_buffer.Find(nextId) : NULL;
|
||||||
|
|
@ -783,18 +781,18 @@ bool NormObject::AppendRepairRequest(NormNackMsg& nack,
|
||||||
switch (nextForm)
|
switch (nextForm)
|
||||||
{
|
{
|
||||||
case NormRepairRequest::ITEMS:
|
case NormRepairRequest::ITEMS:
|
||||||
req.AppendRepairItem(id, prevId, GetBlockSize(prevId), 0); // (TBD) error check
|
req.AppendRepairItem(transport_id, prevId, GetBlockSize(prevId), 0); // (TBD) error check
|
||||||
if (2 == consecutiveCount)
|
if (2 == consecutiveCount)
|
||||||
{
|
{
|
||||||
prevId++;
|
prevId++;
|
||||||
req.AppendRepairItem(id, prevId, GetBlockSize(prevId), 0); // (TBD) error check
|
req.AppendRepairItem(transport_id, prevId, GetBlockSize(prevId), 0); // (TBD) error check
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::RANGES:
|
case NormRepairRequest::RANGES:
|
||||||
{
|
{
|
||||||
NormBlockId lastId = prevId+consecutiveCount-1;
|
NormBlockId lastId = prevId+consecutiveCount-1;
|
||||||
req.AppendRepairRange(id, prevId, GetBlockSize(prevId), 0,
|
req.AppendRepairRange(transport_id, prevId, GetBlockSize(prevId), 0,
|
||||||
id, lastId, GetBlockSize(lastId), 0); // (TBD) error check
|
transport_id, lastId, GetBlockSize(lastId), 0); // (TBD) error check
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -820,16 +818,16 @@ bool NormObject::AppendRepairRequest(NormNackMsg& nack,
|
||||||
nack.PackRepairRequest(req); // (TBD) error check
|
nack.PackRepairRequest(req); // (TBD) error check
|
||||||
if (flush || (nextId != max_pending_block))
|
if (flush || (nextId != max_pending_block))
|
||||||
{
|
{
|
||||||
block->AppendRepairRequest(nack, numData, nparity, id,
|
block->AppendRepairRequest(nack, numData, nparity, transport_id,
|
||||||
pending_info, segment_size); // (TBD) error check
|
pending_info, segment_size); // (TBD) error check
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (max_pending_segment < numData)
|
if (max_pending_segment < numData)
|
||||||
block->AppendRepairRequest(nack, max_pending_segment, 0, id,
|
block->AppendRepairRequest(nack, max_pending_segment, 0, transport_id,
|
||||||
pending_info, segment_size); // (TBD) error check
|
pending_info, segment_size); // (TBD) error check
|
||||||
else
|
else
|
||||||
block->AppendRepairRequest(nack, numData, nparity, id,
|
block->AppendRepairRequest(nack, numData, nparity, transport_id,
|
||||||
pending_info, segment_size); // (TBD) error check
|
pending_info, segment_size); // (TBD) error check
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -862,7 +860,7 @@ bool NormObject::AppendRepairRequest(NormNackMsg& nack,
|
||||||
req.SetForm(NormRepairRequest::ITEMS);
|
req.SetForm(NormRepairRequest::ITEMS);
|
||||||
req.ResetFlags();
|
req.ResetFlags();
|
||||||
req.SetFlag(NormRepairRequest::INFO);
|
req.SetFlag(NormRepairRequest::INFO);
|
||||||
req.AppendRepairItem(id, 0, 0, 0); // (TBD) error check
|
req.AppendRepairItem(transport_id, 0, 0, 0); // (TBD) error check
|
||||||
} // end if/else (iterating)
|
} // end if/else (iterating)
|
||||||
if (NormRepairRequest::INVALID != prevForm)
|
if (NormRepairRequest::INVALID != prevForm)
|
||||||
nack.PackRepairRequest(req); // (TBD) error check
|
nack.PackRepairRequest(req); // (TBD) error check
|
||||||
|
|
@ -885,7 +883,8 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
{
|
{
|
||||||
info_len = segment_size;
|
info_len = segment_size;
|
||||||
DMSG(0, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(0, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"Warning! info too long.\n", LocalNodeId(), server->GetId(), (UINT16)id);
|
"Warning! info too long.\n", LocalNodeId(), server->GetId(),
|
||||||
|
(UINT16)transport_id);
|
||||||
}
|
}
|
||||||
memcpy(info, infoMsg.GetInfo(), info_len);
|
memcpy(info, infoMsg.GetInfo(), info_len);
|
||||||
pending_info = false;
|
pending_info = false;
|
||||||
|
|
@ -896,7 +895,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
// (TBD) Verify info hasn't changed?
|
// (TBD) Verify info hasn't changed?
|
||||||
DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"received duplicate info ...\n", LocalNodeId(),
|
"received duplicate info ...\n", LocalNodeId(),
|
||||||
server->GetId(), (UINT16)id);
|
server->GetId(), (UINT16)transport_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // NORM_MSG_DATA
|
else // NORM_MSG_DATA
|
||||||
|
|
@ -909,7 +908,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
if (!stream->StreamUpdateStatus(blockId))
|
if (!stream->StreamUpdateStatus(blockId))
|
||||||
{
|
{
|
||||||
DMSG(4, "NormObject::HandleObjectMessage() node:%lu server:%lu obj>%hu blk>%lu "
|
DMSG(4, "NormObject::HandleObjectMessage() node:%lu server:%lu obj>%hu blk>%lu "
|
||||||
"broken stream ...\n", LocalNodeId(), server->GetId(), (UINT16)id, (UINT32)blockId);
|
"broken stream ...\n", LocalNodeId(), server->GetId(), (UINT16)transport_id, (UINT32)blockId);
|
||||||
|
|
||||||
//ASSERT(0);
|
//ASSERT(0);
|
||||||
// ??? Ignore this new packet and try to fix stream ???
|
// ??? Ignore this new packet and try to fix stream ???
|
||||||
|
|
@ -943,11 +942,11 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
NormBlock* block = block_buffer.Find(blockId);
|
NormBlock* block = block_buffer.Find(blockId);
|
||||||
if (!block)
|
if (!block)
|
||||||
{
|
{
|
||||||
if (!(block = server->GetFreeBlock(id, blockId)))
|
if (!(block = server->GetFreeBlock(transport_id, blockId)))
|
||||||
{
|
{
|
||||||
DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"Warning! no free blocks ...\n", LocalNodeId(), server->GetId(),
|
"Warning! no free blocks ...\n", LocalNodeId(), server->GetId(),
|
||||||
(UINT16)id);
|
(UINT16)transport_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
block->RxInit(blockId, numData, nparity);
|
block->RxInit(blockId, numData, nparity);
|
||||||
|
|
@ -956,12 +955,12 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
if (block->IsPending(segmentId))
|
if (block->IsPending(segmentId))
|
||||||
{
|
{
|
||||||
// 1) Cache segment in block buffer in case its needed for decoding
|
// 1) Cache segment in block buffer in case its needed for decoding
|
||||||
char* segment = server->GetFreeSegment(id, blockId);
|
char* segment = server->GetFreeSegment(transport_id, blockId);
|
||||||
if (!segment)
|
if (!segment)
|
||||||
{
|
{
|
||||||
DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"Warning! no free segments ...\n", LocalNodeId(), server->GetId(),
|
"Warning! no free segments ...\n", LocalNodeId(), server->GetId(),
|
||||||
(UINT16)id);
|
(UINT16)transport_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UINT16 segmentLength = data.GetPayloadDataLength();
|
UINT16 segmentLength = data.GetPayloadDataLength();
|
||||||
|
|
@ -969,7 +968,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
{
|
{
|
||||||
DMSG(0, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(0, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"Error! segment too large ...\n", LocalNodeId(), server->GetId(),
|
"Error! segment too large ...\n", LocalNodeId(), server->GetId(),
|
||||||
(UINT16)id);
|
(UINT16)transport_id);
|
||||||
server->PutFreeSegment(segment);
|
server->PutFreeSegment(segment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1011,7 +1010,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
// and write any decoded data segments to object
|
// and write any decoded data segments to object
|
||||||
DMSG(8, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu blk>%lu "
|
DMSG(8, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu blk>%lu "
|
||||||
"completed block ...\n", LocalNodeId(), server->GetId(),
|
"completed block ...\n", LocalNodeId(), server->GetId(),
|
||||||
(UINT16)id, (UINT32)block->Id());
|
(UINT16)transport_id, (UINT32)block->GetId());
|
||||||
UINT16 erasureCount = 0;
|
UINT16 erasureCount = 0;
|
||||||
UINT16 nextErasure = 0;
|
UINT16 nextErasure = 0;
|
||||||
if (block->GetFirstPending(nextErasure))
|
if (block->GetFirstPending(nextErasure))
|
||||||
|
|
@ -1023,11 +1022,11 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
server->SetErasureLoc(erasureCount++, nextErasure);
|
server->SetErasureLoc(erasureCount++, nextErasure);
|
||||||
if (nextErasure < numData)
|
if (nextErasure < numData)
|
||||||
{
|
{
|
||||||
if (!(segment = server->GetFreeSegment(id, blockId)))
|
if (!(segment = server->GetFreeSegment(transport_id, blockId)))
|
||||||
{
|
{
|
||||||
DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"Warning! no free segments ...\n", LocalNodeId(), server->GetId(),
|
"Warning! no free segments ...\n", LocalNodeId(), server->GetId(),
|
||||||
(UINT16)id);
|
(UINT16)transport_id);
|
||||||
// (TBD) Dump the block ...???
|
// (TBD) Dump the block ...???
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1076,14 +1075,14 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
||||||
{
|
{
|
||||||
DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"received duplicate segment ...\n", LocalNodeId(),
|
"received duplicate segment ...\n", LocalNodeId(),
|
||||||
server->GetId(), (UINT16)id);
|
server->GetId(), (UINT16)transport_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu "
|
||||||
"received duplicate block message ...\n", LocalNodeId(),
|
"received duplicate block message ...\n", LocalNodeId(),
|
||||||
server->GetId(), (UINT16)id);
|
server->GetId(), (UINT16)transport_id);
|
||||||
} // end if/else pending_mask.Test(blockId)
|
} // end if/else pending_mask.Test(blockId)
|
||||||
} // end if/else (NORM_MSG_INFO)
|
} // end if/else (NORM_MSG_INFO)
|
||||||
} // end NormObject::HandleObjectMessage()
|
} // end NormObject::HandleObjectMessage()
|
||||||
|
|
@ -1104,7 +1103,7 @@ NormBlock* NormObject::StealNonPendingBlock(bool excludeBlock, NormBlockId exclu
|
||||||
NormBlock* block;
|
NormBlock* block;
|
||||||
while ((block = iterator.GetNextBlock()))
|
while ((block = iterator.GetNextBlock()))
|
||||||
{
|
{
|
||||||
NormBlockId bid = block->Id();
|
NormBlockId bid = block->GetId();
|
||||||
if (block->IsTransmitPending() ||
|
if (block->IsTransmitPending() ||
|
||||||
pending_mask.Test(bid) ||
|
pending_mask.Test(bid) ||
|
||||||
repair_mask.Test(bid) ||
|
repair_mask.Test(bid) ||
|
||||||
|
|
@ -1134,7 +1133,7 @@ NormBlock* NormObject::StealNewestBlock(bool excludeBlock, NormBlockId excludeId
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NormBlock* block = block_buffer.Find(block_buffer.RangeHi());
|
NormBlock* block = block_buffer.Find(block_buffer.RangeHi());
|
||||||
if (excludeBlock && (excludeId == block->Id()))
|
if (excludeBlock && (excludeId == block->GetId()))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1158,7 +1157,7 @@ NormBlock* NormObject::StealOldestBlock(bool excludeBlock, NormBlockId excludeId
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NormBlock* block = block_buffer.Find(block_buffer.RangeLo());
|
NormBlock* block = block_buffer.Find(block_buffer.RangeLo());
|
||||||
if (excludeBlock && (excludeId == block->Id()))
|
if (excludeBlock && (excludeId == block->GetId()))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1195,7 +1194,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
|
||||||
}
|
}
|
||||||
if (info) msg->SetFlag(NormObjectMsg::FLAG_INFO);
|
if (info) msg->SetFlag(NormObjectMsg::FLAG_INFO);
|
||||||
msg->SetFecId(129);
|
msg->SetFecId(129);
|
||||||
msg->SetObjectId(id);
|
msg->SetObjectId(transport_id);
|
||||||
|
|
||||||
// We currently always apply the FTI extension
|
// We currently always apply the FTI extension
|
||||||
NormFtiExtension fti;
|
NormFtiExtension fti;
|
||||||
|
|
@ -1222,7 +1221,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
|
||||||
NormBlock* block = block_buffer.Find(blockId);
|
NormBlock* block = block_buffer.Find(blockId);
|
||||||
if (!block)
|
if (!block)
|
||||||
{
|
{
|
||||||
if (!(block = session->ServerGetFreeBlock(id, blockId)))
|
if (!(block = session->ServerGetFreeBlock(transport_id, blockId)))
|
||||||
{
|
{
|
||||||
DMSG(2, "NormObject::NextServerMsg() node>%lu Warning! server resource "
|
DMSG(2, "NormObject::NextServerMsg() node>%lu Warning! server resource "
|
||||||
"constrained (no free blocks).\n", LocalNodeId());
|
"constrained (no free blocks).\n", LocalNodeId());
|
||||||
|
|
@ -1232,7 +1231,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
|
||||||
UINT16 totalBlockLen = numData + nparity;
|
UINT16 totalBlockLen = numData + nparity;
|
||||||
for (UINT16 i = numData; i < totalBlockLen; i++)
|
for (UINT16 i = numData; i < totalBlockLen; i++)
|
||||||
{
|
{
|
||||||
char* s = session->ServerGetFreeSegment(id, blockId);
|
char* s = session->ServerGetFreeSegment(transport_id, blockId);
|
||||||
if (s)
|
if (s)
|
||||||
{
|
{
|
||||||
UINT16 payloadMax = segment_size + NormDataMsg::GetStreamPayloadHeaderLength();
|
UINT16 payloadMax = segment_size + NormDataMsg::GetStreamPayloadHeaderLength();
|
||||||
|
|
@ -1378,7 +1377,7 @@ void NormStreamObject::StreamAdvance()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DMSG(4, "NormStreamObject::StreamAdvance() node>%lu Pending segment repairs (blk>%lu) "
|
DMSG(4, "NormStreamObject::StreamAdvance() node>%lu Pending segment repairs (blk>%lu) "
|
||||||
"delaying stream advance ...\n", LocalNodeId(), (UINT32)block->Id());
|
"delaying stream advance ...\n", LocalNodeId(), (UINT32)block->GetId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1391,10 +1390,10 @@ void NormStreamObject::StreamAdvance()
|
||||||
bool NormObject::CalculateBlockParity(NormBlock* block)
|
bool NormObject::CalculateBlockParity(NormBlock* block)
|
||||||
{
|
{
|
||||||
char buffer[NormMsg::MAX_SIZE];
|
char buffer[NormMsg::MAX_SIZE];
|
||||||
UINT16 numData = GetBlockSize(block->Id());
|
UINT16 numData = GetBlockSize(block->GetId());
|
||||||
for (UINT16 i = 0; i < numData; i++)
|
for (UINT16 i = 0; i < numData; i++)
|
||||||
{
|
{
|
||||||
UINT16 payloadLength = ReadSegment(block->Id(), i, buffer);
|
UINT16 payloadLength = ReadSegment(block->GetId(), i, buffer);
|
||||||
if (0 != payloadLength)
|
if (0 != payloadLength)
|
||||||
{
|
{
|
||||||
UINT16 payloadMax = segment_size+NormDataMsg::GetStreamPayloadHeaderLength();
|
UINT16 payloadMax = segment_size+NormDataMsg::GetStreamPayloadHeaderLength();
|
||||||
|
|
@ -1416,7 +1415,7 @@ bool NormObject::CalculateBlockParity(NormBlock* block)
|
||||||
|
|
||||||
NormBlock* NormObject::ServerRecoverBlock(NormBlockId blockId)
|
NormBlock* NormObject::ServerRecoverBlock(NormBlockId blockId)
|
||||||
{
|
{
|
||||||
NormBlock* block = session->ServerGetFreeBlock(id, blockId);
|
NormBlock* block = session->ServerGetFreeBlock(transport_id, blockId);
|
||||||
if (block)
|
if (block)
|
||||||
{
|
{
|
||||||
UINT16 numData = GetBlockSize(blockId);
|
UINT16 numData = GetBlockSize(blockId);
|
||||||
|
|
@ -1426,7 +1425,7 @@ NormBlock* NormObject::ServerRecoverBlock(NormBlockId blockId)
|
||||||
UINT16 totalBlockLen = numData + nparity;
|
UINT16 totalBlockLen = numData + nparity;
|
||||||
for (UINT16 i = numData; i < totalBlockLen; i++)
|
for (UINT16 i = numData; i < totalBlockLen; i++)
|
||||||
{
|
{
|
||||||
char* s = session->ServerGetFreeSegment(id, blockId);
|
char* s = session->ServerGetFreeSegment(transport_id, blockId);
|
||||||
if (s)
|
if (s)
|
||||||
{
|
{
|
||||||
UINT16 payloadMax = segment_size + NormDataMsg::GetStreamPayloadHeaderLength();
|
UINT16 payloadMax = segment_size + NormDataMsg::GetStreamPayloadHeaderLength();
|
||||||
|
|
@ -1952,7 +1951,7 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
|
||||||
while (block->IsPending())
|
while (block->IsPending())
|
||||||
{
|
{
|
||||||
// Notify app for stream data salvage
|
// Notify app for stream data salvage
|
||||||
read_index.block = block->Id();
|
read_index.block = block->GetId();
|
||||||
block->GetFirstPending(read_index.segment);
|
block->GetFirstPending(read_index.segment);
|
||||||
NormBlock* tempBlock = block;
|
NormBlock* tempBlock = block;
|
||||||
UINT32 tempOffset = read_offset;
|
UINT32 tempOffset = read_offset;
|
||||||
|
|
@ -1995,9 +1994,9 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
|
||||||
if (broken)
|
if (broken)
|
||||||
{
|
{
|
||||||
DMSG(4, "NormStreamObject::WriteSegment() node>%lu obj>%hu blk>%lu seg>%hu broken stream ...\n",
|
DMSG(4, "NormStreamObject::WriteSegment() node>%lu obj>%hu blk>%lu seg>%hu broken stream ...\n",
|
||||||
LocalNodeId(), (UINT16)id, (UINT32)blockId, (UINT16)segmentId);
|
LocalNodeId(), (UINT16)transport_id, (UINT32)blockId, (UINT16)segmentId);
|
||||||
NormBlock* first = stream_buffer.Find(stream_buffer.RangeLo());
|
NormBlock* first = stream_buffer.Find(stream_buffer.RangeLo());
|
||||||
read_index.block = first->Id();
|
read_index.block = first->GetId();
|
||||||
read_index.segment = 0;
|
read_index.segment = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2029,10 +2028,10 @@ void NormStreamObject::Prune(NormBlockId blockId)
|
||||||
NormBlock* block;
|
NormBlock* block;
|
||||||
while ((block = block_buffer.Find(block_buffer.RangeLo())))
|
while ((block = block_buffer.Find(block_buffer.RangeLo())))
|
||||||
{
|
{
|
||||||
if (block->Id() < blockId)
|
if (block->GetId() < blockId)
|
||||||
{
|
{
|
||||||
resync = true;
|
resync = true;
|
||||||
pending_mask.Unset(block->Id());
|
pending_mask.Unset(block->GetId());
|
||||||
block_buffer.Remove(block);
|
block_buffer.Remove(block);
|
||||||
server->PutFreeBlock(block);
|
server->PutFreeBlock(block);
|
||||||
}
|
}
|
||||||
|
|
@ -2183,7 +2182,7 @@ unsigned long NormStreamObject::Write(const char* buffer, unsigned long len,
|
||||||
ASSERT(block);
|
ASSERT(block);
|
||||||
if (push)
|
if (push)
|
||||||
{
|
{
|
||||||
NormBlockId blockId = block->Id();
|
NormBlockId blockId = block->GetId();
|
||||||
pending_mask.Unset(blockId);
|
pending_mask.Unset(blockId);
|
||||||
repair_mask.Unset(blockId);
|
repair_mask.Unset(blockId);
|
||||||
NormBlock* b = FindBlock(blockId);
|
NormBlock* b = FindBlock(blockId);
|
||||||
|
|
@ -2215,7 +2214,7 @@ unsigned long NormStreamObject::Write(const char* buffer, unsigned long len,
|
||||||
ASSERT(b != block);
|
ASSERT(b != block);
|
||||||
if (push)
|
if (push)
|
||||||
{
|
{
|
||||||
NormBlockId blockId = block->Id();
|
NormBlockId blockId = block->GetId();
|
||||||
pending_mask.Unset(blockId);
|
pending_mask.Unset(blockId);
|
||||||
repair_mask.Unset(blockId);
|
repair_mask.Unset(blockId);
|
||||||
NormBlock* c = FindBlock(blockId);
|
NormBlock* c = FindBlock(blockId);
|
||||||
|
|
@ -2404,7 +2403,7 @@ NormObject* NormObjectTable::Find(const NormObjectId& objectId) const
|
||||||
{
|
{
|
||||||
if ((objectId < range_lo) || (objectId > range_hi)) return (NormObject*)NULL;
|
if ((objectId < range_lo) || (objectId > range_hi)) return (NormObject*)NULL;
|
||||||
NormObject* theObject = table[((UINT16)objectId) & hash_mask];
|
NormObject* theObject = table[((UINT16)objectId) & hash_mask];
|
||||||
while (theObject && (objectId != theObject->Id())) theObject = theObject->next;
|
while (theObject && (objectId != theObject->GetId())) theObject = theObject->next;
|
||||||
return theObject;
|
return theObject;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -2445,7 +2444,7 @@ bool NormObjectTable::CanInsert(NormObjectId objectId) const
|
||||||
|
|
||||||
bool NormObjectTable::Insert(NormObject* theObject)
|
bool NormObjectTable::Insert(NormObject* theObject)
|
||||||
{
|
{
|
||||||
const NormObjectId& objectId = theObject->Id();
|
const NormObjectId& objectId = theObject->GetId();
|
||||||
if (!range)
|
if (!range)
|
||||||
{
|
{
|
||||||
range_lo = range_hi = objectId;
|
range_lo = range_hi = objectId;
|
||||||
|
|
@ -2468,7 +2467,7 @@ bool NormObjectTable::Insert(NormObject* theObject)
|
||||||
UINT16 index = ((UINT16)objectId) & hash_mask;
|
UINT16 index = ((UINT16)objectId) & hash_mask;
|
||||||
NormObject* prev = NULL;
|
NormObject* prev = NULL;
|
||||||
NormObject* entry = table[index];
|
NormObject* entry = table[index];
|
||||||
while (entry && (entry->Id() < objectId))
|
while (entry && (entry->GetId() < objectId))
|
||||||
{
|
{
|
||||||
prev = entry;
|
prev = entry;
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
|
|
@ -2477,24 +2476,24 @@ bool NormObjectTable::Insert(NormObject* theObject)
|
||||||
prev->next = theObject;
|
prev->next = theObject;
|
||||||
else
|
else
|
||||||
table[index] = theObject;
|
table[index] = theObject;
|
||||||
ASSERT((entry ? (objectId != entry->Id()) : true));
|
ASSERT((entry ? (objectId != entry->GetId()) : true));
|
||||||
theObject->next = entry;
|
theObject->next = entry;
|
||||||
count++;
|
count++;
|
||||||
size = size + theObject->Size();
|
size = size + theObject->GetSize();
|
||||||
return true;
|
return true;
|
||||||
} // end NormObjectTable::Insert()
|
} // end NormObjectTable::Insert()
|
||||||
|
|
||||||
bool NormObjectTable::Remove(const NormObject* theObject)
|
bool NormObjectTable::Remove(const NormObject* theObject)
|
||||||
{
|
{
|
||||||
ASSERT(theObject);
|
ASSERT(theObject);
|
||||||
const NormObjectId& objectId = theObject->Id();
|
const NormObjectId& objectId = theObject->GetId();
|
||||||
if (range)
|
if (range)
|
||||||
{
|
{
|
||||||
if ((objectId < range_lo) || (objectId > range_hi)) return false;
|
if ((objectId < range_lo) || (objectId > range_hi)) return false;
|
||||||
UINT16 index = ((UINT16)objectId) & hash_mask;
|
UINT16 index = ((UINT16)objectId) & hash_mask;
|
||||||
NormObject* prev = NULL;
|
NormObject* prev = NULL;
|
||||||
NormObject* entry = table[index];
|
NormObject* entry = table[index];
|
||||||
while (entry && (entry->Id() != objectId))
|
while (entry && (entry->GetId() != objectId))
|
||||||
{
|
{
|
||||||
prev = entry;
|
prev = entry;
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
|
|
@ -2525,10 +2524,10 @@ bool NormObjectTable::Remove(const NormObject* theObject)
|
||||||
if ((entry = table[i]))
|
if ((entry = table[i]))
|
||||||
{
|
{
|
||||||
NormObjectId id = (UINT16)index + offset;
|
NormObjectId id = (UINT16)index + offset;
|
||||||
while(entry && (entry->Id() != id))
|
while(entry && (entry->GetId() != id))
|
||||||
{
|
{
|
||||||
if ((entry->Id() > objectId) &&
|
if ((entry->GetId() > objectId) &&
|
||||||
(entry->Id() < nextId)) nextId = entry->Id();
|
(entry->GetId() < nextId)) nextId = entry->GetId();
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -2536,7 +2535,7 @@ bool NormObjectTable::Remove(const NormObject* theObject)
|
||||||
}
|
}
|
||||||
} while (i != endex);
|
} while (i != endex);
|
||||||
if (entry)
|
if (entry)
|
||||||
range_lo = entry->Id();
|
range_lo = entry->GetId();
|
||||||
else
|
else
|
||||||
range_lo = nextId;
|
range_lo = nextId;
|
||||||
range = range_hi - range_lo + 1;
|
range = range_hi - range_lo + 1;
|
||||||
|
|
@ -2561,18 +2560,18 @@ bool NormObjectTable::Remove(const NormObject* theObject)
|
||||||
if ((entry = table[i]))
|
if ((entry = table[i]))
|
||||||
{
|
{
|
||||||
NormObjectId id = (UINT16)index - offset;
|
NormObjectId id = (UINT16)index - offset;
|
||||||
//printf("Looking for id:%lu at index:%lu\n", (UINT16)id, i);
|
//printf("Looking for id:%lu at index:%lu\n", (UINT16)transport_id, i);
|
||||||
while(entry && (entry->Id() != id))
|
while(entry && (entry->GetId() != id))
|
||||||
{
|
{
|
||||||
if ((entry->Id() < objectId) &&
|
if ((entry->GetId() < objectId) &&
|
||||||
(entry->Id() > prevId)) prevId = entry->Id();
|
(entry->GetId() > prevId)) prevId = entry->GetId();
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
}
|
}
|
||||||
if (entry) break;
|
if (entry) break;
|
||||||
}
|
}
|
||||||
} while (i != endex);
|
} while (i != endex);
|
||||||
if (entry)
|
if (entry)
|
||||||
range_hi = entry->Id();
|
range_hi = entry->GetId();
|
||||||
else
|
else
|
||||||
range_hi = prevId;
|
range_hi = prevId;
|
||||||
range = range_hi - range_lo + 1;
|
range = range_hi - range_lo + 1;
|
||||||
|
|
@ -2583,7 +2582,7 @@ bool NormObjectTable::Remove(const NormObject* theObject)
|
||||||
range = 0;
|
range = 0;
|
||||||
}
|
}
|
||||||
count--;
|
count--;
|
||||||
size = size - theObject->Size();
|
size = size - theObject->GetSize();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -2633,15 +2632,15 @@ NormObject* NormObjectTable::Iterator::GetNextObject()
|
||||||
offset++;
|
offset++;
|
||||||
NormObjectId id = (UINT16)index + offset;
|
NormObjectId id = (UINT16)index + offset;
|
||||||
NormObject* entry = table.table[i];
|
NormObject* entry = table.table[i];
|
||||||
while ((NULL != entry) && (entry->Id() != id))
|
while ((NULL != entry) && (entry->GetId() != id))
|
||||||
{
|
{
|
||||||
if ((entry->Id() > index) && (entry->Id() < nextId))
|
if ((entry->GetId() > index) && (entry->GetId() < nextId))
|
||||||
nextId = entry->Id();
|
nextId = entry->GetId();
|
||||||
entry = table.Next(entry);
|
entry = table.Next(entry);
|
||||||
}
|
}
|
||||||
if (entry)
|
if (entry)
|
||||||
{
|
{
|
||||||
index = entry->Id();
|
index = entry->GetId();
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
} while (i != endex);
|
} while (i != endex);
|
||||||
|
|
@ -2692,15 +2691,15 @@ NormObject* NormObjectTable::Iterator::GetPrevObject()
|
||||||
offset--;
|
offset--;
|
||||||
NormObjectId id = (UINT16)index + offset;
|
NormObjectId id = (UINT16)index + offset;
|
||||||
NormObject* entry = table.table[i];
|
NormObject* entry = table.table[i];
|
||||||
while ((NULL != entry ) && (entry->Id() != id))
|
while ((NULL != entry ) && (entry->GetId() != id))
|
||||||
{
|
{
|
||||||
if ((entry->Id() > index) && (entry->Id() < nextId))
|
if ((entry->GetId() > index) && (entry->GetId() < nextId))
|
||||||
nextId = entry->Id();
|
nextId = entry->GetId();
|
||||||
entry = table.Next(entry);
|
entry = table.Next(entry);
|
||||||
}
|
}
|
||||||
if (entry)
|
if (entry)
|
||||||
{
|
{
|
||||||
index = entry->Id();
|
index = entry->GetId();
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
} while (i != endex);
|
} while (i != endex);
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,11 @@ class NormObject
|
||||||
|
|
||||||
// Object information
|
// Object information
|
||||||
NormObject::Type GetType() const {return type;}
|
NormObject::Type GetType() const {return type;}
|
||||||
const NormObjectId& Id() const {return id;}
|
const NormObjectId& GetId() const {return transport_id;}
|
||||||
const NormObjectSize& Size() const {return object_size;}
|
const NormObjectSize& GetSize() const {return object_size;}
|
||||||
bool HaveInfo() const {return (info_len > 0);}
|
bool HaveInfo() const {return (info_len > 0);}
|
||||||
const char* GetInfo() const {return info;}
|
const char* GetInfo() const {return info;}
|
||||||
UINT16 InfoLength() const {return info_len;}
|
UINT16 GetInfoLength() const {return info_len;}
|
||||||
bool IsStream() const {return (STREAM == type);}
|
bool IsStream() const {return (STREAM == type);}
|
||||||
|
|
||||||
NormNodeId LocalNodeId() const;
|
NormNodeId LocalNodeId() const;
|
||||||
|
|
@ -127,7 +127,7 @@ class NormObject
|
||||||
NormSegmentId lastSegmentId,
|
NormSegmentId lastSegmentId,
|
||||||
UINT16 numErasures)
|
UINT16 numErasures)
|
||||||
{
|
{
|
||||||
NormBlockId blockId = theBlock->Id();
|
NormBlockId blockId = theBlock->GetId();
|
||||||
bool result = theBlock->TxUpdate(firstSegmentId, lastSegmentId,
|
bool result = theBlock->TxUpdate(firstSegmentId, lastSegmentId,
|
||||||
GetBlockSize(blockId), nparity,
|
GetBlockSize(blockId), nparity,
|
||||||
numErasures);
|
numErasures);
|
||||||
|
|
@ -184,7 +184,7 @@ class NormObject
|
||||||
NormObject::Type type;
|
NormObject::Type type;
|
||||||
class NormSession* session;
|
class NormSession* session;
|
||||||
class NormServerNode* server; // NULL value indicates local (tx) object
|
class NormServerNode* server; // NULL value indicates local (tx) object
|
||||||
NormObjectId id;
|
NormObjectId transport_id;
|
||||||
|
|
||||||
NormObjectSize object_size;
|
NormObjectSize object_size;
|
||||||
UINT16 segment_size;
|
UINT16 segment_size;
|
||||||
|
|
|
||||||
|
|
@ -104,28 +104,28 @@ NormBlock::~NormBlock()
|
||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NormBlock::Init(UINT16 blockSize)
|
bool NormBlock::Init(UINT16 totalSize)
|
||||||
{
|
{
|
||||||
if (segment_table) Destroy();
|
if (segment_table) Destroy();
|
||||||
if (!(segment_table = new char*[blockSize]))
|
if (!(segment_table = new char*[totalSize]))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormBlock::Init() segment_table allocation error: %s\n", strerror(errno));
|
DMSG(0, "NormBlock::Init() segment_table allocation error: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memset(segment_table, 0, blockSize*sizeof(char*));
|
memset(segment_table, 0, totalSize*sizeof(char*));
|
||||||
if (!pending_mask.Init(blockSize))
|
if (!pending_mask.Init(totalSize))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormBlock::Init() pending_mask allocation error: %s\n", strerror(errno));
|
DMSG(0, "NormBlock::Init() pending_mask allocation error: %s\n", strerror(errno));
|
||||||
Destroy();
|
Destroy();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!repair_mask.Init(blockSize))
|
if (!repair_mask.Init(totalSize))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormBlock::Init() repair_mask allocation error: %s\n", strerror(errno));
|
DMSG(0, "NormBlock::Init() repair_mask allocation error: %s\n", strerror(errno));
|
||||||
Destroy();
|
Destroy();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size = blockSize;
|
size = totalSize;
|
||||||
erasure_count = 0;
|
erasure_count = 0;
|
||||||
parity_count = 0;
|
parity_count = 0;
|
||||||
parity_offset = 0;;
|
parity_offset = 0;;
|
||||||
|
|
@ -173,16 +173,16 @@ bool NormBlock::IsEmpty() const
|
||||||
|
|
||||||
// Used by client side to determine if NACK should be sent
|
// Used by client side to determine if NACK should be sent
|
||||||
// Note: This invalidates the block's "repair_mask" state
|
// Note: This invalidates the block's "repair_mask" state
|
||||||
bool NormBlock::IsRepairPending(UINT16 ndata, UINT16 nparity)
|
bool NormBlock::IsRepairPending(UINT16 numData, UINT16 numParity)
|
||||||
{
|
{
|
||||||
// Clients ask for a block of parity to fulfill their
|
// Clients ask for a block of parity to fulfill their
|
||||||
// repair needs (erasure_count), but if there isn't
|
// repair needs (erasure_count), but if there isn't
|
||||||
// enough parity, they ask for some data segments, too
|
// enough parity, they ask for some data segments, too
|
||||||
if (erasure_count > nparity)
|
if (erasure_count > numParity)
|
||||||
{
|
{
|
||||||
if (nparity)
|
if (numParity)
|
||||||
{
|
{
|
||||||
UINT16 i = nparity;
|
UINT16 i = numParity;
|
||||||
NormSegmentId nextId = 0;
|
NormSegmentId nextId = 0;
|
||||||
GetFirstPending(nextId);
|
GetFirstPending(nextId);
|
||||||
while (i--)
|
while (i--)
|
||||||
|
|
@ -194,44 +194,44 @@ bool NormBlock::IsRepairPending(UINT16 ndata, UINT16 nparity)
|
||||||
GetNextPending(nextId);
|
GetNextPending(nextId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (size > ndata)
|
else if (size > numData)
|
||||||
{
|
{
|
||||||
repair_mask.SetBits(ndata, size-ndata);
|
repair_mask.SetBits(numData, size-numData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
repair_mask.SetBits(0, ndata);
|
repair_mask.SetBits(0, numData);
|
||||||
repair_mask.SetBits(ndata+erasure_count, nparity-erasure_count);
|
repair_mask.SetBits(numData+erasure_count, numParity-erasure_count);
|
||||||
}
|
}
|
||||||
repair_mask.XCopy(pending_mask);
|
repair_mask.XCopy(pending_mask);
|
||||||
return (repair_mask.IsSet());
|
return (repair_mask.IsSet());
|
||||||
} // end NormBlock::IsRepairPending()
|
} // end NormBlock::IsRepairPending()
|
||||||
|
|
||||||
// Called by server
|
// Called by server
|
||||||
bool NormBlock::TxReset(UINT16 ndata,
|
bool NormBlock::TxReset(UINT16 numData,
|
||||||
UINT16 nparity,
|
UINT16 numParity,
|
||||||
UINT16 autoParity,
|
UINT16 autoParity,
|
||||||
UINT16 segmentSize)
|
UINT16 segmentSize)
|
||||||
{
|
{
|
||||||
bool increasedRepair = false;
|
bool increasedRepair = false;
|
||||||
repair_mask.SetBits(0, ndata+autoParity);
|
repair_mask.SetBits(0, numData+autoParity);
|
||||||
repair_mask.UnsetBits(ndata+autoParity, nparity-autoParity);
|
repair_mask.UnsetBits(numData+autoParity, numParity-autoParity);
|
||||||
repair_mask.Xor(pending_mask);
|
repair_mask.Xor(pending_mask);
|
||||||
if (repair_mask.IsSet())
|
if (repair_mask.IsSet())
|
||||||
{
|
{
|
||||||
increasedRepair = true;
|
increasedRepair = true;
|
||||||
repair_mask.Clear();
|
repair_mask.Clear();
|
||||||
pending_mask.SetBits(0, ndata+autoParity);
|
pending_mask.SetBits(0, numData+autoParity);
|
||||||
pending_mask.UnsetBits(ndata+autoParity, nparity-autoParity);
|
pending_mask.UnsetBits(numData+autoParity, numParity-autoParity);
|
||||||
parity_offset = autoParity; // reset parity since we're resending this one
|
parity_offset = autoParity; // reset parity since we're resending this one
|
||||||
parity_count = nparity; // no parity repair this repair cycle
|
parity_count = numParity; // no parity repair this repair cycle
|
||||||
SetFlag(IN_REPAIR);
|
SetFlag(IN_REPAIR);
|
||||||
if (!ParityReady(ndata)) // (TBD) only when incrementalParity == true
|
if (!ParityReady(numData)) // (TBD) only when incrementalParity == true
|
||||||
{
|
{
|
||||||
// Clear _any_ existing incremental parity state
|
// Clear _any_ existing incremental parity state
|
||||||
char** ptr = segment_table+ndata;
|
char** ptr = segment_table+numData;
|
||||||
while (nparity--)
|
while (numParity--)
|
||||||
{
|
{
|
||||||
if (*ptr) memset(*ptr, 0, segmentSize);
|
if (*ptr) memset(*ptr, 0, segmentSize);
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
@ -242,7 +242,7 @@ bool NormBlock::TxReset(UINT16 ndata,
|
||||||
return increasedRepair;
|
return increasedRepair;
|
||||||
} // end NormBlock::TxReset()
|
} // end NormBlock::TxReset()
|
||||||
|
|
||||||
bool NormBlock::ActivateRepairs(UINT16 nparity)
|
bool NormBlock::ActivateRepairs(UINT16 numParity)
|
||||||
{
|
{
|
||||||
if (repair_mask.IsSet())
|
if (repair_mask.IsSet())
|
||||||
{
|
{
|
||||||
|
|
@ -260,14 +260,14 @@ bool NormBlock::ActivateRepairs(UINT16 nparity)
|
||||||
// (we directly update the "pending_mask" for blocks/segments
|
// (we directly update the "pending_mask" for blocks/segments
|
||||||
// greater than our current transmit index)
|
// greater than our current transmit index)
|
||||||
bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
|
bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
UINT16 ndata, UINT16 nparity, UINT16 erasureCount)
|
UINT16 numData, UINT16 numParity, UINT16 erasureCount)
|
||||||
{
|
{
|
||||||
bool increasedRepair = false;
|
bool increasedRepair = false;
|
||||||
|
|
||||||
if (nextId < ndata)
|
if (nextId < numData)
|
||||||
{
|
{
|
||||||
// Explicit data repair request
|
// Explicit data repair request
|
||||||
parity_offset = parity_count = nparity;
|
parity_offset = parity_count = numParity;
|
||||||
while (nextId <= lastId)
|
while (nextId <= lastId)
|
||||||
{
|
{
|
||||||
if (!pending_mask.Test(nextId))
|
if (!pending_mask.Test(nextId))
|
||||||
|
|
@ -281,13 +281,13 @@ bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// parity repair request
|
// parity repair request
|
||||||
UINT16 parityAvailable = nparity - parity_offset;
|
UINT16 parityAvailable = numParity - parity_offset;
|
||||||
if (erasureCount <= parityAvailable)
|
if (erasureCount <= parityAvailable)
|
||||||
{
|
{
|
||||||
// Use fresh parity for repair
|
// Use fresh parity for repair
|
||||||
if (erasureCount > parity_count)
|
if (erasureCount > parity_count)
|
||||||
{
|
{
|
||||||
pending_mask.SetBits(ndata+parity_offset+parity_count,
|
pending_mask.SetBits(numData+parity_offset+parity_count,
|
||||||
erasureCount - parity_count);
|
erasureCount - parity_count);
|
||||||
parity_count = erasureCount;
|
parity_count = erasureCount;
|
||||||
increasedRepair = true;
|
increasedRepair = true;
|
||||||
|
|
@ -299,7 +299,7 @@ bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
if (parity_count < parityAvailable)
|
if (parity_count < parityAvailable)
|
||||||
{
|
{
|
||||||
UINT16 count = parityAvailable - parity_count;
|
UINT16 count = parityAvailable - parity_count;
|
||||||
pending_mask.SetBits(ndata+parity_offset+parity_count, count);
|
pending_mask.SetBits(numData+parity_offset+parity_count, count);
|
||||||
parity_count = parityAvailable;
|
parity_count = parityAvailable;
|
||||||
nextId += parityAvailable;
|
nextId += parityAvailable;
|
||||||
increasedRepair = true;
|
increasedRepair = true;
|
||||||
|
|
@ -320,15 +320,15 @@ bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
} // end NormBlock::TxUpdate()
|
} // end NormBlock::TxUpdate()
|
||||||
|
|
||||||
bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
UINT16 ndata, UINT16 nparity, UINT16 erasureCount)
|
UINT16 numData, UINT16 numParity, UINT16 erasureCount)
|
||||||
{
|
{
|
||||||
DMSG(6, "NormBlock::HandleSegmentRequest() blk>%lu seg>%hu:%hu erasures:%hu\n",
|
DMSG(6, "NormBlock::HandleSegmentRequest() blk>%lu seg>%hu:%hu erasures:%hu\n",
|
||||||
(UINT32)id, (UINT16)nextId, (UINT16)lastId, erasureCount);
|
(UINT32)id, (UINT16)nextId, (UINT16)lastId, erasureCount);
|
||||||
bool increasedRepair = false;
|
bool increasedRepair = false;
|
||||||
if (nextId < ndata)
|
if (nextId < numData)
|
||||||
{
|
{
|
||||||
// Explicit data repair request
|
// Explicit data repair request
|
||||||
parity_count = parity_offset = nparity;
|
parity_count = parity_offset = numParity;
|
||||||
while (nextId <= lastId)
|
while (nextId <= lastId)
|
||||||
{
|
{
|
||||||
if (!repair_mask.Test(nextId))
|
if (!repair_mask.Test(nextId))
|
||||||
|
|
@ -342,13 +342,13 @@ bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// parity repair request
|
// parity repair request
|
||||||
UINT16 parityAvailable = nparity - parity_offset;
|
UINT16 parityAvailable = numParity - parity_offset;
|
||||||
if (erasureCount <= parityAvailable)
|
if (erasureCount <= parityAvailable)
|
||||||
{
|
{
|
||||||
// Use fresh parity for repair
|
// Use fresh parity for repair
|
||||||
if (erasureCount > parity_count)
|
if (erasureCount > parity_count)
|
||||||
{
|
{
|
||||||
repair_mask.SetBits(ndata+parity_offset+parity_count,
|
repair_mask.SetBits(numData+parity_offset+parity_count,
|
||||||
erasureCount - parity_count);
|
erasureCount - parity_count);
|
||||||
parity_count = erasureCount;
|
parity_count = erasureCount;
|
||||||
increasedRepair = true;
|
increasedRepair = true;
|
||||||
|
|
@ -360,7 +360,7 @@ bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
if (parity_count < parityAvailable)
|
if (parity_count < parityAvailable)
|
||||||
{
|
{
|
||||||
UINT16 count = parityAvailable - parity_count;
|
UINT16 count = parityAvailable - parity_count;
|
||||||
repair_mask.SetBits(ndata+parity_offset+parity_count, count);
|
repair_mask.SetBits(numData+parity_offset+parity_count, count);
|
||||||
parity_count = parityAvailable;
|
parity_count = parityAvailable;
|
||||||
nextId += parityAvailable;
|
nextId += parityAvailable;
|
||||||
increasedRepair = true;
|
increasedRepair = true;
|
||||||
|
|
@ -384,7 +384,7 @@ bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
NormObjectId objectId,
|
NormObjectId objectId,
|
||||||
bool repairInfo,
|
bool repairInfo,
|
||||||
UINT16 ndata,
|
UINT16 numData,
|
||||||
UINT16 segmentSize)
|
UINT16 segmentSize)
|
||||||
{
|
{
|
||||||
NormRepairRequest req;
|
NormRepairRequest req;
|
||||||
|
|
@ -393,18 +393,18 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
NormSymbolId nextId = 0;
|
NormSymbolId nextId = 0;
|
||||||
if (GetFirstRepair(nextId))
|
if (GetFirstRepair(nextId))
|
||||||
{
|
{
|
||||||
UINT16 blockSize = size;
|
UINT16 totalSize = size;
|
||||||
NormRepairRequest::Form prevForm = NormRepairRequest::INVALID;
|
NormRepairRequest::Form prevForm = NormRepairRequest::INVALID;
|
||||||
UINT16 segmentCount = 0;
|
UINT16 segmentCount = 0;
|
||||||
UINT16 firstId = 0;
|
UINT16 firstId = 0;
|
||||||
while (nextId < blockSize)
|
while (nextId < totalSize)
|
||||||
{
|
{
|
||||||
UINT16 currentId = nextId;
|
UINT16 currentId = nextId;
|
||||||
if (!GetNextRepair(++nextId)) nextId = blockSize;
|
if (!GetNextRepair(++nextId)) nextId = totalSize;
|
||||||
if (!segmentCount) firstId = currentId;
|
if (!segmentCount) firstId = currentId;
|
||||||
segmentCount++;
|
segmentCount++;
|
||||||
// Check for break in consecutive series or end
|
// Check for break in consecutive series or end
|
||||||
if (((nextId - currentId) > 1) || (nextId >= blockSize))
|
if (((nextId - currentId) > 1) || (nextId >= totalSize))
|
||||||
{
|
{
|
||||||
NormRepairRequest::Form form;
|
NormRepairRequest::Form form;
|
||||||
switch (segmentCount)
|
switch (segmentCount)
|
||||||
|
|
@ -434,13 +434,13 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
ASSERT(0); // can't happen
|
ASSERT(0); // can't happen
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::ITEMS:
|
case NormRepairRequest::ITEMS:
|
||||||
req.AppendRepairItem(objectId, id, ndata, firstId);
|
req.AppendRepairItem(objectId, id, numData, firstId);
|
||||||
if (2 == segmentCount)
|
if (2 == segmentCount)
|
||||||
req.AppendRepairItem(objectId, id, ndata, currentId);
|
req.AppendRepairItem(objectId, id, numData, currentId);
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::RANGES:
|
case NormRepairRequest::RANGES:
|
||||||
req.AppendRepairRange(objectId, id, ndata, firstId,
|
req.AppendRepairRange(objectId, id, numData, firstId,
|
||||||
objectId, id, ndata, currentId);
|
objectId, id, numData, currentId);
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::ERASURES:
|
case NormRepairRequest::ERASURES:
|
||||||
// erasure counts not used
|
// erasure counts not used
|
||||||
|
|
@ -448,7 +448,7 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
}
|
}
|
||||||
segmentCount = 0;
|
segmentCount = 0;
|
||||||
}
|
}
|
||||||
} // end while (nextId < blockSize)
|
} // end while (nextId < totalSize)
|
||||||
if (NormRepairRequest::INVALID != prevForm)
|
if (NormRepairRequest::INVALID != prevForm)
|
||||||
cmd.PackRepairRequest(req); // (TBD) error check
|
cmd.PackRepairRequest(req); // (TBD) error check
|
||||||
}
|
}
|
||||||
|
|
@ -457,32 +457,32 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
|
|
||||||
// Called by client
|
// Called by client
|
||||||
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||||
UINT16 ndata,
|
UINT16 numData,
|
||||||
UINT16 nparity,
|
UINT16 numParity,
|
||||||
NormObjectId objectId,
|
NormObjectId objectId,
|
||||||
bool pendingInfo,
|
bool pendingInfo,
|
||||||
UINT16 segmentSize)
|
UINT16 segmentSize)
|
||||||
{
|
{
|
||||||
NormSegmentId nextId = 0;
|
NormSegmentId nextId = 0;
|
||||||
NormSegmentId endId;
|
NormSegmentId endId;
|
||||||
if (erasure_count > nparity)
|
if (erasure_count > numParity)
|
||||||
{
|
{
|
||||||
// Request explicit repair
|
// Request explicit repair
|
||||||
GetFirstPending(nextId);
|
GetFirstPending(nextId);
|
||||||
UINT16 i = nparity;
|
UINT16 i = numParity;
|
||||||
// Skip nparity missing data segments
|
// Skip numParity missing data segments
|
||||||
while (i--)
|
while (i--)
|
||||||
{
|
{
|
||||||
nextId++;
|
nextId++;
|
||||||
GetNextPending(nextId);
|
GetNextPending(nextId);
|
||||||
}
|
}
|
||||||
endId = ndata + nparity;
|
endId = numData + numParity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nextId = ndata;
|
nextId = numData;
|
||||||
GetNextPending(nextId);
|
GetNextPending(nextId);
|
||||||
endId = ndata + erasure_count;
|
endId = numData + erasure_count;
|
||||||
}
|
}
|
||||||
NormRepairRequest req;
|
NormRepairRequest req;
|
||||||
req.SetFlag(NormRepairRequest::SEGMENT);
|
req.SetFlag(NormRepairRequest::SEGMENT);
|
||||||
|
|
@ -528,13 +528,13 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::ITEMS:
|
case NormRepairRequest::ITEMS:
|
||||||
req.AppendRepairItem(objectId, id, ndata, firstId); // (TBD) error check
|
req.AppendRepairItem(objectId, id, numData, firstId); // (TBD) error check
|
||||||
if (2 == segmentCount)
|
if (2 == segmentCount)
|
||||||
req.AppendRepairItem(objectId, id, ndata, currentId); // (TBD) error check
|
req.AppendRepairItem(objectId, id, numData, currentId); // (TBD) error check
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::RANGES:
|
case NormRepairRequest::RANGES:
|
||||||
req.AppendRepairRange(objectId, id, ndata, firstId, // (TBD) error check
|
req.AppendRepairRange(objectId, id, numData, firstId, // (TBD) error check
|
||||||
objectId, id, ndata, currentId); // (TBD) error check
|
objectId, id, numData, currentId); // (TBD) error check
|
||||||
break;
|
break;
|
||||||
case NormRepairRequest::ERASURES:
|
case NormRepairRequest::ERASURES:
|
||||||
// erasure counts not used
|
// erasure counts not used
|
||||||
|
|
@ -627,7 +627,7 @@ NormBlockPool::~NormBlockPool()
|
||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NormBlockPool::Init(UINT32 numBlocks, UINT16 blockSize)
|
bool NormBlockPool::Init(UINT32 numBlocks, UINT16 totalSize)
|
||||||
{
|
{
|
||||||
if (head) Destroy();
|
if (head) Destroy();
|
||||||
for (UINT32 i = 0; i < numBlocks; i++)
|
for (UINT32 i = 0; i < numBlocks; i++)
|
||||||
|
|
@ -635,7 +635,7 @@ bool NormBlockPool::Init(UINT32 numBlocks, UINT16 blockSize)
|
||||||
NormBlock* b = new NormBlock();
|
NormBlock* b = new NormBlock();
|
||||||
if (b)
|
if (b)
|
||||||
{
|
{
|
||||||
if (!b->Init(blockSize))
|
if (!b->Init(totalSize))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormBlockPool::Init() block init error\n");
|
DMSG(0, "NormBlockPool::Init() block init error\n");
|
||||||
delete b;
|
delete b;
|
||||||
|
|
@ -723,7 +723,7 @@ NormBlock* NormBlockBuffer::Find(const NormBlockId& blockId) const
|
||||||
if ((blockId < range_lo) || (blockId > range_hi))
|
if ((blockId < range_lo) || (blockId > range_hi))
|
||||||
return (NormBlock*)NULL;
|
return (NormBlock*)NULL;
|
||||||
NormBlock* theBlock = table[((UINT32)blockId) & hash_mask];
|
NormBlock* theBlock = table[((UINT32)blockId) & hash_mask];
|
||||||
while (theBlock && (blockId != theBlock->Id()))
|
while (theBlock && (blockId != theBlock->GetId()))
|
||||||
theBlock = theBlock->next;
|
theBlock = theBlock->next;
|
||||||
return theBlock;
|
return theBlock;
|
||||||
}
|
}
|
||||||
|
|
@ -766,7 +766,7 @@ bool NormBlockBuffer::CanInsert(NormBlockId blockId) const
|
||||||
|
|
||||||
bool NormBlockBuffer::Insert(NormBlock* theBlock)
|
bool NormBlockBuffer::Insert(NormBlock* theBlock)
|
||||||
{
|
{
|
||||||
const NormBlockId& blockId = theBlock->Id();
|
const NormBlockId& blockId = theBlock->GetId();
|
||||||
if (!range)
|
if (!range)
|
||||||
{
|
{
|
||||||
range_lo = range_hi = blockId;
|
range_lo = range_hi = blockId;
|
||||||
|
|
@ -789,7 +789,7 @@ bool NormBlockBuffer::Insert(NormBlock* theBlock)
|
||||||
UINT32 index = ((UINT32)blockId) & hash_mask;
|
UINT32 index = ((UINT32)blockId) & hash_mask;
|
||||||
NormBlock* prev = NULL;
|
NormBlock* prev = NULL;
|
||||||
NormBlock* entry = table[index];
|
NormBlock* entry = table[index];
|
||||||
while (entry && (entry->Id() < blockId))
|
while (entry && (entry->GetId() < blockId))
|
||||||
{
|
{
|
||||||
prev = entry;
|
prev = entry;
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
|
|
@ -799,7 +799,7 @@ bool NormBlockBuffer::Insert(NormBlock* theBlock)
|
||||||
else
|
else
|
||||||
table[index] = theBlock;
|
table[index] = theBlock;
|
||||||
|
|
||||||
ASSERT((entry ? (blockId != entry->Id()) : true));
|
ASSERT((entry ? (blockId != entry->GetId()) : true));
|
||||||
|
|
||||||
theBlock->next = entry;
|
theBlock->next = entry;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -810,12 +810,12 @@ bool NormBlockBuffer::Remove(const NormBlock* theBlock)
|
||||||
ASSERT(theBlock);
|
ASSERT(theBlock);
|
||||||
if (range)
|
if (range)
|
||||||
{
|
{
|
||||||
const NormBlockId& blockId = theBlock->Id();
|
const NormBlockId& blockId = theBlock->GetId();
|
||||||
if ((blockId < range_lo) || (blockId > range_hi)) return false;
|
if ((blockId < range_lo) || (blockId > range_hi)) return false;
|
||||||
UINT32 index = ((UINT32)blockId) & hash_mask;
|
UINT32 index = ((UINT32)blockId) & hash_mask;
|
||||||
NormBlock* prev = NULL;
|
NormBlock* prev = NULL;
|
||||||
NormBlock* entry = table[index];
|
NormBlock* entry = table[index];
|
||||||
while (entry && (entry->Id() != blockId))
|
while (entry && (entry->GetId() != blockId))
|
||||||
{
|
{
|
||||||
prev = entry;
|
prev = entry;
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
|
|
@ -847,10 +847,10 @@ bool NormBlockBuffer::Remove(const NormBlock* theBlock)
|
||||||
if ((entry = table[i]))
|
if ((entry = table[i]))
|
||||||
{
|
{
|
||||||
NormBlockId id = (UINT32)index + offset;
|
NormBlockId id = (UINT32)index + offset;
|
||||||
while(entry && (entry->Id() != id))
|
while(entry && (entry->GetId() != id))
|
||||||
{
|
{
|
||||||
if ((entry->Id() > blockId) &&
|
if ((entry->GetId() > blockId) &&
|
||||||
(entry->Id() < nextId)) nextId = entry->Id();
|
(entry->GetId() < nextId)) nextId = entry->GetId();
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -858,7 +858,7 @@ bool NormBlockBuffer::Remove(const NormBlock* theBlock)
|
||||||
}
|
}
|
||||||
} while (i != endex);
|
} while (i != endex);
|
||||||
if (entry)
|
if (entry)
|
||||||
range_lo = entry->Id();
|
range_lo = entry->GetId();
|
||||||
else
|
else
|
||||||
range_lo = nextId;
|
range_lo = nextId;
|
||||||
range = range_hi - range_lo + 1;
|
range = range_hi - range_lo + 1;
|
||||||
|
|
@ -884,17 +884,17 @@ bool NormBlockBuffer::Remove(const NormBlock* theBlock)
|
||||||
{
|
{
|
||||||
NormBlockId id = (UINT32)index - offset;
|
NormBlockId id = (UINT32)index - offset;
|
||||||
//printf("Looking for id:%lu at index:%lu\n", (UINT32)id, i);
|
//printf("Looking for id:%lu at index:%lu\n", (UINT32)id, i);
|
||||||
while(entry && (entry->Id() != id))
|
while(entry && (entry->GetId() != id))
|
||||||
{
|
{
|
||||||
if ((entry->Id() < blockId) &&
|
if ((entry->GetId() < blockId) &&
|
||||||
(entry->Id() > prevId)) prevId = entry->Id();
|
(entry->GetId() > prevId)) prevId = entry->GetId();
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
}
|
}
|
||||||
if (entry) break;
|
if (entry) break;
|
||||||
}
|
}
|
||||||
} while (i != endex);
|
} while (i != endex);
|
||||||
if (entry)
|
if (entry)
|
||||||
range_hi = entry->Id();
|
range_hi = entry->GetId();
|
||||||
else
|
else
|
||||||
range_hi = prevId;
|
range_hi = prevId;
|
||||||
range = range_hi - range_lo + 1;
|
range = range_hi - range_lo + 1;
|
||||||
|
|
@ -954,15 +954,15 @@ NormBlock* NormBlockBuffer::Iterator::GetNextBlock()
|
||||||
NormBlockId id = (UINT32)index + offset;
|
NormBlockId id = (UINT32)index + offset;
|
||||||
ASSERT(i < 256);
|
ASSERT(i < 256);
|
||||||
NormBlock* entry = buffer.table[i];
|
NormBlock* entry = buffer.table[i];
|
||||||
while ((NULL != entry ) && (entry->Id() != id))
|
while ((NULL != entry ) && (entry->GetId() != id))
|
||||||
{
|
{
|
||||||
if ((entry->Id() > index) && (entry->Id() < nextId))
|
if ((entry->GetId() > index) && (entry->GetId() < nextId))
|
||||||
nextId = entry->Id();
|
nextId = entry->GetId();
|
||||||
entry = NormBlockBuffer::Next(entry);
|
entry = NormBlockBuffer::Next(entry);
|
||||||
}
|
}
|
||||||
if (entry)
|
if (entry)
|
||||||
{
|
{
|
||||||
index = entry->Id();
|
index = entry->GetId();
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
} while (i != endex);
|
} while (i != endex);
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,9 @@ class NormBlock
|
||||||
|
|
||||||
NormBlock();
|
NormBlock();
|
||||||
~NormBlock();
|
~NormBlock();
|
||||||
const NormBlockId& Id() const {return id;}
|
const NormBlockId& GetId() const {return id;}
|
||||||
void SetId(NormBlockId& x) {id = x;}
|
void SetId(NormBlockId& x) {id = x;}
|
||||||
bool Init(UINT16 blockSize);
|
bool Init(UINT16 totalSize);
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
void SetFlag(NormBlock::Flag flag) {flags |= flag;}
|
void SetFlag(NormBlock::Flag flag) {flags |= flag;}
|
||||||
|
|
@ -134,7 +134,7 @@ class NormBlock
|
||||||
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
NormObjectId objectId,
|
NormObjectId objectId,
|
||||||
bool repairInfo,
|
bool repairInfo,
|
||||||
UINT16 ndata,
|
UINT16 numData,
|
||||||
UINT16 segmentSize);
|
UINT16 segmentSize);
|
||||||
|
|
||||||
// Client routines
|
// Client routines
|
||||||
|
|
@ -217,8 +217,8 @@ class NormBlock
|
||||||
{return (pending_mask.IsSet() || repair_mask.IsSet());}
|
{return (pending_mask.IsSet() || repair_mask.IsSet());}
|
||||||
|
|
||||||
bool AppendRepairRequest(NormNackMsg& nack,
|
bool AppendRepairRequest(NormNackMsg& nack,
|
||||||
UINT16 ndata,
|
UINT16 numData,
|
||||||
UINT16 nparity,
|
UINT16 numParity,
|
||||||
NormObjectId objectId,
|
NormObjectId objectId,
|
||||||
bool pendingInfo,
|
bool pendingInfo,
|
||||||
UINT16 segmentSize);
|
UINT16 segmentSize);
|
||||||
|
|
@ -248,7 +248,7 @@ class NormBlockPool
|
||||||
public:
|
public:
|
||||||
NormBlockPool();
|
NormBlockPool();
|
||||||
~NormBlockPool();
|
~NormBlockPool();
|
||||||
bool Init(UINT32 numBlocks, UINT16 blockSize);
|
bool Init(UINT32 numBlocks, UINT16 totalSize);
|
||||||
void Destroy();
|
void Destroy();
|
||||||
bool IsEmpty() const {return (NULL == head);}
|
bool IsEmpty() const {return (NULL == head);}
|
||||||
NormBlock* Get()
|
NormBlock* Get()
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
||||||
ttl(DEFAULT_TTL), tx_rate(DEFAULT_TRANSMIT_RATE/8.0),
|
ttl(DEFAULT_TTL), tx_rate(DEFAULT_TRANSMIT_RATE/8.0),
|
||||||
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), session_id(0),
|
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), session_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),
|
||||||
next_tx_object_id(0), tx_cache_count_min(1), tx_cache_count_max(256),
|
next_tx_object_id(0), tx_cache_count_min(8), tx_cache_count_max(256),
|
||||||
tx_cache_size_max((UINT32)20*1024*1024),
|
tx_cache_size_max((UINT32)20*1024*1024),
|
||||||
flush_count(NORM_ROBUST_FACTOR+1),
|
flush_count(NORM_ROBUST_FACTOR+1),
|
||||||
posted_tx_queue_empty(false), advertise_repairs(false),
|
posted_tx_queue_empty(false), advertise_repairs(false),
|
||||||
|
|
@ -72,7 +72,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
||||||
// (It may be used to trigger transmission of report messages
|
// (It may be used to trigger transmission of report messages
|
||||||
// in the future for debugging, etc
|
// in the future for debugging, etc
|
||||||
report_timer.SetListener(this, &NormSession::OnReportTimeout);
|
report_timer.SetListener(this, &NormSession::OnReportTimeout);
|
||||||
report_timer.SetInterval(10.0);
|
report_timer.SetInterval(60.0);
|
||||||
report_timer.SetRepeat(-1);
|
report_timer.SetRepeat(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,6 +233,8 @@ bool NormSession::StartServer(unsigned long bufferSpace,
|
||||||
flush_count = NORM_ROBUST_FACTOR+1; // (TBD) parameterize robust_factor
|
flush_count = NORM_ROBUST_FACTOR+1; // (TBD) parameterize robust_factor
|
||||||
//probe_timer.SetInterval(0.0);
|
//probe_timer.SetInterval(0.0);
|
||||||
probe_pending = probe_reset = false;
|
probe_pending = probe_reset = false;
|
||||||
|
|
||||||
|
if (cc_enable) tx_rate = segmentSize;
|
||||||
OnProbeTimeout(probe_timer);
|
OnProbeTimeout(probe_timer);
|
||||||
ActivateTimer(probe_timer);
|
ActivateTimer(probe_timer);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -317,7 +319,7 @@ void NormSession::Serve()
|
||||||
if (obj->IsStream())
|
if (obj->IsStream())
|
||||||
posted_tx_queue_empty = true; // repair-delayed stream advance
|
posted_tx_queue_empty = true; // repair-delayed stream advance
|
||||||
else
|
else
|
||||||
tx_pending_mask.Unset(obj->Id());
|
tx_pending_mask.Unset(obj->GetId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -379,13 +381,13 @@ void NormSession::ServerQueueFlush()
|
||||||
if (obj->IsStream())
|
if (obj->IsStream())
|
||||||
{
|
{
|
||||||
NormStreamObject* stream = (NormStreamObject*)obj;
|
NormStreamObject* stream = (NormStreamObject*)obj;
|
||||||
objectId = stream->Id();
|
objectId = stream->GetId();
|
||||||
blockId = stream->FlushBlockId();
|
blockId = stream->FlushBlockId();
|
||||||
segmentId = stream->FlushSegmentId();
|
segmentId = stream->FlushSegmentId();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
objectId = obj->Id();
|
objectId = obj->GetId();
|
||||||
blockId = obj->GetFinalBlockId();
|
blockId = obj->GetFinalBlockId();
|
||||||
segmentId = obj->GetBlockSize(blockId) - 1;
|
segmentId = obj->GetBlockSize(blockId) - 1;
|
||||||
}
|
}
|
||||||
|
|
@ -579,7 +581,7 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||||
unsigned long count = tx_table.Count();
|
unsigned long count = tx_table.Count();
|
||||||
while ((count >= tx_cache_count_min) &&
|
while ((count >= tx_cache_count_min) &&
|
||||||
((count >= tx_cache_count_max) ||
|
((count >= tx_cache_count_max) ||
|
||||||
((tx_table.Size() + obj->Size()) > tx_cache_size_max)))
|
((tx_table.Size() + obj->GetSize()) > tx_cache_size_max)))
|
||||||
{
|
{
|
||||||
// Remove oldest non-pending
|
// Remove oldest non-pending
|
||||||
NormObject* oldest = tx_table.Find(tx_table.RangeLo());
|
NormObject* oldest = tx_table.Find(tx_table.RangeLo());
|
||||||
|
|
@ -605,8 +607,8 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tx_pending_mask.Set(obj->Id());
|
tx_pending_mask.Set(obj->GetId());
|
||||||
ASSERT(tx_pending_mask.Test(obj->Id()));
|
ASSERT(tx_pending_mask.Test(obj->GetId()));
|
||||||
next_tx_object_id++;
|
next_tx_object_id++;
|
||||||
TouchServer();
|
TouchServer();
|
||||||
//posted_tx_queue_empty = false;
|
//posted_tx_queue_empty = false;
|
||||||
|
|
@ -616,7 +618,7 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||||
|
|
||||||
void NormSession::DeleteTxObject(NormObject* obj)
|
void NormSession::DeleteTxObject(NormObject* obj)
|
||||||
{
|
{
|
||||||
NormObjectId objectId = obj->Id();
|
NormObjectId objectId = obj->GetId();
|
||||||
ASSERT(obj == tx_table.Find(objectId));
|
ASSERT(obj == tx_table.Find(objectId));
|
||||||
tx_table.Remove(obj);
|
tx_table.Remove(obj);
|
||||||
obj->Close();
|
obj->Close();
|
||||||
|
|
@ -637,7 +639,7 @@ NormBlock* NormSession::ServerGetFreeBlock(NormObjectId objectId,
|
||||||
NormObject* obj;
|
NormObject* obj;
|
||||||
while ((obj = iterator.GetNextObject()))
|
while ((obj = iterator.GetNextObject()))
|
||||||
{
|
{
|
||||||
if (obj->Id() == objectId)
|
if (obj->GetId() == objectId)
|
||||||
b = obj->StealNonPendingBlock(true, blockId);
|
b = obj->StealNonPendingBlock(true, blockId);
|
||||||
else
|
else
|
||||||
b = obj->StealNonPendingBlock(false);
|
b = obj->StealNonPendingBlock(false);
|
||||||
|
|
@ -656,13 +658,13 @@ NormBlock* NormSession::ServerGetFreeBlock(NormObjectId objectId,
|
||||||
NormObject* obj;
|
NormObject* obj;
|
||||||
while ((obj = iterator.GetPrevObject()))
|
while ((obj = iterator.GetPrevObject()))
|
||||||
{
|
{
|
||||||
if (obj->Id() < objectId)
|
if (obj->GetId() < objectId)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (obj->Id() > objectId)
|
if (obj->GetId() > objectId)
|
||||||
b = obj->StealNewestBlock(false);
|
b = obj->StealNewestBlock(false);
|
||||||
else
|
else
|
||||||
b = obj->StealNewestBlock(true, blockId);
|
b = obj->StealNewestBlock(true, blockId);
|
||||||
|
|
@ -888,34 +890,21 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast)
|
||||||
|
|
||||||
if (trace) NormTrace(currentTime, LocalNodeId(), msg, false);
|
if (trace) NormTrace(currentTime, LocalNodeId(), msg, false);
|
||||||
|
|
||||||
// Do common updates for servers we already know.
|
|
||||||
NormNodeId sourceId = msg.GetSourceId();
|
|
||||||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
|
||||||
if (theServer)
|
|
||||||
{
|
|
||||||
// (TBD) combine these as needed for efficiency
|
|
||||||
// (i.e. fewer function calls per message)
|
|
||||||
if (theServer->IsOpen()) theServer->Activate();
|
|
||||||
theServer->UpdateRecvRate(currentTime, msg.GetLength());
|
|
||||||
theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
|
|
||||||
theServer->SetAddress(msg.GetSource());
|
|
||||||
// for statistics only (TBD) #ifdef NORM_DEBUG
|
|
||||||
theServer->IncrementRecvTotal(msg.GetLength());
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (msg.GetType())
|
switch (msg.GetType())
|
||||||
{
|
{
|
||||||
case NormMsg::INFO:
|
case NormMsg::INFO:
|
||||||
//DMSG(0, "NormSession::HandleReceiveMessage(NormMsg::INFO)\n");
|
//DMSG(0, "NormSession::HandleReceiveMessage(NormMsg::INFO)\n");
|
||||||
if (IsClient()) ClientHandleObjectMessage(currentTime, (NormObjectMsg&)msg, theServer);
|
if (IsClient()) ClientHandleObjectMessage(currentTime, (NormObjectMsg&)msg);
|
||||||
break;
|
break;
|
||||||
case NormMsg::DATA:
|
case NormMsg::DATA:
|
||||||
//DMSG(0, "NormSession::HandleReceiveMessage(NormMsg::DATA) ...\n");
|
//DMSG(0, "NormSession::HandleReceiveMessage(NormMsg::DATA) ...\n");
|
||||||
if (IsClient()) ClientHandleObjectMessage(currentTime, (NormObjectMsg&)msg, theServer);
|
if (IsClient()) ClientHandleObjectMessage(currentTime, (NormObjectMsg&)msg);
|
||||||
break;
|
break;
|
||||||
case NormMsg::CMD:
|
case NormMsg::CMD:
|
||||||
//DMSG(0, "NormSession::HandleReceiveMessage(NormMsg::CMD) ...\n");
|
//DMSG(0, "NormSession::HandleReceiveMessage(NormMsg::CMD) ...\n");
|
||||||
if (IsClient()) ClientHandleCommand(currentTime, (NormCmdMsg&)msg, theServer);
|
if (IsClient()) ClientHandleCommand(currentTime, (NormCmdMsg&)msg);
|
||||||
break;
|
break;
|
||||||
case NormMsg::NACK:
|
case NormMsg::NACK:
|
||||||
DMSG(4, "NormSession::HandleReceiveMessage(NormMsg::NACK) node>%lu ...\n",
|
DMSG(4, "NormSession::HandleReceiveMessage(NormMsg::NACK) node>%lu ...\n",
|
||||||
|
|
@ -923,7 +912,7 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast)
|
||||||
if (IsServer() && (((NormNackMsg&)msg).GetServerId() == LocalNodeId()))
|
if (IsServer() && (((NormNackMsg&)msg).GetServerId() == LocalNodeId()))
|
||||||
{
|
{
|
||||||
ServerHandleNackMessage(currentTime, (NormNackMsg&)msg);
|
ServerHandleNackMessage(currentTime, (NormNackMsg&)msg);
|
||||||
if (wasUnicast && (backoff_factor > 0.5))
|
if (wasUnicast && (backoff_factor > 0.5) && Address().IsMulticast())
|
||||||
{
|
{
|
||||||
// for suppression of unicast nack feedback
|
// for suppression of unicast nack feedback
|
||||||
advertise_repairs = true;
|
advertise_repairs = true;
|
||||||
|
|
@ -952,9 +941,11 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast)
|
||||||
|
|
||||||
|
|
||||||
void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
||||||
const NormObjectMsg& msg,
|
const NormObjectMsg& msg)
|
||||||
NormServerNode* theServer)
|
|
||||||
{
|
{
|
||||||
|
// Do common updates for servers we already know.
|
||||||
|
NormNodeId sourceId = msg.GetSourceId();
|
||||||
|
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
||||||
if (!theServer)
|
if (!theServer)
|
||||||
{
|
{
|
||||||
if ((theServer = new NormServerNode(this, msg.GetSourceId())))
|
if ((theServer = new NormServerNode(this, msg.GetSourceId())))
|
||||||
|
|
@ -962,11 +953,6 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
||||||
server_tree.AttachNode(theServer);
|
server_tree.AttachNode(theServer);
|
||||||
DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n",
|
DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n",
|
||||||
LocalNodeId(), msg.GetSourceId());
|
LocalNodeId(), msg.GetSourceId());
|
||||||
theServer->UpdateRecvRate(currentTime, msg.GetLength());
|
|
||||||
theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
|
|
||||||
theServer->SetAddress(msg.GetSource());
|
|
||||||
// for statistics only (TBD) #ifdef NORM_DEBUG
|
|
||||||
theServer->IncrementRecvTotal(msg.GetLength());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -976,13 +962,20 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (theServer->IsOpen()) theServer->Activate();
|
||||||
|
theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
|
||||||
|
theServer->SetAddress(msg.GetSource());
|
||||||
|
theServer->IncrementRecvTotal(msg.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
|
||||||
theServer->HandleObjectMessage(msg);
|
theServer->HandleObjectMessage(msg);
|
||||||
|
theServer->UpdateRecvRate(currentTime, msg.GetLength());
|
||||||
} // end NormSession::ClientHandleObjectMessage()
|
} // end NormSession::ClientHandleObjectMessage()
|
||||||
|
|
||||||
void NormSession::ClientHandleCommand(const struct timeval& currentTime,
|
void NormSession::ClientHandleCommand(const struct timeval& currentTime,
|
||||||
const NormCmdMsg& cmd,
|
const NormCmdMsg& cmd)
|
||||||
NormServerNode* theServer)
|
|
||||||
{
|
{
|
||||||
|
// Do common updates for servers we already know.
|
||||||
|
NormNodeId sourceId = cmd.GetSourceId();
|
||||||
|
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
||||||
if (!theServer)
|
if (!theServer)
|
||||||
{
|
{
|
||||||
//DMSG(0, "NormSession::ClientHandleCommand() node>%lu recvd command from unknown server ...\n",
|
//DMSG(0, "NormSession::ClientHandleCommand() node>%lu recvd command from unknown server ...\n",
|
||||||
|
|
@ -993,11 +986,6 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
|
||||||
server_tree.AttachNode(theServer);
|
server_tree.AttachNode(theServer);
|
||||||
DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n",
|
DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n",
|
||||||
LocalNodeId(), cmd.GetSourceId());
|
LocalNodeId(), cmd.GetSourceId());
|
||||||
theServer->UpdateRecvRate(currentTime, cmd.GetLength());
|
|
||||||
theServer->UpdateLossEstimate(currentTime, cmd.GetSequence());
|
|
||||||
theServer->SetAddress(cmd.GetSource());
|
|
||||||
// for statistics only (TBD) #ifdef NORM_DEBUG
|
|
||||||
theServer->IncrementRecvTotal(cmd.GetLength());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1007,7 +995,12 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (theServer->IsOpen()) theServer->Activate();
|
||||||
|
theServer->UpdateLossEstimate(currentTime, cmd.GetSequence());
|
||||||
|
theServer->SetAddress(cmd.GetSource());
|
||||||
|
theServer->IncrementRecvTotal(cmd.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
|
||||||
theServer->HandleCommand(currentTime, cmd);
|
theServer->HandleCommand(currentTime, cmd);
|
||||||
|
theServer->UpdateRecvRate(currentTime, cmd.GetLength());
|
||||||
} // end NormSession::ClientHandleCommand()
|
} // end NormSession::ClientHandleCommand()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1046,16 +1039,16 @@ double NormSession::CalculateRtt(const struct timeval& currentTime,
|
||||||
void NormSession::ServerUpdateGrttEstimate(double clientRtt)
|
void NormSession::ServerUpdateGrttEstimate(double clientRtt)
|
||||||
{
|
{
|
||||||
grtt_response = true;
|
grtt_response = true;
|
||||||
if (clientRtt > grtt_current_peak)
|
if ((clientRtt > grtt_current_peak) || !address.IsMulticast())
|
||||||
{
|
{
|
||||||
// Immediately incorporate bigger RTT's
|
// Immediately incorporate bigger RTT's
|
||||||
grtt_current_peak = clientRtt;
|
grtt_current_peak = clientRtt;
|
||||||
if (clientRtt > grtt_measured)
|
if ((clientRtt > grtt_measured) || !address.IsMulticast())
|
||||||
{
|
{
|
||||||
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
|
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
|
||||||
grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
|
grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
|
||||||
if (grtt_measured > grtt_max) grtt_measured = grtt_max;
|
if (grtt_measured > grtt_max) grtt_measured = grtt_max;
|
||||||
double pktInterval = 2.0 * ((double)(44+segment_size))/tx_rate;
|
double pktInterval = ((double)(44+segment_size))/tx_rate;
|
||||||
UINT8 grttQuantizedOld = grtt_quantized;
|
UINT8 grttQuantizedOld = grtt_quantized;
|
||||||
grtt_quantized = NormQuantizeRtt(MAX(pktInterval, grtt_measured));
|
grtt_quantized = NormQuantizeRtt(MAX(pktInterval, grtt_measured));
|
||||||
// Calculate grtt_advertised since quantization rounds upward
|
// Calculate grtt_advertised since quantization rounds upward
|
||||||
|
|
@ -1104,6 +1097,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
|
||||||
// Adjust ccRtt if we have state on this nodeId
|
// Adjust ccRtt if we have state on this nodeId
|
||||||
NormCCNode* node = (NormCCNode*)cc_node_list.FindNodeById(nodeId);
|
NormCCNode* node = (NormCCNode*)cc_node_list.FindNodeById(nodeId);
|
||||||
if (node) ccRtt = node->UpdateRtt(ccRtt);
|
if (node) ccRtt = node->UpdateRtt(ccRtt);
|
||||||
|
|
||||||
if (0 == (ccFlags & NormCC::START))
|
if (0 == (ccFlags & NormCC::START))
|
||||||
{
|
{
|
||||||
// slow start has ended
|
// slow start has ended
|
||||||
|
|
@ -1287,7 +1281,7 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasUnicast && probe_proactive)
|
if (wasUnicast && probe_proactive && Address().IsMulticast())
|
||||||
{
|
{
|
||||||
// for suppression of unicast feedback
|
// for suppression of unicast feedback
|
||||||
advertise_repairs = true;
|
advertise_repairs = true;
|
||||||
|
|
@ -1711,7 +1705,7 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
block->HandleSegmentRequest(nextSegmentId, lastSegmentId,
|
block->HandleSegmentRequest(nextSegmentId, lastSegmentId,
|
||||||
object->GetBlockSize(block->Id()),
|
object->GetBlockSize(block->GetId()),
|
||||||
nparity, numErasures);
|
nparity, numErasures);
|
||||||
startTimer = true;
|
startTimer = true;
|
||||||
} // end if/else (holdoff)
|
} // end if/else (holdoff)
|
||||||
|
|
@ -1798,7 +1792,7 @@ bool NormSession::ServerQueueSquelch(NormObjectId objectId)
|
||||||
squelch->SetFecSymbolId(0);
|
squelch->SetFecSymbolId(0);
|
||||||
squelch->ResetInvalidObjectList();
|
squelch->ResetInvalidObjectList();
|
||||||
while ((obj = iterator.GetNextObject()))
|
while ((obj = iterator.GetNextObject()))
|
||||||
if (objectId == obj->Id()) break;
|
if (objectId == obj->GetId()) break;
|
||||||
nextId = objectId + 1;
|
nextId = objectId + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1806,13 +1800,13 @@ bool NormSession::ServerQueueSquelch(NormObjectId objectId)
|
||||||
obj = iterator.GetNextObject();
|
obj = iterator.GetNextObject();
|
||||||
if (obj)
|
if (obj)
|
||||||
{
|
{
|
||||||
squelch->SetObjectId(obj->Id());
|
squelch->SetObjectId(obj->GetId());
|
||||||
if (obj->IsStream())
|
if (obj->IsStream())
|
||||||
squelch->SetFecBlockId(((NormStreamObject*)obj)->StreamBufferLo());
|
squelch->SetFecBlockId(((NormStreamObject*)obj)->StreamBufferLo());
|
||||||
else
|
else
|
||||||
squelch->SetFecBlockId(0);
|
squelch->SetFecBlockId(0);
|
||||||
squelch->SetFecSymbolId(0);
|
squelch->SetFecSymbolId(0);
|
||||||
nextId = obj->Id() + 1;
|
nextId = obj->GetId() + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1826,7 +1820,7 @@ bool NormSession::ServerQueueSquelch(NormObjectId objectId)
|
||||||
bool buildingList = true;
|
bool buildingList = true;
|
||||||
while (buildingList && (obj = iterator.GetNextObject()))
|
while (buildingList && (obj = iterator.GetNextObject()))
|
||||||
{
|
{
|
||||||
while (nextId != obj->Id())
|
while (nextId != obj->GetId())
|
||||||
{
|
{
|
||||||
if (!squelch->AppendInvalidObject(nextId, segment_size))
|
if (!squelch->AppendInvalidObject(nextId, segment_size))
|
||||||
{
|
{
|
||||||
|
|
@ -1864,7 +1858,7 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
|
||||||
{
|
{
|
||||||
NormObject* currentObject = nextObject;
|
NormObject* currentObject = nextObject;
|
||||||
nextObject = iterator.GetNextObject();
|
nextObject = iterator.GetNextObject();
|
||||||
NormObjectId currentId = currentObject->Id();
|
NormObjectId currentId = currentObject->GetId();
|
||||||
bool repairEntireObject = tx_repair_mask.Test(currentId);
|
bool repairEntireObject = tx_repair_mask.Test(currentId);
|
||||||
if (repairEntireObject)
|
if (repairEntireObject)
|
||||||
{
|
{
|
||||||
|
|
@ -1953,7 +1947,7 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
|
||||||
NormObject* obj;
|
NormObject* obj;
|
||||||
while ((obj = iterator.GetNextObject()))
|
while ((obj = iterator.GetNextObject()))
|
||||||
{
|
{
|
||||||
NormObjectId objectId = obj->Id();
|
NormObjectId objectId = obj->GetId();
|
||||||
if (tx_repair_mask.Test(objectId))
|
if (tx_repair_mask.Test(objectId))
|
||||||
{
|
{
|
||||||
DMSG(6, "NormSession::OnRepairTimeout() node>%lu tx reset obj>%hu ...\n",
|
DMSG(6, "NormSession::OnRepairTimeout() node>%lu tx reset obj>%hu ...\n",
|
||||||
|
|
@ -2167,31 +2161,32 @@ bool NormSession::SendMessage(NormMsg& msg)
|
||||||
// Separate send/recv tracing
|
// Separate send/recv tracing
|
||||||
if (trace) NormTrace(currentTime, LocalNodeId(), msg, true);
|
if (trace) NormTrace(currentTime, LocalNodeId(), msg, true);
|
||||||
|
|
||||||
// Keep track of _actual_ sent rate
|
// Keep track of _actual_ sent rate (TBD) we can do away with this now
|
||||||
double interval;
|
|
||||||
if (prev_update_time.tv_sec || prev_update_time.tv_usec)
|
if (prev_update_time.tv_sec || prev_update_time.tv_usec)
|
||||||
{
|
{
|
||||||
interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec);
|
double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec);
|
||||||
if (currentTime.tv_usec > prev_update_time.tv_sec)
|
if (currentTime.tv_usec > prev_update_time.tv_sec)
|
||||||
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec);
|
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec);
|
||||||
else
|
else
|
||||||
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
|
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
|
||||||
|
sent_rate += 0.125 * (((double)msgSize)/interval - sent_rate);
|
||||||
|
prev_update_time = currentTime;
|
||||||
|
/*if (interval < grtt_advertised)
|
||||||
|
{
|
||||||
|
sent_accumulator += msgSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sent_rate = ((double)(sent_accumulator+msgSize)) / interval;
|
||||||
|
prev_update_time = currentTime;
|
||||||
|
sent_accumulator = 0;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sent_rate = ((double)msgSize) / grtt_advertised;
|
sent_rate = ((double)msgSize) / grtt_advertised;
|
||||||
interval = -1.0;
|
prev_update_time = currentTime;
|
||||||
prev_update_time = currentTime;
|
sent_accumulator = msgSize;
|
||||||
}
|
|
||||||
if (interval < grtt_advertised)
|
|
||||||
{
|
|
||||||
sent_accumulator += msgSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sent_rate = ((double)(sent_accumulator+msgSize)) / interval;
|
|
||||||
prev_update_time = currentTime;
|
|
||||||
sent_accumulator = 0;
|
|
||||||
}
|
}
|
||||||
// Update nominal packet size
|
// Update nominal packet size
|
||||||
nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size);
|
nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size);
|
||||||
|
|
@ -2224,7 +2219,7 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
|
||||||
probe_reset = true;
|
probe_reset = true;
|
||||||
probe_timer.Deactivate();
|
probe_timer.Deactivate();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Update grtt_estimate _if_ sufficient time elapsed.
|
// 2) Update grtt_estimate _if_ sufficient time elapsed.
|
||||||
// This new code allows more liberal downward adjustment of
|
// This new code allows more liberal downward adjustment of
|
||||||
|
|
@ -2289,6 +2284,7 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
|
||||||
cmd->Init();
|
cmd->Init();
|
||||||
cmd->SetDestination(address);
|
cmd->SetDestination(address);
|
||||||
cmd->SetGrtt(grtt_quantized);
|
cmd->SetGrtt(grtt_quantized);
|
||||||
|
|
||||||
cmd->SetBackoffFactor((unsigned char)backoff_factor);
|
cmd->SetBackoffFactor((unsigned char)backoff_factor);
|
||||||
cmd->SetGroupSize(gsize_quantized);
|
cmd->SetGroupSize(gsize_quantized);
|
||||||
// SetSendTime() when message is being sent (in OnTxTimeout())
|
// SetSendTime() when message is being sent (in OnTxTimeout())
|
||||||
|
|
@ -2332,8 +2328,8 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
|
||||||
// Determine next probe_interval
|
// Determine next probe_interval
|
||||||
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
|
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
|
||||||
probeInterval = clr ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised;
|
probeInterval = clr ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised;
|
||||||
double nominalRate = ((double)segment_size)/((double)tx_rate);
|
//double nominalRate = ((double)segment_size)/((double)tx_rate);
|
||||||
probeInterval = MAX(probeInterval, nominalRate);
|
//probeInterval = MAX(probeInterval, nominalRate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -2356,6 +2352,7 @@ void NormSession::AdjustRate(bool onResponse)
|
||||||
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
|
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
|
||||||
double ccRtt = clr ? clr->GetRtt() : grtt_measured;
|
double ccRtt = clr ? clr->GetRtt() : grtt_measured;
|
||||||
double ccLoss = clr ? clr->GetLoss() : 0.0;
|
double ccLoss = clr ? clr->GetLoss() : 0.0;
|
||||||
|
double oldRate = tx_rate;
|
||||||
if (onResponse)
|
if (onResponse)
|
||||||
{
|
{
|
||||||
// Adjust rate based on CLR feedback and
|
// Adjust rate based on CLR feedback and
|
||||||
|
|
@ -2364,19 +2361,16 @@ void NormSession::AdjustRate(bool onResponse)
|
||||||
// (TBD) check feedback age
|
// (TBD) check feedback age
|
||||||
if (cc_slow_start)
|
if (cc_slow_start)
|
||||||
{
|
{
|
||||||
double scale = tx_rate / sent_rate;
|
tx_rate = clr->GetRate();
|
||||||
scale = MAX(1.0, scale);
|
DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n",
|
||||||
scale = 1.0;
|
clr->GetId(), tx_rate*8.0/1000.0, oldRate*8.0/1000.0, sent_rate*8.0/1000.0,
|
||||||
//DMSG(0, "NormSession::AdjustRate() slow start clr>%lu rate>%lf tx_rate>%lf sent_rate>%lf\n",
|
clr->GetRate()*8.0/1000.0);
|
||||||
// clr->Id(), clr->GetRate() * 8.0/1000.0, tx_rate * 8.0/1000.0, sent_rate * 8.0/1000.0);
|
|
||||||
tx_rate = clr->GetRate() * scale;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double clrRate = clr->GetRate();
|
double clrRate = clr->GetRate();
|
||||||
if (clrRate > tx_rate)
|
if (clrRate > tx_rate)
|
||||||
{
|
{
|
||||||
|
|
||||||
double linRate = tx_rate + segment_size;
|
double linRate = tx_rate + segment_size;
|
||||||
tx_rate = MIN(clrRate, linRate);
|
tx_rate = MIN(clrRate, linRate);
|
||||||
}
|
}
|
||||||
|
|
@ -2384,9 +2378,9 @@ void NormSession::AdjustRate(bool onResponse)
|
||||||
{
|
{
|
||||||
tx_rate = clrRate;
|
tx_rate = clrRate;
|
||||||
}
|
}
|
||||||
|
DMSG(6, "NormSession::AdjustRate(stdy state) clr>%lu newRate>%lf (rtt>%lf loss>%lf)\n",
|
||||||
|
clr->GetId(), tx_rate*8.0/1000.0, clr->GetRtt(), clr->GetLoss());
|
||||||
}
|
}
|
||||||
//DMSG(0, "NormSession::AdjustRate() regular rate adjust clr>%lu rate>%lf (rtt>%lf loss>%lf slow_start>%d)\n",
|
|
||||||
// clr->Id(), tx_rate*8.0/1000.0, clr->GetRtt(), clr->GetLoss(), cc_slow_start);
|
|
||||||
}
|
}
|
||||||
else if (clr)
|
else if (clr)
|
||||||
{
|
{
|
||||||
|
|
@ -2414,7 +2408,21 @@ void NormSession::AdjustRate(bool onResponse)
|
||||||
struct timeval currentTime;
|
struct timeval currentTime;
|
||||||
::ProtoSystemTime(currentTime);
|
::ProtoSystemTime(currentTime);
|
||||||
double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec);
|
double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec);
|
||||||
DMSG(6, "ServerRateTracking time>%lf rate>%lf rtt>%lf loss>%lf\n", theTime, tx_rate * (8.0/1000.0), ccRtt, ccLoss);
|
|
||||||
|
if (tx_rate != oldRate)
|
||||||
|
{
|
||||||
|
if (tx_timer.IsActive())
|
||||||
|
{
|
||||||
|
//double ratio = tx_rate / oldRate;
|
||||||
|
double txInterval = tx_timer.GetInterval() * oldRate / tx_rate;
|
||||||
|
double timeElapsed = tx_timer.GetInterval() - tx_timer.GetTimeRemaining();
|
||||||
|
txInterval = timeElapsed < txInterval ? (txInterval - timeElapsed) : 0.0;
|
||||||
|
tx_timer.SetInterval(txInterval);
|
||||||
|
tx_timer.Reschedule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DMSG(6, "ServerRateTracking time>%lf rate>%lf rtt>%lf loss>%lf\n\n", theTime, tx_rate*(8.0/1000.0), ccRtt, ccLoss);
|
||||||
} // end NormSession::AdjustRate()
|
} // end NormSession::AdjustRate()
|
||||||
|
|
||||||
bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
|
bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,14 @@ class NormSession
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double ServerGrtt() {return grtt_advertised;}
|
||||||
|
void ServerSetGrtt(double grttValue)
|
||||||
|
{
|
||||||
|
double grttMin = 2.0 * ((double)(44+segment_size))/tx_rate;
|
||||||
|
grttValue = (grttValue < grttMin) ? grttMin : grttValue;
|
||||||
|
grtt_quantized = NormQuantizeRtt(grttValue);
|
||||||
|
grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized);
|
||||||
|
}
|
||||||
double ServerGroupSize() {return gsize_measured;}
|
double ServerGroupSize() {return gsize_measured;}
|
||||||
void ServerSetGroupSize(double gsize)
|
void ServerSetGroupSize(double gsize)
|
||||||
{
|
{
|
||||||
|
|
@ -267,11 +275,9 @@ class NormSession
|
||||||
|
|
||||||
// Client message handling routines
|
// Client message handling routines
|
||||||
void ClientHandleObjectMessage(const struct timeval& currentTime,
|
void ClientHandleObjectMessage(const struct timeval& currentTime,
|
||||||
const NormObjectMsg& msg,
|
const NormObjectMsg& msg);
|
||||||
NormServerNode* theServer);
|
|
||||||
void ClientHandleCommand(const struct timeval& currentTime,
|
void ClientHandleCommand(const struct timeval& currentTime,
|
||||||
const NormCmdMsg& msg,
|
const NormCmdMsg& msg);
|
||||||
NormServerNode* theServer);
|
|
||||||
void ClientHandleNackMessage(const NormNackMsg& nack);
|
void ClientHandleNackMessage(const NormNackMsg& nack);
|
||||||
void ClientHandleAckMessage(const NormAckMsg& ack);
|
void ClientHandleAckMessage(const NormAckMsg& ack);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,10 @@ NormSimAgent::NormSimAgent(ProtoTimerMgr& timerMgr,
|
||||||
backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR),
|
backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR),
|
||||||
segment_size(1024), ndata(32), nparity(16), auto_parity(0), extra_parity(0),
|
segment_size(1024), ndata(32), nparity(16), auto_parity(0), extra_parity(0),
|
||||||
group_size(NormSession::DEFAULT_GSIZE_ESTIMATE),
|
group_size(NormSession::DEFAULT_GSIZE_ESTIMATE),
|
||||||
|
grtt_estimate(NormSession::DEFAULT_GRTT_ESTIMATE),
|
||||||
tx_buffer_size(1024*1024), rx_buffer_size(1024*1024),
|
tx_buffer_size(1024*1024), rx_buffer_size(1024*1024),
|
||||||
tx_object_size(0), tx_object_interval(0.0),
|
tx_object_size(0), tx_object_interval(0.0),
|
||||||
|
tx_object_size_min(0), tx_object_size_max(0),
|
||||||
tx_repeat_count(0), tx_repeat_interval(0.0),
|
tx_repeat_count(0), tx_repeat_interval(0.0),
|
||||||
stream(NULL), auto_stream(false), push_stream(false),
|
stream(NULL), auto_stream(false), push_stream(false),
|
||||||
flush_mode(NormStreamObject::FLUSH_PASSIVE),
|
flush_mode(NormStreamObject::FLUSH_PASSIVE),
|
||||||
|
|
@ -62,11 +64,13 @@ const char* const NormSimAgent::cmd_list[] =
|
||||||
"+auto", // server auto parity count
|
"+auto", // server auto parity count
|
||||||
"+extra", // server extra parity count
|
"+extra", // server extra parity count
|
||||||
"+gsize", // group size estimate
|
"+gsize", // group size estimate
|
||||||
|
"+grtt", // grtt estimate
|
||||||
"+txbuffer", // tx buffer size (bytes)
|
"+txbuffer", // tx buffer size (bytes)
|
||||||
"+rxbuffer", // rx buffer size (bytes)
|
"+rxbuffer", // rx buffer size (bytes)
|
||||||
"+start", // open session and beging activity
|
"+start", // open session and beging activity
|
||||||
"-stop", // cease activity and close session
|
"-stop", // cease activity and close session
|
||||||
"+sendFile", // queue a "sim" file for transmission
|
"+sendFile", // queue a "sim" file of <size> bytes for transmission
|
||||||
|
"+sendRandomFile", // queue random-size file size range <sizeMin>:<sizeMax>
|
||||||
"+sendStream", // send a simulated NORM stream
|
"+sendStream", // send a simulated NORM stream
|
||||||
"+openStream", // open a stream object for messaging
|
"+openStream", // open a stream object for messaging
|
||||||
"+push", // "on" means real-time push stream advancement (non-blocking)
|
"+push", // "on" means real-time push stream advancement (non-blocking)
|
||||||
|
|
@ -285,6 +289,15 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
|
||||||
}
|
}
|
||||||
if (session) session->ServerSetGroupSize(group_size);
|
if (session) session->ServerSetGroupSize(group_size);
|
||||||
}
|
}
|
||||||
|
else if (!strncmp("grtt", cmd, len))
|
||||||
|
{
|
||||||
|
if (1 != sscanf(val, "%lf", &grtt_estimate))
|
||||||
|
{
|
||||||
|
DMSG(0, "NormSimAgent::ProcessCommand(gize) invalid value!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (session) session->ServerSetGroupSize(grtt_estimate);
|
||||||
|
}
|
||||||
else if (!strncmp("txbuffer", cmd, len))
|
else if (!strncmp("txbuffer", cmd, len))
|
||||||
{
|
{
|
||||||
if (1 != sscanf(val, "%lu", &tx_buffer_size))
|
if (1 != sscanf(val, "%lu", &tx_buffer_size))
|
||||||
|
|
@ -338,6 +351,33 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!strncmp("sendRandomFile", cmd, len))
|
||||||
|
{
|
||||||
|
if (2 != sscanf(val, "%lu:%lu", &tx_object_size_min, &tx_object_size_max))
|
||||||
|
{
|
||||||
|
DMSG(0, "NormSimAgent::ProcessCommand(sendRandomFile) invalid size!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tx_object_size_min > tx_object_size_max)
|
||||||
|
{
|
||||||
|
unsigned int tempSize = tx_object_size_min;
|
||||||
|
tx_object_size_min = tx_object_size_max;
|
||||||
|
tx_object_size_max = tempSize;
|
||||||
|
}
|
||||||
|
tx_object_size = tx_object_size_max - tx_object_size_min;
|
||||||
|
tx_object_size = (unsigned long)(tx_object_size * UniformRand(1.0));
|
||||||
|
tx_object_size += tx_object_size_min;
|
||||||
|
if (session)
|
||||||
|
{
|
||||||
|
TRACE("Queued file size: %lu bytes\n", tx_object_size);
|
||||||
|
return (NULL != session->QueueTxSim(tx_object_size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DMSG(0, "NormSimAgent::ProcessCommand(sendRandomFile) no session started!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (!strncmp("sendStream", cmd, len))
|
else if (!strncmp("sendStream", cmd, len))
|
||||||
{
|
{
|
||||||
if (session)
|
if (session)
|
||||||
|
|
@ -422,7 +462,7 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSimAgent::ProcessCommand(flushStream) session not started!\n");
|
DMSG(0, "NormSimAgent::ProcessCommand(doFlush) session not started!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -532,8 +572,8 @@ bool NormSimAgent::SendMessage(unsigned int len, const char* txBuffer)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Message still pending, can't send yet
|
// Message still pending, can't send yet
|
||||||
DMSG(0, "NormSimAgent::SendMessage() input overflow!\n");
|
DMSG(0, "NormSimAgent::SendMessage() warning: input overflow!\n");
|
||||||
ASSERT(0);
|
//ASSERT(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -564,11 +604,12 @@ void NormSimAgent::OnInputReady()
|
||||||
}
|
}
|
||||||
} // end NormSimAgent::InputReady()
|
} // end NormSimAgent::InputReady()
|
||||||
|
|
||||||
|
// Do an _active_ flush of the stream (for use at end-of-transmission)
|
||||||
bool NormSimAgent::FlushStream()
|
bool NormSimAgent::FlushStream()
|
||||||
{
|
{
|
||||||
if (stream && session && session->IsServer())
|
if (stream && session && session->IsServer())
|
||||||
{
|
{
|
||||||
stream->Write(NULL, 0, flush_mode, false, false);
|
stream->Write(NULL, 0, NormStreamObject::FLUSH_ACTIVE, false, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -631,7 +672,7 @@ void NormSimAgent::Notify(NormController::Event event,
|
||||||
if (silent_client)
|
if (silent_client)
|
||||||
size = NormObjectSize(rx_buffer_size);
|
size = NormObjectSize(rx_buffer_size);
|
||||||
else
|
else
|
||||||
size = object->Size();
|
size = object->GetSize();
|
||||||
if (!((NormStreamObject*)object)->Accept(size.LSB()))
|
if (!((NormStreamObject*)object)->Accept(size.LSB()))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSimAgent::Notify(RX_OBJECT_NEW) stream object accept error!\n");
|
DMSG(0, "NormSimAgent::Notify(RX_OBJECT_NEW) stream object accept error!\n");
|
||||||
|
|
@ -822,11 +863,18 @@ bool NormSimAgent::OnIntervalTimeout(ProtoTimer& theTimer)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Queue a NORM_OBJECT_SIM as long as there are repeats
|
// Queue a NORM_OBJECT_SIM as long as there are repeats
|
||||||
if (tx_repeat_count > 0) tx_repeat_count--;
|
if (tx_repeat_count > 0) tx_repeat_count--;
|
||||||
|
if (tx_object_size_min > 0)
|
||||||
|
{
|
||||||
|
tx_object_size = tx_object_size_max - tx_object_size_min;
|
||||||
|
tx_object_size = (unsigned long)(tx_object_size * UniformRand(1.0));
|
||||||
|
tx_object_size += tx_object_size_min;
|
||||||
|
}
|
||||||
if (!session->QueueTxSim(tx_object_size))
|
if (!session->QueueTxSim(tx_object_size))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSimAgent::OnIntervalTimeout() Error queueing tx object.\n");
|
DMSG(0, "NormSimAgent::OnIntervalTimeout() Error queueing tx object.\n");
|
||||||
}
|
}
|
||||||
|
TRACE("Queued file size: %lu bytes\n", tx_object_size);
|
||||||
}
|
}
|
||||||
interval_timer.SetInterval(tx_object_interval);
|
interval_timer.SetInterval(tx_object_interval);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -837,7 +885,6 @@ bool NormSimAgent::OnIntervalTimeout(ProtoTimer& theTimer)
|
||||||
if (interval_timer.IsActive()) interval_timer.Deactivate();
|
if (interval_timer.IsActive()) interval_timer.Deactivate();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end NormSimAgent::OnIntervalTimeout()
|
} // end NormSimAgent::OnIntervalTimeout()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -866,7 +913,8 @@ bool NormSimAgent::StartServer()
|
||||||
session->SetTrace(tracing);
|
session->SetTrace(tracing);
|
||||||
session->SetTxLoss(tx_loss);
|
session->SetTxLoss(tx_loss);
|
||||||
session->SetRxLoss(rx_loss);
|
session->SetRxLoss(rx_loss);
|
||||||
session->ServerSetGroupSize(group_size);
|
session->ServerSetGroupSize(group_size);
|
||||||
|
session->ServerSetGrtt(grtt_estimate);
|
||||||
// StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity)
|
// StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity)
|
||||||
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity))
|
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -64,12 +64,15 @@ class NormSimAgent : public NormController
|
||||||
UINT8 auto_parity;
|
UINT8 auto_parity;
|
||||||
UINT8 extra_parity;
|
UINT8 extra_parity;
|
||||||
double group_size;
|
double group_size;
|
||||||
|
double grtt_estimate;
|
||||||
unsigned long tx_buffer_size; // bytes
|
unsigned long tx_buffer_size; // bytes
|
||||||
unsigned long rx_buffer_size; // bytes
|
unsigned long rx_buffer_size; // bytes
|
||||||
|
|
||||||
// for simulated transmission (streams or files)
|
// for simulated transmission (streams or files)
|
||||||
unsigned long tx_object_size;
|
unsigned long tx_object_size;
|
||||||
double tx_object_interval;
|
double tx_object_interval;
|
||||||
|
unsigned long tx_object_size_min;
|
||||||
|
unsigned long tx_object_size_max;
|
||||||
int tx_repeat_count;
|
int tx_repeat_count;
|
||||||
double tx_repeat_interval;
|
double tx_repeat_interval;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,6 @@
|
||||||
|
|
||||||
#ifndef _NORM_VERSION
|
#ifndef _NORM_VERSION
|
||||||
#define _NORM_VERSION
|
#define _NORM_VERSION
|
||||||
#define VERSION "1.1b5"
|
#define VERSION "1.1b6"
|
||||||
#endif // _NORM_VERSION
|
#endif // _NORM_VERSION
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue