Example #1
0
        private int ProcessAcquireRequest(Zeze.Net.Protocol p)
        {
            Acquire rpc = (Acquire)p;

            if (rpc.Sender.UserState == null)
            {
                rpc.SendResultCode(AcquireNotLogin);
                return(0);
            }
            switch (rpc.Argument.State)
            {
            case StateInvalid:     // realease
                Release(rpc.Sender.UserState as CacheHolder, rpc.Argument.GlobalTableKey);
                rpc.Result = rpc.Argument;
                rpc.SendResult();
                return(0);

            case StateShare:
                return(AcquireShare(rpc));

            case StateModify:
                return(AcquireModify(rpc));

            default:
                rpc.Result = rpc.Argument;
                rpc.SendResultCode(AcquireErrorState);
                return(0);
            }
        }
Example #2
0
        private int AcquireModify(Acquire rpc)
        {
            CacheHolder sender = (CacheHolder)rpc.Sender.UserState;

            rpc.Result = rpc.Argument;

            while (true)
            {
                CacheState cs = global.GetOrAdd(rpc.Argument.GlobalTableKey, (tabkeKeyNotUsed) => new CacheState());
                lock (cs)
                {
                    if (cs.AcquireStatePending == StateRemoved)
                    {
                        continue;
                    }

                    while (cs.AcquireStatePending != StateInvalid)
                    {
                        switch (cs.AcquireStatePending)
                        {
                        case StateShare:
                            if (cs.Modify == sender)
                            {
                                logger.Debug("1 {0} {1} {2}", sender, rpc.Argument.State, cs);
                                rpc.Result.State = StateInvalid;
                                rpc.SendResultCode(AcquireModifyDeadLockFound);
                                return(0);
                            }
                            break;

                        case StateModify:
                            if (cs.Modify == sender || cs.Share.Contains(sender))
                            {
                                logger.Debug("2 {0} {1} {2}", sender, rpc.Argument.State, cs);
                                rpc.Result.State = StateInvalid;
                                rpc.SendResultCode(AcquireModifyDeadLockFound);
                                return(0);
                            }
                            break;
                        }
                        logger.Debug("3 {0} {1} {2}", sender, rpc.Argument.State, cs);
                        Monitor.Wait(cs);
                    }
                    cs.AcquireStatePending = StateModify;

                    if (cs.Modify != null)
                    {
                        if (cs.Modify == sender)
                        {
                            logger.Debug("4 {0} {1} {2}", sender, rpc.Argument.State, cs);
                            // 已经是Modify又申请,可能是sender异常关闭,又重启连上。
                            // 更新一下。应该是不需要的。
                            sender.Acquired[rpc.Argument.GlobalTableKey] = StateModify;
                            rpc.SendResultCode(AcquireModifyAlreadyIsModify);
                            cs.AcquireStatePending = StateInvalid;
                            return(0);
                        }

                        int stateReduceResult = StateReduceException;
                        Zeze.Util.Task.Run(
                            () =>
                        {
                            stateReduceResult = cs.Modify.Reduce(rpc.Argument.GlobalTableKey, StateInvalid);
                            lock (cs)
                            {
                                Monitor.PulseAll(cs);
                            }
                        },
                            "GlobalCacheManager.AcquireModify.Reduce");
                        logger.Debug("5 {0} {1} {2}", sender, rpc.Argument.State, cs);
                        Monitor.Wait(cs);

                        switch (stateReduceResult)
                        {
                        case StateInvalid:
                            cs.Modify.Acquired.TryRemove(rpc.Argument.GlobalTableKey, out var _);
                            break;     // reduce success

                        default:
                            // case StateReduceRpcTimeout:
                            // case StateReduceException:
                            // case StateReduceNetError:
                            cs.AcquireStatePending = StateInvalid;
                            Monitor.Pulse(cs);

                            logger.Error("XXX 9 {0} {1} {2}", sender, rpc.Argument.State, cs);
                            rpc.Result.State = StateInvalid;
                            rpc.SendResultCode(AcquireModifyFaild);
                            return(0);
                        }

                        cs.Modify = sender;
                        sender.Acquired[rpc.Argument.GlobalTableKey] = StateModify;
                        cs.AcquireStatePending = StateInvalid;
                        Monitor.Pulse(cs);

                        logger.Debug("6 {0} {1} {2}", sender, rpc.Argument.State, cs);
                        rpc.SendResult();
                        return(0);
                    }

                    List <Util.KV <CacheHolder, Reduce> > reducePending
                        = new List <Util.KV <CacheHolder, Reduce> >();
                    HashSet <CacheHolder> reduceSuccessed = new HashSet <CacheHolder>();
                    bool senderIsShare = false;
                    // 先把降级请求全部发送给出去。
                    foreach (CacheHolder c in cs.Share)
                    {
                        if (c == sender)
                        {
                            senderIsShare = true;
                            reduceSuccessed.Add(sender);
                            continue;
                        }
                        Reduce reduce = c.ReduceWaitLater(rpc.Argument.GlobalTableKey, StateInvalid);
                        if (null != reduce)
                        {
                            reducePending.Add(Util.KV.Create(c, reduce));
                        }
                        else
                        {
                            // 网络错误不再认为成功。整个降级失败,要中断降级。
                            // 已经发出去的降级请求要等待并处理结果。后面处理。
                            break;
                        }
                    }

                    Zeze.Util.Task.Run(
                        () =>
                    {
                        // 一个个等待是否成功。WaitAll 碰到错误不知道怎么处理的,
                        // 应该也会等待所有任务结束(包括错误)。
                        foreach (var reduce in reducePending)
                        {
                            try
                            {
                                reduce.Value.Future.Task.Wait();
                                if (reduce.Value.Result.State == StateInvalid)
                                {
                                    // 后面还有个成功的处理循环,但是那里可能包含sender,
                                    // 在这里更新吧。
                                    reduce.Key.Acquired.TryRemove(rpc.Argument.GlobalTableKey, out var _);
                                    reduceSuccessed.Add(reduce.Key);
                                }
                                else
                                {
                                    reduce.Key.SetError();
                                }
                            }
                            catch (Exception ex)
                            {
                                reduce.Key.SetError();
                                // 等待失败不再看作成功。
                                logger.Error(ex, "Reduce {0} {1} {2} {3}", sender, rpc.Argument.State, cs, reduce.Value.Argument);
                            }
                        }
                        lock (cs)
                        {
                            // 需要唤醒等待任务结束的,但没法指定,只能全部唤醒。
                            Monitor.PulseAll(cs);
                        }
                    },
                        "GlobalCacheManager.AcquireModify.WaitReduce");
                    logger.Debug("7 {0} {1} {2}", sender, rpc.Argument.State, cs);
                    Monitor.Wait(cs);

                    // 移除成功的。
                    foreach (CacheHolder successed in reduceSuccessed)
                    {
                        cs.Share.Remove(successed);
                    }

                    // 如果前面降级发生中断(break),这里就不会为0。
                    if (cs.Share.Count == 0)
                    {
                        cs.Modify = sender;
                        sender.Acquired[rpc.Argument.GlobalTableKey] = StateModify;
                        cs.AcquireStatePending = StateInvalid;
                        Monitor.Pulse(cs); // Pending 结束,唤醒一个进来就可以了。

                        logger.Debug("8 {0} {1} {2}", sender, rpc.Argument.State, cs);
                        rpc.SendResult();
                    }
                    else
                    {
                        // senderIsShare 在失败的时候,Acquired 没有变化,不需要更新。
                        // 失败了,要把原来是share的sender恢复。先这样吧。
                        if (senderIsShare)
                        {
                            cs.Share.Add(sender);
                        }

                        cs.AcquireStatePending = StateInvalid;
                        Monitor.Pulse(cs); // Pending 结束,唤醒一个进来就可以了。

                        logger.Error("XXX 10 {0} {1} {2}", sender, rpc.Argument.State, cs);

                        rpc.Result.State = StateInvalid;
                        rpc.SendResultCode(AcquireModifyFaild);
                    }
                    // 很好,网络失败不再看成成功,发现除了加break,
                    // 其他处理已经能包容这个改动,都不用动。
                    return(0);
                }
            }
        }
