[{"data":1,"prerenderedAt":1126},["ShallowReactive",2],{"content:\u002Fen\u002Ffiddling\u002Fchitchat-about-programming-language":3,"series:content_en":416},{"id":4,"title":5,"authorship":6,"body":7,"categories":387,"date":389,"description":390,"draft":391,"extension":392,"image":393,"meta":394,"navigation":396,"path":397,"permalink":398,"published":398,"readingTime":399,"recommend":404,"references":398,"seo":405,"seoDescription":406,"seoTitle":407,"sitemap":408,"stem":409,"tags":410,"type":414,"__hash__":415},"content_en\u002Fposts\u002Ffiddling\u002Fchitchat-about-programming-language.md","Some Thoughts on Programming Languages","human-only",{"type":8,"value":9,"toc":374},"minimark",[10,14,19,22,25,28,31,34,38,41,47,50,53,56,59,62,65,73,84,87,90,93,97,100,110,113,116,127,130,135,138,141,147,150,157,162,165,171,186,189,196,205,208,211,216,219,222,225,228,231,235,238,257,263,266,269,272,278,281,284,288,291,294,297,300,308,311,314,318,321,336,355,358,362,365,368,371],[11,12,13],"p",{},"This post introduces some basic concepts, implementation approaches, and the current state of programming-language theory by talking through how to design a language.",[15,16,18],"h3",{"id":17},"im-designing-a-programming-language-am-i","I'm designing a programming language... am I?",[11,20,21],{},"Let's design a brand-new programming language: C--.",[11,23,24],{},"Yes, ourselves.",[11,26,27],{},"For now, set aside complicated compiler theory, compiler and interpreter implementation, and the details of implementing particular features. Look at the title: these are just some thoughts!",[11,29,30],{},"We will build our own language from the bottom up.",[11,32,33],{},"Let's assume the bottom layer: our language compiles to RISC-VI format, with a corresponding RISC-VI instruction set. This assembly language is very basic, offering only simple operations on memory and registers.",[15,35,37],{"id":36},"where-does-the-code-run","Where does the code run?",[11,39,40],{},"This sounds like a question about the RISC-VI instruction set or architecture, unrelated to the high-level features we want to design. But it determines which layer of the computer system our code occupies, something a language designer must consider first:",[42,43,44],"blockquote",{},[11,45,46],{},"A computer system is, fundamentally, a hierarchy of virtual machines.",[11,48,49],{},"In this layered model, each upper layer wraps and hides the interfaces below it, adding its own features for the next layer to use.",[11,51,52],{},"An operating system virtualizes the hardware, or bare machine. Suppose your computer uses x86. When you compile and run a small C program, the OS first parses the binary's format. On Linux, that executable is in ELF format. After parsing it, the OS loads its segments into memory and jumps to the first instruction in the code segment. Reality is less simple, of course: an actual OS manages memory more carefully and isolates running tasks using processes and other mechanisms.",[11,54,55],{},"By a remarkable coincidence(?), compiled C binaries can run not only atop an OS but on bare metal. The obvious example is the Linux kernel, mostly written in C; Rust code recently entered mainline too, which is promising. In system programming, C programs mainly use OS-provided system calls. On x86 Linux, a program reading a file into memory typically uses sys_read. Linux reads the data on its behalf, after permission checks and other preliminaries. But if you write an OS in C, there are no system calls to use. Even files are an OS abstraction. You must interact with the disk hardware somehow, modifying controller registers just to read data from a particular location.",[11,57,58],{},"This fits the definition of a virtual machine perfectly. You could even call Linux a VM for executing ELF files, though it does much more. If we set aside the C standard library provided by the OS, C runs at the bare-metal layer. Strictly speaking, its compiled output runs there, but let's use that shorthand for now.",[11,60,61],{},"Another example 🌰: Python, a typical interpreted language. Its official interpreter, CPython, is written in C. In our layered model, CPython is a VM built on the OS, wrapping OS interfaces for higher-level Python programs to call.",[11,63,64],{},"Taken to an extreme, even a compiled language like C can be regarded as interpreted: the CPU reads, decodes, and executes instructions one at a time; they just happen to be binary. Python's instructions are readable, and CPython takes human-readable strings as input.",[11,66,67,68,72],{},"A major advantage of interpreted languages is portability. The interpreter hides OS differences and supplies the same APIs to the high-level language, letting you ",[69,70,71],"strong",{},"write once, run anywhere",". By the law of conservation of suffering, your convenience is paid for by the interpreter's author. Still, a compiled language needs compiler implementations for different instruction sets too, so perhaps the suffering is not so different.",[11,74,75,76,79,80,83],{},"Speaking of ",[69,77,78],{},"run anywhere",", we have to mention the famous ",[69,81,82],{},"compile once, run anywhere",": Java! It combines compilation with interpretation. The JVM is Java's runtime, analogous to CPython for Python. A java file first compiles into a class file, the format the JVM reads. This is binary too, but the format is the same across operating systems using different instruction sets. That is why a class file compiled on x86 also runs on a RISC-V JVM. After reading it, the JVM loads, decodes, and executes instructions one by one, like an interpreter. Calling Java purely compiled or interpreted is therefore difficult.",[11,85,86],{},"The JVM is a successful virtual machine in the computer-systems sense. It supports not only Java but languages such as Scala and Groovy. The crucial fact is that all of them can compile to class format.",[11,88,89],{},"We generally regard interpreted languages as slower and compiled ones as faster. As languages have developed, many interpreted implementations have added features to improve performance. During Java class-file interpretation, for example, the JVM dynamically identifies hot code and compiles it directly to machine code. When that code runs again, it executes the compiled version rather than being interpreted anew. This is JIT, just-in-time compilation. Python's Numba library similarly uses JIT to accelerate execution.",[11,91,92],{},"Of course, if you write a C interpreter, you can call C an interpreted language too...",[15,94,96],{"id":95},"type-systems","Type systems",[11,98,99],{},"We have established where C-- runs, but it is still rudimentary, arguably nonexistent:",[101,102,103,107],"ul",{},[104,105,106],"li",{},"On the compiled-language path, RISC-VI is an instruction-set architecture, generally independent of the high-level language.",[104,108,109],{},"On the interpreted-language path, we might design and implement RISC-VI and its interpreter ourselves.",[11,111,112],{},"RISC-VI manipulates only memory and registers. To it, both are meaningless byte arrays, and any byte may be manipulated within the limits permitted by the VM below.",[11,114,115],{},"Suppose our language has no type system and operates directly on byte arrays. In C terms, that means defining no types and using void * pointers for everything. We can only take addresses, dereference, and read or assign bytes. That is barely different from assembly! Creating a four-byte integer on the heap and setting it to 1 would look like this, using C syntax, though without types it really is like assembly:",[117,118,124],"pre",{"className":119,"code":121,"language":122,"meta":123},[120],"language-c","void *intBytes = malloc(4);    \u002F\u002F 堆上分配四字节\n*(intBytes+3) = 0x01;          \u002F\u002F 假设大端序，偏移为 3 处设置为 1\n","c","",[125,126,121],"code",{"__ignoreMap":123},[11,128,129],{},"Where did our familiar int, float, and friends go? That is the type system's job.",[42,131,132],{},[11,133,134],{},"A type is fundamentally a way to interpret a region of memory.",[11,136,137],{},"A type system divides unstructured stack and heap space into meaningful blocks, assigning interpretations according to type. For programmers, the most visible difference is the syntax used to define them. In C, int usually denotes a four-byte integer, while double denotes an IEEE 754 double-precision floating-point value. The type determines how the compiler's generated runtime code operates on those bytes.",[11,139,140],{},"With a type system, creating that four-byte integer becomes:",[117,142,145],{"className":143,"code":144,"language":122,"meta":123},[120],"int *intBytes = (int *)malloc(4);\n*intBytes = 1;\n",[125,146,144],{"__ignoreMap":123},[11,148,149],{},"By declaring intBytes as an int pointer, we say that its target memory should be interpreted as an integer. On the second line, we can assign 1 through intBytes without worrying that it lands in byte 0 instead of byte 3. Knowing the pointer's type, the compiler customizes all operations accordingly. The final machine code still sets the third byte to 1, but the compiler handles that; we work with types.",[11,151,152,153,156],{},"An interesting detail is that C handles pointer-offset calculations at compile time. In this example, ",[125,154,155],{"code":155},"intBytes+1"," actually means the address in intBytes plus 4, because int occupies four bytes. This is also central to C's implementation of arrays.",[42,158,159],{},[11,160,161],{},"The type system is a compile-time feature, in C's case.",[11,163,164],{},"Struct definitions likewise guide the compiler's memory operations. Consider:",[117,166,169],{"className":167,"code":168,"language":122,"meta":123},[120],"typedef exampleStruct struct {\n\tint a;\n\tint b;\n}\n",[125,170,168],{"__ignoreMap":123},[11,172,173,174,177,178,181,182,185],{},"This struct contains two ints, occupying eight bytes. A pointer ",[125,175,176],{"code":176},"esp"," of type exampleStruct means that the eight-byte region starting at that address should be interpreted according to exampleStruct's layout. Accessing int b with ",[125,179,180],{"code":180},"esp.b"," or ",[125,183,184],{"code":184},"esp->b"," means treating bytes at offsets four through seven from esp as an int.",[11,187,188],{},"In that sense, a struct's field names serve at runtime only to indicate offsets from the start of the struct.",[11,190,191,192,195],{},"Declaring a struct directly inside a function with ",[125,193,194],{"code":194},"exampleStruct esp;",", instead of using a pointer, is special compiler handling for stack allocation. You can even view it as syntactic sugar, because:",[197,198,199,202],"ol",{},[104,200,201],{},"You do not manually initialize the struct; declaring it makes it available. The compiler has already chosen its position in the stack frame at compile time.",[104,203,204],{},"You do not manage its lifetime. It is freed when the function ends, by moving the stack pointer upward on a downward-growing stack, without overwriting the memory.",[11,206,207],{},"The drawback is obvious: that second advantage is also a disadvantage. Once the function returns, the allocation is released, so it cannot be used outside the function.",[11,209,210],{},"Compared with C, Java's type system is quite restricted: type information is stored directly in the object's memory, and casts can only move between parent and child nodes of the type tree.",[212,213,215],"h4",{"id":214},"pass-by-value-or-pass-by-reference","Pass by value or pass by reference?",[11,217,218],{},"A frequent topic of discussion, and misunderstanding, is whether function arguments are passed by value or by reference.",[11,220,221],{},"At bottom, all argument passing can be viewed as passing values; so-called reference passing is an optimization built on that.",[11,223,224],{},"C is straightforward. Whether arguments use registers or the stack, the original contents must be copied or backed up so they remain unchanged after the called function returns. A pointer, stripped of its pointer-ness, is just a number, perhaps 32 or 64 bits depending on the architecture. Passing it has the same result as putting the address in a long and passing that.",[11,226,227],{},"“Pass by reference” comes up mostly around Java. A reference is essentially an object handle through which programs access some of an object's information. The handle does not itself represent the memory address, but its implementation must contain the actual address. Passing a reference into a function or method can be viewed as passing a struct containing that address, much like passing a pointer in C, hence the similar behavior.",[11,229,230],{},"Java also has eight primitive types, each with a corresponding wrapper class, which makes the implementation feel inconsistent. Supposedly this was an early attempt to attract C++ programmers. Elegance took a hit.",[15,232,234],{"id":233},"what-is-an-array","What is an array?",[11,236,237],{},"With a basic type system in place, we should consider a special but common compound type: arrays. But what is an array, and do arrays really exist?",[11,239,240,241,244,245,248,249,252,253,256],{},"C actually has no arrays at runtime; they are compile-time syntactic sugar implemented with pointers. An array name is the address of its zeroth element: after declaring ",[125,242,243],{"code":243},"int a[10]",", using a is equivalent to ",[125,246,247],{"code":247},"&a[0]",". Subscripting with brackets is also implemented by typed-pointer offsets. Accessing the element with ",[125,250,251],{"code":251},"a[1]"," can be viewed as ",[125,254,255],{"code":255},"*(a+1)",". More concretely:",[117,258,261],{"className":259,"code":260,"language":122,"meta":123},[120],"int b = a[0];\n\n\u002F\u002F 等同于\nvoid *p = (void *)a;\np += 4;\nint b = *((int *)p);\n",[125,262,260],{"__ignoreMap":123},[11,264,265],{},"Because arrays are based on typed pointers and can be freely converted to and from the corresponding pointer type, the language does no bounds checking. If I define a ten-element array on the stack, reading or writing an eleventh element sometimes causes no immediate problem.",[11,267,268],{},"You might object that out-of-bounds accesses cause segmentation faults. That is not C checking bounds. An access beyond the array may read unreadable memory or write unwritable memory, causing an OS error. This is not a language-level error.",[11,270,271],{},"C offers three forms for array parameters: a pointer, an array with a specified size, and one without a specified size:",[117,273,276],{"className":274,"code":275,"language":122,"meta":123},[120],"void func(int *array);\nvoid func(int array[10]);\nvoid func(int array[]);\n",[125,277,275],{"__ignoreMap":123},[11,279,280],{},"With the first and third forms, func cannot recover the original length through len. With the second, the reported length is always 10, even if the argument is not a ten-element array. This illustrates that length information lives in the type definition; type changes during argument passing can lose it. It also fits the idea of arrays being fundamentally pointer-based: their memory contains only consecutive elements, with no additional information.",[11,282,283],{},"Java, by contrast, has real arrays. Every array is an object, with information such as element type and length in its header. Java can therefore check bounds at runtime and throw IndexOutOfBoundsException.",[15,285,287],{"id":286},"procedural-or-object-oriented","Procedural or object-oriented?",[11,289,290],{},"This is not really a question. Broadly, procedural and object-oriented programming are styles and paradigms rather than distinctions between particular languages. C can also support object-oriented programming through structs.",[11,292,293],{},"We can adopt a narrower definition: only a language that natively and fully implements the three pillars of object orientation—encapsulation, inheritance, and polymorphism—counts as object-oriented.",[11,295,296],{},"Simple encapsulation needs little explanation; even C can bundle things into a struct. But an important aim is to hide implementation details so that external code can access and manipulate data only through an object's interfaces. C structs have no access control; their fields can be modified freely, making that sort of encapsulation effectively meaningless. One large syntactic difference between Java\u002FC++ and C is invoking member methods with the dot operator. The implementation is not special: a member method is a function whose first argument is an object pointer. The compiler adds that argument automatically and calls it this. Otherwise, it is no different from an ordinary function.",[11,298,299],{},"Java, C++, and Go have something in common: they implement inheritance through composition, directly or indirectly. Because composition is involved, custom constructors must first call the parent's constructor. Go makes the composition particularly obvious by embedding an unnamed parent struct. Accessing a parent's field is really accessing that contained object's field, making it look very much like syntactic sugar:",[117,301,306],{"className":302,"code":304,"language":305,"meta":123},[303],"language-go","type Parent struct {\n\ta int64\n}\n\ntype Child struct {\n\tParent\n\tb int64\n}\n\nc := &Child{Parent{}, 0}\na := c.a\n\u002F\u002F或者\na := c.Parent.a;\n","go",[125,307,304],{"__ignoreMap":123},[11,309,310],{},"Compared with Java and C++, Go's inheritance feels like playing house. There is no dedicated control over a child's access to parent fields, just the usual initial-letter capitalization that determines package exports. It lacks something like Java's protected for specifically controlling child-to-parent access.",[11,312,313],{},"A typical expression of polymorphism is that a parent pointer can refer to different child objects, and invoking their shared method produces different behavior. Java and C++ exemplify two approaches. Java has the JVM runtime, which makes polymorphism easy: even when calling through a parent-type handle, the handle leads to the object's concrete type and method information, so selecting the implementation is straightforward. Java thus has runtime polymorphism. C++, meanwhile, has compile-time polymorphism. Each class has a virtual function table, and instances carry a pointer to theirs. The table lists methods that inheritance may override. The compiler ensures that a method implemented by both parent and child occupies the same position in both tables. A potentially inherited method call thus becomes “call the Nth function in the virtual table.” Calling through a parent pointer actually finds a function pointer in the child object's table, invoking the child's implementation and achieving polymorphism.",[15,315,317],{"id":316},"implementing-generics","Implementing generics",[11,319,320],{},"Thanks to IDEA's intelligent completion, generics are among the most widely used advanced language features. Yet Java only introduced generic programming in JDK 5, and C++ only introduced template programming, one implementation of generics, in C++11, making them relatively new. Interestingly, these represent two very different implementation strategies.",[11,322,323,324,327,328,331,332,335],{},"Java generics exist at compile time and disappear at runtime: type erasure. They provide compile-time checks that supplied objects or types satisfy the generic parameters. If you bypass those checks by manually constructing a class file or using runtime reflection, the JVM cannot help. For instance, normal code permits only Strings in a ",[125,325,326],{"code":326},"List\u003CString>",". With erasure, however, it is simply a ",[125,329,330],{"code":330},"List"," at runtime, or effectively a ",[125,333,334],{"code":334},"List\u003CObject>",". Somehow insert an Integer at runtime and the JVM will not complain.",[11,337,338,339,342,343,346,347,350,351,354],{},"C++ implements generics through code generation, hence the name templates. The compiler inspects the template arguments used at each instantiation and generates every method of the generic class for each distinct argument set. Suppose a template class ",[125,340,341],{"code":341},"ClassName\u003C typename T >"," contains ",[125,344,345],{"code":345},"Test(T t)",", and we instantiate it with ",[125,348,349],{"code":349},"ClassName\u003Cint> testObj",". The compiled output really contains a ",[125,352,353],{"code":353},"Test(int t)"," method. As with Java, runtime code has no awareness of generics; generated classes and methods look just like handwritten ones. This is undoubtedly safer than Java's approach. Code generation rather than erasure avoids the situation where bypassing compilation leaves no checks at all.",[11,356,357],{},"One disadvantage is that each template-generated C++ class must be complete. Even functions that do not involve template parameters are generated repeatedly, despite identical code, potentially wasting considerable space. C# optimizes this. Rather than generating final template code at compile time, it determines the different implementations needed. The .NET runtime's JIT compiler—CLR is analogous to the JVM—generates shared machine code for the template, while each instantiated generic type stores specialization information in an additional table. Most code can then be shared. See the paper for details. Still, this is hardly C++'s fault: C# has a runtime, and without its own runtime or one compiled into the output, C++ would struggle to implement such dynamic sharing.",[15,359,361],{"id":360},"closing-thoughts","Closing thoughts",[11,363,364],{},"Once you have decided all this, you have essentially determined what your language looks like, even before choosing its syntax! What remains is fairly standard, step-by-step work: implement it.",[11,366,367],{},"You can add all the advanced features you like, such as GC or unusual lifetime management. A VM makes implementing them much easier, but is not required. Go, for example, compiles GC code directly into the final output, effectively bundling a tiny VM with each executable.",[11,369,370],{},"Most people do not need to implement their own language, but understanding these shared ideas and distinctive features is still worthwhile. There is no best programming language, only the most suitable one for a particular situation. Debates over the “best language” are therefore rather silly: each language exists to solve some problem. A new language that differs from an existing one only in syntax, with no distinctive features, will struggle to last. If it solves no new problem, why bother learning it?",[11,372,373],{},"Understanding these features has unexpected benefits too. When programmers are drinking and talking big, or a tech chat group starts another well-reasoned best-language argument, you will have plenty to say.",{"title":123,"searchDepth":375,"depth":375,"links":376},4,[377,379,380,383,384,385,386],{"id":17,"depth":378,"text":18},3,{"id":36,"depth":378,"text":37},{"id":95,"depth":378,"text":96,"children":381},[382],{"id":214,"depth":375,"text":215},{"id":233,"depth":378,"text":234},{"id":286,"depth":378,"text":287},{"id":316,"depth":378,"text":317},{"id":360,"depth":378,"text":361},[388],"fiddling","2023-04-08 13:16:36","Designing a new programming language is challenging and fun. Setting aside complicated compiler theory and implementation details to focus on where code runs helps clarify how languages are built. Starting from the RISC-VI instruction set, this discussion explores the underlying architecture, layered computer systems, and virtual-machine model, reflecting on the nature of programming languages as well as their implementation.",false,"md","https:\u002F\u002Fblog-img.774352199.xyz\u002FuO420B.webp",{"slots":395},{},true,"\u002Ffiddling\u002Fchitchat-about-programming-language",null,{"text":400,"minutes":401,"time":402,"words":403},"15 min read",14.275,856500,2855,2,{"title":5,"description":390},"Using a hypothetical language design, I compare runtimes, types, arrays, parameter passing, inheritance, and generics across C, Java, Go, and other languages.","Programming language design: type systems, runtimes and implementation",{"loc":397},"posts\u002Ffiddling\u002Fchitchat-about-programming-language",[411,96,412,413],"Programming language design","Compiler design","RISC-V","tech","kx0g-9FCXEHkHZnoxIqXmJiszNBTU9oh51E0vA0E66Y",[417,435,452,470,487,505,509,527,545,561,577,592,608,624,641,659,674,691,705,721,738,755,771,788,804,823,839,856,874,888,906,923,939,955,969,986,1000,1015,1030,1044,1058,1072,1087,1101,1112],{"categories":418,"date":420,"description":421,"image":422,"path":423,"readingTime":424,"recommend":398,"tags":429,"title":434,"type":414},[419],"daily","2024-09-01 22:03:10","Chronic gastritis has been a long, uneven journey: stomach trouble throughout childhood, a surprising reprieve at university, then a return of symptoms after years of late nights and drinking. Frequent nausea and reflux eventually became too much to live with. After repeated examinations and some reflection, I finally began taking the recovery process seriously.","https:\u002F\u002Fblog-img.774352199.xyz\u002F0Hr9l5.webp","\u002Fdaily\u002Fanti-chronic-gastritis",{"text":425,"minutes":426,"time":427,"words":428},"4 min read",3.08,184800,616,[430,431,432,433],"Chronic gastritis","Medical care experiences","Gastroscopy","Health journal","My Journey with Chronic Gastritis",{"categories":436,"date":437,"description":438,"image":439,"path":440,"readingTime":441,"recommend":398,"tags":446,"title":451,"type":414},[419],"2022-04-11 00:13:13","In The Three-Body Problem, Liu Cixin uses an immense historical canvas to explore the relationship between individuals and the collective. His doubts about Western democracy and the majority’s ability to determine its own fate run through the trilogy. Heroes struggle and sacrifice, only to see their work swept aside by history. Beginning with the Cultural Revolution, the story sets up a conflict between exceptional individuals and the ordinary masses, raising uncomfortable questions about humanity and society.","https:\u002F\u002Fblog-img.774352199.xyz\u002FLTzbFP.webp","\u002Fdaily\u002Fpeople-in-three-body",{"text":442,"minutes":443,"time":444,"words":445},"9 min read",8.635,518100,1727,[447,448,449,450],"The Three-Body Problem","Liu Cixin","Science fiction","Reading notes","The “Majority” in The Three-Body Problem",{"categories":453,"date":454,"description":455,"image":456,"path":457,"readingTime":458,"recommend":398,"tags":463,"title":469,"type":414},[419],"2024-01-04 02:06:51","My learning goals for 2024: reach N2 in Japanese, finish SICP and TAPL, build a kernel with full POSIX support, and update the blog theme. A challenging list, but a clear direction for the year.","https:\u002F\u002Fblog-img.774352199.xyz\u002FV3rSQC.webp","\u002Fdaily\u002Fplan2024",{"text":459,"minutes":460,"time":461,"words":462},"1 min read",0.15,9000,30,[464,465,466,467,468],"Annual planning","Learning Japanese","SICP","TAPL","Operating systems","My Learning Plan for 2024",{"categories":471,"date":472,"description":473,"image":474,"path":475,"readingTime":476,"recommend":398,"tags":481,"title":486,"type":414},[419],"2024-09-28 16:26:00","Three years at ByteDance have made time feel strangely accelerated. Amid the changes, I have still managed to hold on to some mental balance. Looking back at the new graduate gazing at distant mountains from the balcony of our Hangzhou office, I can trace how curiosity, workplace challenges, and shifting expectations taught me to find a rhythm of my own.","https:\u002F\u002Fblog-img.774352199.xyz\u002FhnCaht.webp","\u002Fdaily\u002Fwork-for-3-years",{"text":477,"minutes":478,"time":479,"words":480},"10 min read",9.74,584400,1948,[482,483,484,485],"ByteDance","Software engineering careers","Career retrospective","Mental health","Working at ByteDance for Three Years and Staying Somewhat Sane Is Not Entirely Impossible",{"categories":488,"date":489,"description":490,"image":491,"path":492,"readingTime":493,"recommend":398,"tags":498,"title":504,"type":414},[388],"2025-05-28 22:09:00","After moving my blog to Astro, the usual Google Analytics integration no longer fit its performance goals. Adding event-reporting JavaScript directly to the head works, but hurts page performance. I used partytown to move the scripts off the main thread so they would not interfere with loading. With a few adjustments to the example code, Google Analytics finally worked, balancing performance with analytics.","https:\u002F\u002Fblog-img.774352199.xyz\u002FQ0w4RN.webp","\u002Ffiddling\u002Fastro-google-tag-manager",{"text":494,"minutes":495,"time":496,"words":497},"2 min read",1.785,107100,357,[499,500,501,502,503],"Astro","Google Analytics","Google Tag Manager","Partytown","Web analytics","Adding Google Analytics to Astro with Tag Manager",{"categories":506,"date":389,"description":390,"image":393,"path":397,"readingTime":507,"recommend":404,"tags":508,"title":5,"type":414},[388],{"text":400,"minutes":401,"time":402,"words":403},[411,96,412,413],{"categories":510,"date":511,"description":512,"image":513,"path":514,"readingTime":515,"recommend":375,"tags":520,"title":526,"type":414},[388],"2025-04-18 16:43:12","My girlfriend moved from Beijing to Shanghai for work, and I helped arrange broadband too. Shanghai Telecom’s 500M connection costs more than a 1000M line in Hangzhou, frustratingly. I set out to connect the two cities’ networks: transparent proxying in Shanghai, selected traffic exiting through Hangzhou, and access between both LANs. Hangzhou already had a simple setup with a software router and an AP, configured to route my everyday traffic home and ready for the next networking adventure.","https:\u002F\u002Fblog-img.774352199.xyz\u002FO6cAGh.webp","\u002Ffiddling\u002Fcross-city-network-setup",{"text":516,"minutes":517,"time":518,"words":519},"5 min read",4.865,291900,973,[521,522,523,524,525],"Tailscale","mihomo","Site-to-site networking","Transparent proxy","Home networking","Connecting My Shanghai and Hangzhou Networks",{"categories":528,"date":529,"description":530,"image":531,"path":532,"readingTime":533,"recommend":398,"tags":538,"title":544,"type":414},[388],"2021-12-27 00:09:00","The labs are an essential part of learning CSAPP, but setting up Linux can be discouraging. Virtual machines bring installation errors, compatibility problems, and broken networking. WSL (Windows Subsystem for Linux), especially on Windows 10 version 2004 and later, provides a simpler, more direct Linux environment without the complexity and performance bottlenecks of a traditional VM.","https:\u002F\u002Fblog-img.774352199.xyz\u002FvqOC7N.webp","\u002Ffiddling\u002Fcsapplab0",{"text":534,"minutes":535,"time":536,"words":537},"6 min read",5.295,317700,1059,[539,540,541,542,543],"CSAPP","WSL2","Linux","GDB","Lab environment","Setting Up the CSAPP Lab Environment",{"categories":546,"date":547,"description":548,"image":549,"path":550,"readingTime":551,"recommend":398,"tags":556,"title":560,"type":414},[388],"2024-07-13 17:49:00","Using Debian as a side router offers a more stable and flexible alternative without depending on OpenWrt and LuCI. Configuring Debian directly gives you greater control over the system and avoids the limitations and instability of a GUI. Compared with common side-router setups, this approach makes transparent proxying more reliable and offers another option for those who value performance and efficiency.","https:\u002F\u002Fblog-img.774352199.xyz\u002FpPRU5x.webp","\u002Ffiddling\u002Fdebian-as-bypass-router",{"text":552,"minutes":553,"time":554,"words":555},"12 min read",11.79,707400,2358,[557,558,522,559,524],"Debian","Side router","AdGuard Home","Using Debian as a Side Router",{"categories":562,"date":563,"description":564,"image":565,"path":566,"readingTime":567,"recommend":398,"tags":571,"title":576,"type":414},[388],"2024-08-16 23:53:00","This FakeIP-based transparent proxy design addresses the single point of failure, poor performance, and awkward port forwarding of a traditional side router. Switching to the sing-box proxy core improves forwarding performance and simplifies configuration, with broader protocol support and better optimization than the previous Clash setup. Clash can implement the same design, but sing-box provides a flexible alternative.","https:\u002F\u002Fblog-img.774352199.xyz\u002FS2HHD5.webp","\u002Ffiddling\u002Ffake-ip-based-transparent-proxy",{"text":477,"minutes":568,"time":569,"words":570},9.395,563700,1879,[572,573,524,574,575],"FakeIP","sing-box","Policy-based routing","Traffic routing","Routing Transparent Proxy Traffic with FakeIP",{"categories":578,"date":579,"description":580,"image":581,"path":582,"readingTime":583,"recommend":398,"tags":587,"title":591,"type":414},[388],"2024-08-15 23:50:00","Port forwarding on the main router often stops working when a side router is introduced. Setting the side router as the gateway changes the forwarding path, breaking mappings that previously relied on the main router. A gateway translates addresses and forwards traffic from the internal network to the outside, and each internal device needs one to communicate externally. Understanding this mechanism helps explain how to fix the forwarding problem.","https:\u002F\u002Fblog-img.774352199.xyz\u002FmRqws9.webp","\u002Ffiddling\u002Ffix-port-forward-in-bypass-router",{"text":425,"minutes":584,"time":585,"words":586},3.03,181800,606,[558,588,589,590],"Port forwarding","NAT","Network troubleshooting","Fixing Port Forwarding with a Side Router",{"categories":593,"date":594,"description":595,"image":596,"path":597,"readingTime":598,"recommend":398,"tags":603,"title":607,"type":414},[388],"2023-02-02 23:24:55","Inspiration struck during Chinese New Year: an article read on the train about running Go on bare metal sparked an interest in low-level system interfaces. Its successful implementation suggested exciting possibilities for combining a high-level language with an OS. Further research revealed earlier work on the idea, and that growing enthusiasm became a project full of anticipation that ultimately did not work out.","https:\u002F\u002Fblog-img.774352199.xyz\u002FxB1Ni5.webp","\u002Ffiddling\u002Fgo-os",{"text":599,"minutes":600,"time":601,"words":602},"8 min read",7.29,437400,1458,[604,413,468,605,606],"Go","Bare-metal programming","Runtime","A Project That Failed: Seven Not-So-Happy Days over Chinese New Year",{"categories":609,"date":610,"description":611,"image":612,"path":613,"readingTime":614,"recommend":398,"tags":619,"title":623,"type":414},[388],"2022-08-15 01:05:01","While refactoring a system, converting entities between layers made deep copying surprisingly awkward. A product VO in the view layer, an entity in the domain layer, and a PO in the persistence layer can look nearly identical, yet small type differences complicate direct conversion. I used reflection to build a general conversion method, reducing repetitive assembler methods and making the code more maintainable and flexible.","https:\u002F\u002Fblog-img.774352199.xyz\u002FBlhm0I.webp","\u002Ffiddling\u002Fgolang-deepcopy-between-different-type",{"text":615,"minutes":616,"time":617,"words":618},"3 min read",2.855,171300,571,[604,620,621,622],"Reflection","Deep copy","Struct conversion","Deep Copying Between Different Struct Types in Go",{"categories":625,"date":626,"description":627,"image":628,"path":629,"readingTime":630,"recommend":398,"tags":634,"title":640,"type":414},[388],"2025-03-31 23:51:00","Periodically syncing heart-rate data from Apple Health to a server and visualizing it in Grafana provides an intuitive way to monitor it. Health Auto Export sends the data to an HTTP endpoint through its REST API automation, the server stores it in InfluxDB, and Grafana presents a clear dashboard for tracking and analyzing personal heart-rate changes.","https:\u002F\u002Fblog-img.774352199.xyz\u002FF4qD2T.webp","\u002Ffiddling\u002Fheart-rate-to-grafana",{"text":615,"minutes":631,"time":632,"words":633},2.45,147000,490,[635,636,637,638,639],"Apple Watch","Health Auto Export","InfluxDB","Grafana","Heart rate monitoring","My Heart Beats for U: Visualizing Heart Rate in Grafana",{"categories":642,"date":643,"description":644,"image":645,"path":646,"readingTime":647,"recommend":651,"tags":652,"title":658,"type":414},[388],"2025-06-10 20:18:00","macOS and iPadOS 26 introduce the Liquid Glass design language, refreshing icons and windows with a more modern look. Windowed apps on iPad are a step toward making it a productivity device. The transparent Control Center and the integration of Launchpad have been controversial, however, and the experience still needs work. Despite its shortcomings, this update lays groundwork for a promising future.","https:\u002F\u002Fblog-img.774352199.xyz\u002FTPSaLE.webp","\u002Ffiddling\u002Fmacos-26-trial",{"text":425,"minutes":648,"time":649,"words":650},3.305,198300,661,5,[653,654,655,656,657],"macOS 26","iPadOS 26","Liquid Glass","Apple Intelligence","Operating system impressions","Trying Out macOS 26 and iPadOS 26",{"categories":660,"date":661,"description":662,"image":663,"path":664,"readingTime":665,"recommend":398,"tags":669,"title":673,"type":414},[388],"2026-06-11 10:00:00","Another WWDC brings new Apple Intelligence features in macOS 27. The workarounds from macOS 26 no longer get through, so the battle of wits with Apple continues.","https:\u002F\u002Fblog-img.774352199.xyz\u002FfOFucm.webp","\u002Ffiddling\u002Fmacos-27-apple-intelligence-chatgpt",{"text":534,"minutes":666,"time":667,"words":668},5.1,306000,1020,[670,656,671,672],"macOS 27","ChatGPT","Mainland China Mac","Getting Apple Intelligence Working on a China-Market Mac: Region Changes and Extracting ChatGPT",{"categories":675,"date":676,"description":677,"image":678,"path":679,"readingTime":680,"recommend":398,"tags":684,"title":690,"type":414},[388],"2025-07-20 23:32:00","MoonTV is a new video aggregation platform built with Next.js and React to make following shows convenient. It began as an attempt to improve LibreTV and has attracted substantial attention and usage over several months of development. Cursor made development efficient, although multi-platform support and complex data dependencies posed challenges. As its user base grows, MoonTV continues improving in response to feedback.","https:\u002F\u002Fblog-img.774352199.xyz\u002FnIeONi.webp","\u002Ffiddling\u002Fmoontv-vibe-coding",{"text":534,"minutes":681,"time":682,"words":683},5.76,345600,1152,[685,686,687,688,689],"MoonTV","LunaTV","Vibe Coding","Cursor","AI-assisted development","MoonTV: An Experiment in Vibe Coding",{"categories":692,"date":693,"description":694,"image":695,"path":696,"readingTime":697,"recommend":398,"tags":701,"title":704,"type":414},[388],"2024-10-07 16:51:00","BGP-based routing for Chinese and overseas IPs makes transparent proxying more efficient and accurate. Marking overseas destinations with FakeIP lets the main router route traffic more intelligently for smoother connectivity. The sing-box DNS configuration is also refined to handle queries more flexibly and efficiently, improving the overall network experience.","https:\u002F\u002Fblog-img.774352199.xyz\u002FMOmM1s.webp","\u002Ffiddling\u002Fmore-accurate-chnroute",{"text":425,"minutes":698,"time":699,"words":700},3.805,228300,761,[702,703,574,575],"BGP","IP address database","More Accurate Routing for Chinese and Overseas IPs with BGP",{"categories":706,"date":707,"description":708,"image":709,"path":710,"readingTime":711,"recommend":398,"tags":715,"title":720,"type":414},[388],"2025-12-14 14:31:00","A friend’s comment got me interested in simulation games. After buying Microsoft Flight Simulator, I discovered streamed maps and models, another account login, oddly hidden tutorials, and awkward keyboard controls. A flight stick and some tinkering with Pico VR finally rounded out the experience.","https:\u002F\u002Fblog-img.774352199.xyz\u002FlfhEuE.webp","\u002Ffiddling\u002Fmsfs2024-joystick-and-pico",{"text":516,"minutes":712,"time":713,"words":714},4.68,280800,936,[716,717,718,719],"Microsoft Flight Simulator 2024","Thrustmaster TCA","PICO VR","Flight simulation","Adventures with Microsoft Flight Simulator 2024",{"categories":722,"date":723,"description":724,"image":725,"path":726,"readingTime":727,"recommend":398,"tags":731,"title":737,"type":414},[388],"2025-06-05 23:26:00","My frequent phone changes took me from OnePlus to iPhone, and from enjoying tinkering to relying on an ecosystem. At my girlfriend’s suggestion, I recently bought an OPPO Find X8 Ultra to improve my photos. Migrating apps out of Apple’s ecosystem reminded me how uneven Android’s app selection remains and how difficult finding replacements can be. A month of migration has been an exercise in friction and adaptation between platforms.","https:\u002F\u002Fblog-img.774352199.xyz\u002F19NIhZ.webp","\u002Ffiddling\u002Fone-month-using-android",{"text":599,"minutes":728,"time":729,"words":730},7.61,456600,1522,[732,733,734,735,736],"Android","OPPO","iOS","Smartphone impressions","Ecosystem migration","One Month After Switching to Android",{"categories":739,"date":740,"description":741,"image":742,"path":743,"readingTime":744,"recommend":398,"tags":748,"title":754,"type":414},[388],"2026-05-11 22:43:00","I found a trip-planning tool on GitHub Trending and wanted to host my own instance. Since I was getting a new VPS anyway, I might as well install a little extra. Well, quite a lot extra.","https:\u002F\u002Fblog-img.774352199.xyz\u002FBBdDWW.webp","\u002Ffiddling\u002Fone-trek-twenty-stacks",{"text":534,"minutes":745,"time":746,"words":747},5.735,344100,1147,[749,750,751,752,753],"TREK","Docker Compose","Dockge","VPS","Self-hosting","One TREK, Twenty Stacks",{"categories":756,"date":757,"description":758,"image":759,"path":760,"readingTime":761,"recommend":398,"tags":766,"title":770,"type":414},[388],"2025-01-16 23:09:00","OPNsense is an open-source firewall and router with an attractive interface and a comprehensive feature set. After trying several routing setups, I came to appreciate its potential for transparent proxying and traffic routing. Combining it with BGP-based routing offers better security and stability, while its automatically updated IP lists make network management more convenient.","https:\u002F\u002Fblog-img.774352199.xyz\u002FxA8C1E.webp","\u002Ffiddling\u002Fopnsense-transparent-proxy",{"text":762,"minutes":763,"time":764,"words":765},"7 min read",6.47,388200,1294,[767,768,522,769,524,575],"OPNsense","FreeBSD","tun2socks","Transparent Proxying and Traffic Routing with OPNsense",{"categories":772,"date":773,"description":774,"image":775,"path":776,"readingTime":777,"recommend":378,"tags":781,"title":787,"type":414},[388],"2025-03-15 20:35:00","Distinguishing user-defined type names from ordinary variables is a challenge during parsing. A statement such as `a*b;` can be either an arithmetic expression or a declaration. Grammar rules, especially those involving type specifiers, can misidentify variables as types, affecting correctness and readability. The prevalence of declarations without initializers makes this ambiguity especially common.","https:\u002F\u002Fblog-img.774352199.xyz\u002F2VKHK9.webp","\u002Ffiddling\u002Fparser-type-variable-ambiguity",{"text":599,"minutes":778,"time":779,"words":780},7.475,448500,1495,[782,783,784,785,786],"Parsing","GLR","Symbol table","Scope","Disambiguation","Resolving Type Name and Variable Name Ambiguity in Parsing",{"categories":789,"date":790,"description":791,"image":792,"path":793,"readingTime":794,"recommend":398,"tags":798,"title":803,"type":414},[388],"2023-05-24 17:51:09","To install the RISC-V toolchain, first obtain the riscv-gnu-toolchain source. Using `--depth=1` when cloning reduces the download size. Check the README’s Prerequisites section and install the required dependencies. On Debian, a simple package installation command prepares the environment for building the toolchain.","https:\u002F\u002Fblog-img.774352199.xyz\u002FrWNOKx.webp","\u002Ffiddling\u002Fspike-install",{"text":494,"minutes":795,"time":796,"words":797},1.92,115200,384,[413,799,800,801,802],"Spike","riscv-pk","Cross-compilation","Toolchain","Installing the RISC-V Toolchain and Emulator",{"categories":805,"date":806,"description":807,"image":808,"path":809,"readingTime":810,"recommend":814,"tags":815,"title":822,"type":414},[388],"2026-09-09 23:59:00","This counts as NTR too, surely.","https:\u002F\u002Fblog-img.774352199.xyz\u002FNDPUwc.webp","\u002Ffiddling\u002Fsteamdeck-switch-60fps",{"text":599,"minutes":811,"time":812,"words":813},7.345,440700,1469,7,[816,817,818,819,820,821],"Steam Deck","Nintendo Switch","EmuDeck","Eden","Lossless Scaling","Frame generation","A Second Life for the Steam Deck: Switch Emulation and Frame Generation at 60 FPS",{"categories":824,"date":825,"description":826,"image":827,"path":828,"readingTime":829,"recommend":398,"tags":833,"title":838,"type":414},[388],"2024-06-23 15:31:32","The GFW does more than monitor an exit gateway: it inspects international traffic through passive taps, copying inbound and outbound IP packets to a cluster for analysis and filtering. Understanding where and how this happens matters when studying censorship circumvention. Examining the GFW’s network topology helps explain its blocking mechanisms and how to work around them.","https:\u002F\u002Fblog-img.774352199.xyz\u002FsOpJuL.webp","\u002Ffiddling\u002Ftech-about-gfw",{"text":552,"minutes":830,"time":831,"words":832},11.885,713100,2377,[834,835,836,837],"GFW","DNS poisoning","TCP","Internet censorship","How the Great Firewall Works",{"categories":840,"date":841,"description":842,"image":843,"path":844,"readingTime":845,"recommend":398,"tags":849,"title":855,"type":414},[388],"2022-04-16 00:01:28","In Java, using `this` can prevent the compiler from optimizing constants. Although `ab1` and `ab2` in this example appear to refer to the same static final variable `s`, comparing them produces different results. `ab1` concatenates a direct reference to the static variable, while `ab2` accesses it through `this`, preventing the same constant propagation optimization. This illustrates how a small syntactic difference can change compilation behavior.","https:\u002F\u002Fblog-img.774352199.xyz\u002FgKtkYe.webp","\u002Ffiddling\u002Fthis-in-javac-string-concat",{"text":615,"minutes":846,"time":847,"words":848},2.305,138300,461,[850,851,852,853,854],"Java","javac","String concatenation","Constant propagation","Bytecode","How Java’s this Keyword Can Prevent Compile-Time Constant Propagation",{"categories":857,"date":858,"description":859,"image":860,"path":861,"readingTime":862,"recommend":398,"tags":867,"title":873,"type":414},[388],"2025-01-29 21:58:00","A microblog lets you share short thoughts whenever they occur, without the overhead of publishing a full static-blog post. This implementation uses Cloudflare Workers for the backend and KV for storage and management. A Vue component embedded in VitePress displays the updates, adding a lively, interactive element to the blog.","https:\u002F\u002Fblog-img.774352199.xyz\u002FhZX6hr.webp","\u002Ffiddling\u002Fvitepress-memos-component",{"text":863,"minutes":864,"time":865,"words":866},"19 min read",18.96,1137600,3792,[868,869,870,871,872],"VitePress","Vue","Cloudflare Workers","Cloudflare KV","Microblogging","Adding a Microblog to VitePress",{"categories":875,"date":876,"description":877,"image":878,"path":879,"readingTime":880,"recommend":398,"tags":884,"title":887,"type":414},[388],"2025-03-15 16:24:00","A Telegram notification on an ordinary afternoon introduced a tempting VPS deal: a direct China Telecom CN2 route and 2.5G bandwidth. The plan includes IPv6, useful for unlocking streaming services, but not every connection needs to go through WARP. My previous script was convenient, yet its effects on speed and traffic routing called for a more flexible solution.","https:\u002F\u002Fblog-img.774352199.xyz\u002FMcjrrF.webp","\u002Ffiddling\u002Fvps-warp-ipv6",{"text":615,"minutes":881,"time":882,"words":883},2.34,140400,468,[885,886,752,574,575],"Cloudflare WARP","IPv6","Routing Selected VPS Traffic Through WARP over IPv6",{"categories":889,"date":890,"description":891,"image":892,"path":893,"readingTime":894,"recommend":898,"tags":899,"title":905,"type":414},[388],"2026-08-17 23:59:21","The more I tinker, the more I want to tinker. Still going strong in my old age, still going strong!","https:\u002F\u002Fblog-img.774352199.xyz\u002FqfxB0h.webp","\u002Ffiddling\u002Fxiaomi17-root-and-hide-root",{"text":516,"minutes":895,"time":896,"words":897},4.545,272700,909,6,[900,901,902,903,904],"Xiaomi 17","Bootloader","Android Root","Firmware flashing","Root hiding","Making the Xiaomi 17 My Daily Driver: Unlocking, Flashing, Rooting, and Hiding Root",{"categories":907,"date":909,"description":910,"image":911,"path":912,"readingTime":913,"recommend":398,"tags":917,"title":922,"type":414},[908],"notes","2022-01-20 22:29:00","Lab 1 asks us to implement a MapReduce system with two core components: a master and workers. This requires a good command of Go RPC and concurrent programming, along with a thorough understanding of the MapReduce workflow. I built two versions, starting with mutex locks and then moving to a more elegant channel-based implementation without explicit locks, whose design is simpler and clearer. The key to understanding the lab is to read the relevant documentation carefully, especially the flowcharts and explanations.","https:\u002F\u002Fblog-img.774352199.xyz\u002FibVwPJ.webp","\u002Fnotes\u002F65840\u002Fmapreducelab",{"text":599,"minutes":914,"time":915,"words":916},7.21,432600,1442,[918,919,604,920,921],"MIT 6.5840","MapReduce","RPC","Concurrent programming","6.5840 Lab 1: MapReduce",{"categories":924,"date":925,"description":926,"image":927,"path":928,"readingTime":929,"recommend":398,"tags":933,"title":938,"type":414},[908],"2022-01-16 17:32:00","MapReduce is an efficient parallel computing model designed to simplify processing large datasets. By defining the two key functions, Map and Reduce, users can break complex tasks into simple operations. The framework automatically handles data distribution and task scheduling, allowing developers to focus on the algorithm rather than low-level details. Its widespread use in distributed systems demonstrates its flexibility and practical value.","https:\u002F\u002Fblog-img.774352199.xyz\u002FApIDdC.webp","\u002Fnotes\u002F65840\u002Fmapreducepaper",{"text":516,"minutes":930,"time":931,"words":932},4.12,247200,824,[919,934,935,936,937],"Distributed systems","Paper notes","Parallel computing","Fault tolerance","Reading the MapReduce Paper",{"categories":940,"date":941,"description":942,"image":943,"path":944,"readingTime":945,"recommend":398,"tags":950,"title":954,"type":414},[908],"2022-12-16 02:06:10","Lab 2A focuses on implementing Raft leader election and heartbeats so that elections and term changes work correctly even under extreme conditions. The lab has four stages and lays the foundation for the distributed key-value store that follows. A design without explicit locks simplifies the Raft struct. The lab instructions provide the necessary background, but compared with the previous lab, this one relies on almost no reference material and places greater emphasis on implementing the system independently.","https:\u002F\u002Fblog-img.774352199.xyz\u002Fc11Uk4.webp","\u002Fnotes\u002F65840\u002Fraftlab2a",{"text":946,"minutes":947,"time":948,"words":949},"13 min read",12.235,734100,2447,[918,951,604,952,953],"Raft","Leader election","Distributed consensus","6.5840 Lab 2A: Leader Election",{"categories":956,"date":957,"description":958,"image":959,"path":960,"readingTime":961,"recommend":398,"tags":966,"title":968,"type":414},[908],"2022-12-03 21:40:09","Raft is a consensus algorithm designed to improve the efficiency of log replication. It is particularly suited to clusters of machines, allowing them to keep providing service even when some machines fail. It uses the replicated state machine model: logs record the order of commands so that every machine in the cluster can reach the same state. In Search of an Understandable Consensus Algorithm explores Raft’s design and compares it with Paxos, highlighting its understandability and providing a foundation for building reliable large-scale software systems. These reading notes aim to help explain the paper’s core concepts and their applications.","https:\u002F\u002Fblog-img.774352199.xyz\u002F7mmvIZ.webp","\u002Fnotes\u002F65840\u002Freftextendedpaper",{"text":962,"minutes":963,"time":964,"words":965},"16 min read",15.98,958800,3196,[951,953,967,935],"Log replication","Reading the Raft Paper",{"categories":970,"date":972,"description":973,"image":974,"path":975,"readingTime":976,"recommend":980,"tags":981,"title":985,"type":414},[971],"projects","2021-11-27 14:43:00","MYDB is a personal project exploring and implementing the fundamentals of databases, built in my spare time over a little more than half a month. I picked up some basic knowledge in my university database systems course, though during my internship I mostly used the classes as an excuse to slack off. My candid answers in an interview did not cause too much trouble, but they did make me reconsider what I knew about databases and decide to learn through hands-on practice. That was how this project began.","https:\u002F\u002Fblog-img.774352199.xyz\u002Fxfci2J.webp","\u002Fprojects\u002Fmydb\u002Fmydb0",{"text":516,"minutes":977,"time":978,"words":979},4.15,249000,830,1,[982,850,983,984],"MYDB","Database implementation","Database architecture","MYDB 0. Project Structure and a Few Things I Had to Say",{"categories":987,"date":988,"description":989,"image":990,"path":991,"readingTime":992,"recommend":398,"tags":996,"title":999,"type":414},[971],"2021-11-28 16:10:00","MYDB manages transactions through an XID file. Each transaction has a unique XID, incrementing from 1; XID 0 denotes a super transaction whose state is always committed. TransactionManager maintains this file and records three states: active, committed, and aborted. This mechanism supports accurate transaction state queries and management, providing a foundation for system stability and reliability.","https:\u002F\u002Fblog-img.774352199.xyz\u002FH4zZAK.webp","\u002Fprojects\u002Fmydb\u002Fmydb1",{"text":516,"minutes":993,"time":994,"words":995},4.755,285300,951,[982,850,997,998],"Transaction management","XID","MYDB 1. Starting with the Transaction Manager",{"categories":1001,"date":1002,"description":1003,"image":1004,"path":1005,"readingTime":1006,"recommend":398,"tags":1010,"title":1014,"type":414},[971],"2021-12-25 18:26:00","MYDB uses a client\u002Fserver architecture similar to MySQL, allowing multiple clients to connect to a server over sockets, execute SQL queries, and receive results. Communication uses a special binary format, though plain text would also be an option for a simpler implementation. The basic transport structure supports effective communication and processing between client and server.","https:\u002F\u002Fblog-img.774352199.xyz\u002FPAHrUZ.webp","\u002Fprojects\u002Fmydb\u002Fmydb10",{"text":516,"minutes":1007,"time":1008,"words":1009},4.305,258300,861,[982,850,1011,1012,1013],"Socket","Client-server architecture","Communication protocol","MYDB 10. Implementing the Server, Client, and Wire Protocol",{"categories":1016,"date":1017,"description":1018,"image":1019,"path":1020,"readingTime":1021,"recommend":398,"tags":1025,"title":1029,"type":414},[971],"2021-11-30 23:18:00","The Data Manager (DM) bridges higher-level modules and the filesystem, handling paging and caching while ensuring data safety and recovery. Its cache uses reference counting rather than traditional LRU, aiming for a reusable, efficient foundation for subsequent data operations.","https:\u002F\u002Fblog-img.774352199.xyz\u002FWdIGoG.webp","\u002Fprojects\u002Fmydb\u002Fmydb2",{"text":534,"minutes":1022,"time":1023,"words":1024},5.725,343500,1145,[982,850,1026,1027,1028],"Reference counting","Cache design","Shared memory","MYDB 2. A Reference-Counted Cache Framework and Shared Byte Arrays",{"categories":1031,"date":1032,"description":1033,"image":1034,"path":1035,"readingTime":1036,"recommend":398,"tags":1040,"title":1043,"type":414},[971],"2021-12-05 15:28:00","DM abstracts the filesystem into pages and uses them as the unit of reading, writing, and caching. The default page size is 8K, with larger pages available to improve write performance under heavy loads. With the general-purpose cache framework already in place, we now define the page structure and implement efficient page caching.","https:\u002F\u002Fblog-img.774352199.xyz\u002FjlFC4E.webp","\u002Fprojects\u002Fmydb\u002Fmydb3",{"text":516,"minutes":1037,"time":1038,"words":1039},4.7,282000,940,[982,850,1041,1042],"Data pages","Cache management","MYDB 3. Caching and Managing Data Pages",{"categories":1045,"date":1046,"description":1047,"image":1048,"path":1049,"readingTime":1050,"recommend":398,"tags":1054,"title":1057,"type":414},[971],"2021-12-08 22:55:00","Log files are essential to MYDB’s design, allowing data to be recovered after a crash. DM logs every operation on underlying data, forming a continuous sequence of records. Stored in a specific binary format with checksums and individual operation records, these logs let the database accurately reconstruct its data on restart and maintain consistency and integrity.","https:\u002F\u002Fblog-img.774352199.xyz\u002FTRcbsj.webp","\u002Fprojects\u002Fmydb\u002Fmydb4",{"text":599,"minutes":1051,"time":1052,"words":1053},7.885,473100,1577,[982,850,1055,1056],"Database logging","Crash recovery","MYDB 4. Log Files and Recovery Strategies",{"categories":1059,"date":1060,"description":1061,"image":1062,"path":1063,"readingTime":1064,"recommend":398,"tags":1068,"title":1071,"type":414},[971],"2021-12-11 15:16:00","The page index is an important part of DM, optimizing insertions by caching the free space available on each page. It lets higher-level modules quickly locate a suitable page without a lengthy search, making data operations more efficient. Its implementation works closely with the DataItem abstraction to support efficient database operation.","https:\u002F\u002Fblog-img.774352199.xyz\u002F22PSG1.webp","\u002Fprojects\u002Fmydb\u002Fmydb5",{"text":762,"minutes":1065,"time":1066,"words":1067},6.37,382200,1274,[982,850,1069,1070],"Page index","Data management","MYDB 5. The Page Index and the Data Manager",{"categories":1073,"date":1074,"description":1075,"image":1076,"path":1077,"readingTime":1078,"recommend":398,"tags":1082,"title":1086,"type":414},[971],"2021-12-18 14:58:00","VM uses two-phase locking to ensure serializable schedules and introduces multiversion concurrency control (MVCC) to eliminate blocking between reads and writes. This chapter also defines conflicts between database operations, focusing on the interaction between updates and reads as a foundation for understanding transaction isolation levels.","https:\u002F\u002Fblog-img.774352199.xyz\u002F8YzotA.webp","\u002Fprojects\u002Fmydb\u002Fmydb6",{"text":442,"minutes":1079,"time":1080,"words":1081},8.64,518400,1728,[982,850,1083,1084,1085],"MVCC","Transaction isolation","Two-phase locking","MYDB 6. Record Versions and Transaction Isolation",{"categories":1088,"date":1089,"description":1090,"image":1091,"path":1092,"readingTime":1093,"recommend":398,"tags":1097,"title":1100,"type":414},[971],"2021-12-23 21:20:00","VM must handle version skipping introduced by MVCC as well as deadlocks. By simply marking a transaction, MYDB can cancel or roll it back and keep data from aborted transactions from affecting others. This design makes concurrent transaction handling more efficient and reliable, avoids the deadlock risks common with traditional 2PL, and improves overall stability and performance.","https:\u002F\u002Fblog-img.774352199.xyz\u002FBF3yDW.webp","\u002Fprojects\u002Fmydb\u002Fmydb7",{"text":599,"minutes":1094,"time":1095,"words":1096},7.265,435900,1453,[982,850,1098,1099],"Deadlock detection","Version management","MYDB 7. Deadlock Detection and the Version Manager",{"categories":1102,"date":1103,"description":1104,"image":1105,"path":1106,"readingTime":1107,"recommend":398,"tags":1108,"title":1111,"type":414},[971],"2021-12-24 21:01:00","MYDB implements a clustered index using a B+ tree. IM interacts directly with the Data Manager (DM), bypassing the Version Manager (VM), so index data is written directly to the database file. This chapter details the binary-tree index structure and its basic node fields, including the leaf flag, key count, and sibling identifier, establishing the framework for indexed lookups.","https:\u002F\u002Fblog-img.774352199.xyz\u002Ff92X4o.webp","\u002Fprojects\u002Fmydb\u002Fmydb8",{"text":516,"minutes":977,"time":978,"words":979},[982,850,1109,1110],"B+ tree","Database indexing","MYDB 8. Index Management",{"categories":1113,"date":1114,"description":1115,"image":1116,"path":1117,"readingTime":1118,"recommend":398,"tags":1122,"title":1125,"type":414},[971],"2021-12-25 15:44:00","The Table Manager (TBM) manages field and table structures. Parser turns SQL-like statements into structured representations, wrapping their information in the corresponding classes to simplify subsequent operations. This chapter also covers MYDB’s SQL syntax as a foundation for understanding the management process.","https:\u002F\u002Fblog-img.774352199.xyz\u002FzOMyv5.webp","\u002Fprojects\u002Fmydb\u002Fmydb9",{"text":534,"minutes":1119,"time":1120,"words":1121},5.035,302100,1007,[982,850,1123,1124],"SQL parsing","Table management","MYDB 9. Field and Table Management",1789923142422]