Ignite Debug之put操作

来源:互联网 发布:数据库常用sql语句大全 编辑:程序博客网 时间:2024/06/06 11:49

1. 代码

for(int i = 10;i < 20;i++){    cache.put(i, String.valueOf(i));}

2. IgniteCache#put方法

这里写图片描述

该方法判断完是否是异步操作,由于我们的操作时同步的,所以直接委托给了delegate.put()方法,这里delegate变量是该类的属性IgniteInternalCache的一个实例。

这里写图片描述

开始踢足球了,委派给了GridCacheAdapter类,他是IgniteInternalCache接口的实现类,从图中可以看到,它又继续调用自身的put方法。

这里写图片描述

细节的后续再补,总体就是判断键值非空后,然后对键进行验证,我们可以看到它调用了validateCacheKey(key)

这里写图片描述

继续踢皮球,在方法进来时,它使用类的属性keyCheck(这个属性标识这个键盘需要检验),由于是True,所以它调用了另外一个静态方法来做。这个静态方法是GridCacheUtils的方法

这里写图片描述

上图可以清晰的看到,传入的键10是在的。在判断不是空之后,最终又踢皮球给了下面这个方法:

这里写图片描述

到这里结束了键的验证,继续我们的保存操作,下面的截图最好看下源码,因为屏幕原因不能截取的太完整。

这里写图片描述

继验证之后,调用put0方法,传递了键值对和拦截器(这里是null),全部委托给这个方法了。

这里写图片描述

很奇怪,这里调用的是update方法,因为实验了几次,所以可能有数据,先不管,跑完看看。

这里写图片描述

好的,进入同一个类的update方法,上面几个步骤基本在做前置验证,就不多赘述了,我们看最重要的条件判断,因为没有使用异步,所以必然进else的代码块。

这里写图片描述

跳转方法,下面是该方法的实现

这里写图片描述
方法检测缓存是否已经停止,我们这才启动,当然不会。if判断里对我们这个保存没什么影响,别拆穿。。。还是最终走向map方法。
这里写图片描述

这个方法比较重要了,我们先看451行的代码,调用mapSingleUpdate(topVer, futId)方法,我们看截图吧

这里写图片描述

这个方法实在太长了,一点点截取吧,首先呢,判断键是否为null,然后543行,KeyCacheObject cacheKey = cctx.toCacheKeyObject(key),获取了一个KeyCacheObject 对象,这个toCacheKeyObject方法很重要,我们详细看看:

这里写图片描述

我们看到这个方法只是个中转方法,所以继续,由于return里调用了方法链,我们一个个的看,首先是cacheObjects()

这里写图片描述

这个方法的第一个调用返回的是GridKernalContext对象,这是本类GridCacheContext的一个属性。第二个方法返回IgniteCacheObjectProcessor对象,他是GridKernalContextImpl的一个属性。下面进入方法链的第二个toCacheKeyObject方法:

这里写图片描述

进行比较,因为这里我们是新增操作,传入的值object是10,所以instanceof失败。直接跳到了toBinary方法

这里写图片描述

反正一堆非空以及类型判断,还是交给了marshalToBinary方法了。

这里写图片描述

传入的是参数object是10,我们截图的红线都没过,在其上的BinaryUtils的方法就截止了。截图的目的是告诉大家,下面的方法,基本就是;类型的枚举,我们在截图中出现的有数组结构和IgniteBiTuple类型,除此之外,下面还有Map.Entry等,基本执行的工作都差不多,还是交给BinaryUtils来操作。好的,现在方法返回,我们继续其他的操作:

这里写图片描述

好的,又回到这个方法了,我们以框标出了一些步骤,因为不是if判断的类型,所以直接走到了return,那么我们来看toCacheKeyObject0方法吧。

这里写图片描述

好的,进入比较重要的一个地方了,首先第一个重要的方法就是partition(CacheObjectContext ctx, @Nullable GridCacheContext cctx, Object obj)方法,我们来看一下。

这里写图片描述

判断GridCacheContext是否为null,我们这里不是null,在启动的时候我我创建的命名缓存对象,叫“DEFAULT_CACHE”,不要怀疑是默认的,这是指定的,默认的叫null。因此三元运算符,走的是cctx.affinity().partition(obj, false)这一块代码,我们慢慢剖析。affinity()方法反悔的是本类的一个属性,GridCacheAffinityManager对象。而方法partition(Object key, boolean useKeyPart)则比较重要了,我们以截图标识:

这里写图片描述

if判断GridAffinityAssignmentCache aff0是否为null,肯定不为null。然后判断useKeyPart,这里没有进if,走的是return语句了。affFunction.partition(affinityKey(key));我们看到他是用本类的一个属性,他是AffinityFunction类型的,调用它的partition(affinityKey(key))方法,这个方法需要一个affinityKey对象,如下所示:

这里写图片描述

我们缓存的键是Integer 10个值,所以第一个if没有进去。在return,有三元运算符,因很明显不满足条件,我们走进AffinityKeyMapper的affinityKey方法。

