You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
301 lines
8.3 KiB
301 lines
8.3 KiB
using System;
|
|
using Sog;
|
|
using Sog.Data;
|
|
|
|
|
|
namespace Account
|
|
{
|
|
// 测试没问题后可以放到ServerComm作为公共服务类
|
|
// struct list有性能问题, 后期再修改支持
|
|
public class SyncListOp<T> where T : DataSeqSave, ISyncData
|
|
{
|
|
public SyncList<T> list;
|
|
|
|
public Action<uint, T> syncFunc;
|
|
|
|
private long nextTickTime;
|
|
private int tickTimeGap;
|
|
private int tickNum;
|
|
private int repeatTimeGap;
|
|
|
|
private bool forceRemove;
|
|
|
|
|
|
public SyncListOp(SyncList<T> syncList, Action<uint, T> sync)
|
|
{
|
|
list = syncList;
|
|
syncFunc = sync;
|
|
tickTimeGap = 100;
|
|
tickNum = 100;
|
|
repeatTimeGap = 1000;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
syncFunc = null;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
list.data.Clear();
|
|
list.index.Clear();
|
|
list.visitIdx = 0;
|
|
list.beginVisitTime = 0;
|
|
}
|
|
|
|
public T Get(ulong rid)
|
|
{
|
|
if (! list.index.TryGetValue(rid, out int arrayIdx))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (0 <= arrayIdx && arrayIdx < list.data.Count)
|
|
{
|
|
return list.data[arrayIdx];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public bool Add(T data)
|
|
{
|
|
ulong rid = data.GetRuntimeId();
|
|
if (rid <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//if (forceRemove)
|
|
//{
|
|
// ForceRemoveNull();
|
|
//}
|
|
|
|
// data不存在
|
|
if (! list.index.TryGetValue(rid, out int arrayIdx))
|
|
{
|
|
list.data.Add(data);
|
|
list.index.Add(rid, list.data.Count - 1);
|
|
return true;
|
|
}
|
|
|
|
if (0 <= arrayIdx && arrayIdx < list.data.Count)
|
|
{
|
|
// 索引存在, 但原数据不存在, 代码有bug, 打个错误日志
|
|
if (list.data[arrayIdx] == null)
|
|
{
|
|
TraceLog.Error("SyncListOp.Add {0} rid {1} arrayIdx {2} no data"
|
|
, list.name, data.GetRuntimeId(), arrayIdx);
|
|
|
|
list.data.Add(data);
|
|
list.index[rid] = list.data.Count - 1;
|
|
return true;
|
|
}
|
|
|
|
if (list.data[arrayIdx].GetRuntimeId() == rid)
|
|
{
|
|
list.data[arrayIdx] = data;
|
|
return true;
|
|
}
|
|
|
|
// data rid不一致
|
|
TraceLog.Error("SyncListOp.Add {0} arrayIdx {1} rid {2} {3} not equal"
|
|
, list.name, arrayIdx, list.data[arrayIdx].GetRuntimeId(), rid);
|
|
}
|
|
else
|
|
{
|
|
// data index 错误
|
|
TraceLog.Error("SyncListOp.Add {0} rid {1} invalid arrayIdx {2}, list count {3}"
|
|
, list.name, data.GetRuntimeId(), arrayIdx, list.data.Count);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// 删除时将last覆盖到删除元素, 然后删掉last
|
|
public void Remove(ulong rid)
|
|
{
|
|
// 不存在
|
|
if (!list.index.TryGetValue(rid, out int arrayIdx))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (arrayIdx < 0 || arrayIdx >= list.data.Count)
|
|
{
|
|
TraceLog.Error("SyncListOp.Remove {0} rid {1} invalid arrayIdx {2}, list count {3}"
|
|
, list.name, rid, arrayIdx, list.data.Count);
|
|
return;
|
|
}
|
|
|
|
// data不存在, 删除索引即可, 代码有bug, 打个错误日志
|
|
if (list.data[arrayIdx] == null)
|
|
{
|
|
TraceLog.Error("SyncListOp.Remove {0} rid {1} arrayIdx {2} no data", list.name, rid, arrayIdx);
|
|
list.index.Remove(rid);
|
|
return;
|
|
}
|
|
|
|
// 索引和数据不匹配, 有bug
|
|
if (list.data[arrayIdx].GetRuntimeId() != rid)
|
|
{
|
|
TraceLog.Error("SyncListOp.Add {0} arrayIdx {1} rid {2} {3} not equal"
|
|
, list.name, arrayIdx, list.data[arrayIdx].GetRuntimeId(), rid);
|
|
return;
|
|
}
|
|
|
|
list.data[arrayIdx] = null;
|
|
list.index.Remove(rid);
|
|
}
|
|
|
|
// Next每次遍历结束后, 删除数组中的无效数据, 即null
|
|
public T Next()
|
|
{
|
|
if (list.data.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
while (list.visitIdx < list.data.Count)
|
|
{
|
|
var next = list.data[list.visitIdx];
|
|
list.visitIdx++;
|
|
|
|
if (next != null)
|
|
{
|
|
return next;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
public void BeginVisit(long nowMs)
|
|
{
|
|
// 开始新一轮遍历前删除无效null节点
|
|
RemoveNull();
|
|
|
|
list.visitIdx = 0;
|
|
if (nowMs > 0)
|
|
{
|
|
list.beginVisitTime = nowMs;
|
|
}
|
|
}
|
|
|
|
// 考虑到未来把SyncListOp放入底层Sog, 传入syncSvrId
|
|
public void TickSync(long nowMs, uint syncSvrId)
|
|
{
|
|
if (nowMs < nextTickTime)
|
|
{
|
|
return;
|
|
}
|
|
|
|
nextTickTime = nowMs + tickTimeGap;
|
|
|
|
if (list.data.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (list.visitIdx >= list.data.Count)
|
|
{
|
|
long timeMs = nowMs - list.beginVisitTime;
|
|
if (timeMs < repeatTimeGap)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BeginVisit(nowMs);
|
|
}
|
|
|
|
for (int i = 0; i < tickNum; i++)
|
|
{
|
|
var data = Next();
|
|
if (data == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (data.CanDoSaveReqNow(nowMs))
|
|
{
|
|
syncFunc(syncSvrId, data);
|
|
data.OnSaveReq(nowMs);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetParams(int tickGap = 100, int tickNum = 100, int repeatGap = 1000)
|
|
{
|
|
this.tickTimeGap = tickGap;
|
|
this.tickNum = tickNum;
|
|
this.repeatTimeGap = repeatGap;
|
|
}
|
|
|
|
private void RemoveNull()
|
|
{
|
|
int left = 0, right = list.data.Count - 1;
|
|
|
|
while (left <= right)
|
|
{
|
|
if (list.data[left] == null)
|
|
{
|
|
list.data[left] = list.data[right];
|
|
right--;
|
|
}
|
|
else
|
|
{
|
|
left++;
|
|
}
|
|
}
|
|
|
|
// left是有效数据的长度, num是需要删除的元素数量
|
|
int num = list.data.Count - left;
|
|
while (num > 0)
|
|
{
|
|
list.data.RemoveAt(list.data.Count - 1);
|
|
num--;
|
|
}
|
|
|
|
// list.index索引clear后重建, 需要测试下效率
|
|
list.index.Clear();
|
|
for (int i = 0; i < list.data.Count; i++)
|
|
{
|
|
T item = list.data[i];
|
|
list.index.Add(item.GetRuntimeId(), i);
|
|
}
|
|
}
|
|
|
|
private void SetForceRemove(bool force)
|
|
{
|
|
forceRemove = force;
|
|
}
|
|
|
|
private void ForceRemoveNull()
|
|
{
|
|
double r1 = (list.data.Count - list.index.Count) * 1.0 / list.data.Count;
|
|
double r2 = list.data.Count * 1.0 / list.data.Capacity;
|
|
|
|
// 空闲超过50%, 或者使用超过80%同时空闲超过10%, 强制回收
|
|
if (r1 >= 0.5 || (r2 >= 0.8 && r1 >= 0.1))
|
|
{
|
|
RemoveNull();
|
|
// 重置遍历游标
|
|
BeginVisit(0);
|
|
}
|
|
}
|
|
|
|
public void PrintDebugInfo()
|
|
{
|
|
for (int i = 0; i < list.data.Count; i++)
|
|
{
|
|
T data = list.data[i];
|
|
if (data != null)
|
|
{
|
|
TraceLog.Trace("SyncListOp.PrintDebugInfo {0} rid {1} dataSeq {2} saveSeq {3}"
|
|
, i, data.GetRuntimeId(), data.DataSeq, data.SavedSuccessSeq);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|