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.

302 lines
8.3 KiB

1 month ago
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);
}
}
}
}
}