这里写图片描述

又是BinaryUtils.toBiray二进制方法,if判断仍然是false,走进super.affinityKey(key);即其父类的方法实现:

这里写图片描述

正如我们所看,Integer也没属性,返回为null,最终返回10。好的affinitkey方法,结束.

这里写图片描述

affinityKey(key)方法结束,返回10,交给partition(object)方法。

这里写图片描述

好的,key是10不是null,mask显示了1023,默认一共1024个分区,反正是大于0,进去后,我们看到需要做位运算。hasCode返回10,((h = key.hashCode()) ^ (h >>> 16)) & mask最终结果也是10,继续逐层返回吧。

这里写图片描述

下面是创建UserKeyCacheObjectImpl对象,part=10。好的,至此,我们之前cctx.toCacheKeyObject(key)方法结束。回到mapSingleUpdate方法,即第2.12的那里。

这里写图片描述

好的,现在回到了mapSingleUpdate方法,那么我们从光标看到,toCacheObject方法将被调用。即将缓存的值,变为CacheObject对象,就不细看了,给一个属性toSttring:UserCacheObjectImpl [val=10, hasValBytes=false]程序到达553行:List<ClusterNode> nodes = cctx.affinity().nodesByKey(cacheKey, topVer);affinity()方法会获取到本类的属性---是一个GridCacheAffinityManager对象。然后调用这个对象的nodesByKey方法。下面截图:

这里写图片描述

方法很短,调用的partition(key)我们一定熟悉,上面大篇幅讲的它,但是这里调用,过程很短,我们看截图即可,其实就是返回上面我们所计算出来的分区号。

这里写图片描述

好的,这里返回了分区号,连同版本号一起,调用nodesByPartition方法,截图:

这里写图片描述

cctx并非本地,所以条件判断也没进入,最终进了return语句aff0.nodes(part, topVer);

这里写图片描述

通过方法名也能看出来,根据指定的分区号,来获取关联的节点,返回值就是List<ClusterNode>。我们来拆解这个方法调用的两个方法,第一个是cachedAffinity(AffinityTopologyVersion topVer),截图:

这里写图片描述

返回值AffinityAssignment类型的cache对象,是从本类的head属性中获取的,这个head对象是AtomicReference<GridAffinityAssignment>,他也是本类的一个属性。下面不如第二个方法,即GridAffinityAssignment(他是GridAffinityAssignment的实现)的get(int part) 方法。

这里写图片描述

分区的默认值是1024,我们提供了分区号10,然后根据索引去取值,因为我启动那个了两个服务器节点,在下面我将截取到额两个节点的信息给拿到了。这两种数据分布在1024个节点上。逐层返回,mapSingleUpdate里就会拿到List<ClusterNode>,即是第10分区对应的节点。[TcpDiscoveryNode [id=98855bc3-32ca-48f0-8dc5-936d340409d5, addrs=[0:0:0:0:0:0:0:1, 10.10.18.75, 127.0.0.1, 172.18.103.1], sockAddrs=[/10.10.18.75:47500, /0:0:0:0:0:0:0:1:47500, /127.0.0.1:47500, /172.18.103.1:47500], discPort=47500, order=1, intOrder=1, lastExchangeTime=1498720217843, loc=false, ver=2.0.0#20170430-sha1:d4eef3c6, isClient=false]][TcpDiscoveryNode [id=49f82c4c-b907-4f6a-a7c7-7c6f395aacbd, addrs=[0:0:0:0:0:0:0:1, 10.10.18.75, 127.0.0.1, 172.18.103.1], sockAddrs=[IT-201606271616/10.10.18.75:47501, /172.18.103.1:47501, /0:0:0:0:0:0:0:1:47501, /127.0.0.1:47501], discPort=47501, order=2, intOrder=2, lastExchangeTime=1498720217843, loc=false, ver=2.0.0#20170430-sha1:d4eef3c6, isClient=false]]

这里写图片描述

我们看到回到这个方法了,返回的列表节点只有一个值,毕竟才启动了俩节点,1024个分区要分。要注意的是,分区节点列表的首个肯定是主节点。所以才有了下面的ClusterNode primary = nodes.get(0);然后根据canUseSingleRequest()条件判断,为下文要使用的GridNearAtomicAbstractUpdateRequest提供值。

这里写图片描述

方法走到这里,我们看亮处,需要new一个PrimaryRequestState对象,追踪该类的构造器:

这里写图片描述

可能是我们的操作比较简单,if判断并没有进去,而是直接用的外围的req对象。逐层返回,到达map方法,也就是2-11~2-12的map方法。

这里写图片描述

我们传回的PrimaryRequestState对象,我再截图中标识了,synchronized代码块执行完后判断一些状态值,因为我们是同步请求,直接到了如下截图:

这里写图片描述

可算发送消息了。。。下面看请求的发送方法

这里写图片描述

经过判断。节点并不是本地节点 ,所以需要走else语句,毕竟我是以client节点启动的测试类。 未完待续~~
原创粉丝点击