Example #3
0
        private int AcquireShare(Acquire rpc)
        {
            CacheHolder sender = (CacheHolder)rpc.Sender.UserState;

            rpc.Result = rpc.Argument;
            while (true)
            {
                CacheState cs = global.GetOrAdd(rpc.Argument.GlobalTableKey,
                                                (tabkeKeyNotUsed) => new CacheState());
                lock (cs)
                {
                    if (cs.AcquireStatePending == StateRemoved)
                    {
                        continue;
                    }

                    while (cs.AcquireStatePending != StateInvalid)
                    {
                        switch (cs.AcquireStatePending)
                        {
                        case StateShare:
                            if (cs.Modify == sender)
                            {
                                logger.Debug("1 {0} {1} {2}", sender, rpc.Argument.State, cs);
                                rpc.Result.State = StateInvalid;
                                rpc.SendResultCode(AcquireShareDeadLockFound);
                                return(0);
                            }
                            break;

                        case StateModify:
                            if (cs.Modify == sender || cs.Share.Contains(sender))
                            {
                                logger.Debug("2 {0} {1} {2}", sender, rpc.Argument.State, cs);
                                rpc.Result.State = StateInvalid;
                                rpc.SendResultCode(AcquireShareDeadLockFound);
                                return(0);
                            }
                            break;
                        }
                        logger.Debug("3 {0} {1} {2}", sender, rpc.Argument.State, cs);
                        Monitor.Wait(cs);
                    }
                    cs.AcquireStatePending = StateShare;

                    if (cs.Modify != null)
                    {
                        if (cs.Modify == sender)
                        {
                            cs.AcquireStatePending = StateInvalid;
                            logger.Debug("4 {0} {1} {2}", sender, rpc.Argument.State, cs);
                            rpc.Result.State = StateModify;
                            // 已经是Modify又申请,可能是sender异常关闭,
                            // 又重启连上。更新一下。应该是不需要的。
                            sender.Acquired[rpc.Argument.GlobalTableKey] = StateModify;
                            rpc.SendResultCode(AcquireShareAlreadyIsModify);
                            return(0);
                        }

                        int stateReduceResult = StateReduceException;
                        Zeze.Util.Task.Run(
                            () =>
                        {
                            stateReduceResult = cs.Modify.Reduce(rpc.Argument.GlobalTableKey, StateShare);

                            lock (cs)
                            {
                                Monitor.PulseAll(cs);
                            }
                        },
                            "GlobalCacheManager.AcquireShare.Reduce");
                        logger.Debug("5 {0} {1} {2}", sender, rpc.Argument.State, cs);
                        Monitor.Wait(cs);

                        switch (stateReduceResult)
                        {
                        case StateShare:
                            cs.Modify.Acquired[rpc.Argument.GlobalTableKey] = StateShare;
                            cs.Share.Add(cs.Modify);
                            // 降级成功,有可能降到 Invalid,此时就不需要加入 Share 了。
                            break;

                        default:
                            // 包含协议返回错误的值的情况。
                            // case StateReduceRpcTimeout:
                            // case StateReduceException:
                            // case StateReduceNetError:
                            cs.AcquireStatePending = StateInvalid;
                            Monitor.Pulse(cs);

                            logger.Error("XXX 8 {0} {1} {2}", sender, rpc.Argument.State, cs);
                            rpc.Result.State = StateInvalid;
                            rpc.SendResultCode(AcquireShareFaild);
                            return(0);
                        }

                        cs.Modify = null;
                        sender.Acquired[rpc.Argument.GlobalTableKey] = StateShare;
                        cs.Share.Add(sender);
                        cs.AcquireStatePending = StateInvalid;
                        Monitor.Pulse(cs);
                        logger.Debug("6 {0} {1} {2}", sender, rpc.Argument.State, cs);
                        rpc.SendResult();
                        return(0);
                    }

                    sender.Acquired[rpc.Argument.GlobalTableKey] = StateShare;
                    cs.Share.Add(sender);
                    cs.AcquireStatePending = StateInvalid;
                    logger.Debug("7 {0} {1} {2}", sender, rpc.Argument.State, cs);
                    rpc.SendResult();
                    return(0);
                }
            }
        }