using System; using Sog; using Sog.Data; namespace Account { // 测试没问题后可以放到ServerComm作为公共服务类 // struct list有性能问题, 后期再修改支持 public class SyncListOp where T : DataSeqSave, ISyncData { public SyncList list; public Action syncFunc; private long nextTickTime; private int tickTimeGap; private int tickNum; private int repeatTimeGap; private bool forceRemove; public SyncListOp(SyncList syncList, Action 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); } } } } }