这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战
袁小白开开心心的在例会上分享了关于llb.State和Definition的理解。 得到了龙飞和贾大智的一致好评。 能在短短的时间里掌握到关健的数据结构用法,确实是件了不起的事情。
因为绝大多数情况下,大家宁愿自己写都不想看别人代码的原因就在于代码的复杂性。 本来觉得自己还挺优秀的,但一到看别人代码时,就会多少对之前的信心产生怀疑。 加上看不懂的时候还不少,就一次次将怀疑实锤了。 这当然是不好的体验。
从实际的情况来看,读他人代码确实也存在挑战。 如果代码写的标准,纯粹,读起来简单易懂,这当然是好代码。 但同时这也是较高的要求,要求对设计模式、算法、数据结构、框架及编程范式等等都理解的很到位,这样写出来的东西都是一些程序员之间的共同语言,当然容易沟通一些。 但往往这种理想的状态不容易达到,加上很多时候,我们再把复杂的业务逻辑揉入其中,就更是难上加难了。
贾大智对袁小白赞赏之余,也提了点建议。 那就是能不能用这些掌握了的知识,把之前llb.State第一印象中完整的例子,梳理一遍,既能验证理解的正确性,也顺便可以加深理解。
话是这么说,袁小白不禁心里还是泛起了嘀咕:你怎么不去梳理啊。
想归想,袁小白还是找机会,认真的看起了源码。
递归Marshal思想
递归实例理解
基于对examples/buildkit0/buildkit.go实例的理解,加上理解到的递归思想,袁小白对用例进行了梳理:
从图中可以看出清晰的递归调用流程:
- 基于构建好的llb.State链表,如果要进行Marshal,最先会从最后一个结点开始进行递归,但为例子中所有的操作都是SourceOp和ExecOp类型,所以都会有自己的Marshal方法。
- 如果有多重依赖,会按顺序完成对应的递归,如图中步骤3, 9, 16都是SourceOp
- 因为是深度优先算法,所以会将每一个依赖穷尽,处理完后再进行下一个依赖的处理,只有在都处理完后,才会处理真正的最后一步18.
从结构上来看,像是一颗反过来的树。
llb.State实例理解
如果要将准备好的State都转化成Definition,那对应的llb.State调用顺序又会长什么样呢:
通过梳理:
- 可以看到起先是各自独立的State,如S1, S2, S3,也就是通过llb.Image创建的结果,这时他们互相并不知道对方的存在,并没有关联
- 随着一步步的执行, e5将大家关联到了一起,因为拷贝操作要将src拷贝到dest,而ExecOp的会从Mount中获取位置信息,所以就将几个ExecState关联了起来
- 最后执行我们的最终操作
ls -l /bin
经过一番梳理,袁小白确实比以前更有信心了。 这也为后面的PoC打下了良好的基础。