Bytes

Quick Bytes - Random info that’s too short for a full post will be shared here.

Ring Buffer out in the wild

last updated: Nov 09, 2024

Ring Buffer/Circular Queue/Circular Buffer is a data structure for effectively managing queueing for low latency/time critical tasks, overwriting the old value when the queue is full and wrapping around without needing for dynamic size allowing continuous flow of data.

process 1 which is a producer connected to the ring buffer, process 2 which is a consumer connected to the ring buffer for offloading

A more advanced version of the ring buffer is all over the place. A few examples could be:

  • Device Drivers use it as a transport between software and hardware components
  • io_uring (used by linux kernel for async I/O) uses two ring buffers — submission and completion queue to manage/signal I/O requests
  • Real-time stream and media processing — managing media on the buffer to be processed

At a lower level, locking and unlocking resources is expensive, which results in delays for performance-critical applications. To avoid this, a ring buffer CAN BE implemented as a lock-free data structure without needing to use mutex, semaphores.

Lock-free data structures are thread-safe for concurrent usage without having to use mutual exclusion mechanisms like semaphores or locks.

Concurrency Handling

  • For a Single Producer Single Consumer (SPSC) setup, there is a less chance of data corruption since it’s single producer and consumer. Although atomic operations can be designed to ensure correctness.
  • For Multiple Producers Multiple Consumers (MPMC), additional techniques needs to be employed to combat data races since it is accessed by multiple threads. Atomic Operations, Memory Barrier or other techniques can be used.

There are different lock-free techniques available to ensure correctness and avoid corruption without explicit locking. The io_uring implementation uses memory ordering and barriers to get around without locking the shared memory.

A ring buffer in the shared memory enables inter-process communication (IPC) among different processes. It can act as a transporting mechanism between threads or user-kernel space.

Building Data Pipeline on top of Ring Buffer could result in low latency, high performance message queue.

io_uring how websockets costs us 1m on our aws bill lock-free programming

Collation in Database

last updated: Oct 13, 2024

Collation in Database is the set of rules to govern how characters are searched, compared and sorted in the database. It includes case sensitivity, accent-sensitivity and storing multi-lingual, emojis, special characters. It is mostly applicable for string datatypes (TEXT, VARCHAR) than others.

Why this is important? because every database treats the characters in a unique way.

Like,

  • MySQL don’t support case sensitive search out of box (can be configured to do so).
  • Postgres, SQLite includes it out of box.

Databases allows us to specify collation on the time of

  • creation of the db or table
  • specify per query, per column basis.

For example:

In MySQL, if you want to perform search by case sensitive,

SELECT * FROM names WHERE username = "TesT"; // returns "test", "Test", "tESt"

The default character encoding for MySQL is utf8mb4_general_ci (MySQL 5.7) or utf8mb4_0900_ai_ci (MySQL 8.0)

where,

  • utf8mb - full unicode support in which it occupied 4bytes. (Note: utf8 is different from utf8mb4, utf8 lacks support for all unicode characters. it is not longer recommeded)
  • ci - refers to case insensitive
  • ai - accent insensitive

To make our query aware, we can set collation to utf8mb4_unicode_cs or utf8mb4_bin or another case-sensitive collation.

where,

  • cs - case sensitive
  • bin - binary (compares byte by byte, no other rules)

To perform query aware case sensitive search:

SELECT * FROM names WHERE username COLLATE utf8mb4_bin = "TesT";
SELECT * FROM names WHERE username COLLATE utf8mb4_unicode_cs = "TesT";

Collation plays a important role in dealing with multilingual databases effectively for making search, sorting operations consistent with lingustic rules. It is mostly decided at the time of initializing the database.

charset utf8

fragments and http

last updated: Sep 15, 2024

#Fragments x http x SEO x OG Images

Recently i’ve learned fragments are not sent to backend server nor parsed by social media crawlers (for seo/og image) in a hard way…

In this site /bytes url now looks like /bytes/communication-protocols.

In the tried and reverted back version, i had the url look like /bytes#communication-protocols where the OG image is being replaced for every section id.

<h2 id="communication-protocols">
  <a href="#communication-protocols">test</a>
</h2>

guess what.. social media (like twitter card, linkedin) and SEO crawlers don’t wait for the script (javascript that updates the OG Image url based on #fragments). Search engine doesn’t crawl the page based on fragments either, thus no indexing for SEO.

if you make request from http://example.com/test#test to the backend, the request doesn’t include the fragments. This behaviour is designed by http 1.1 spec even from the starting spec where request uri should not include fragments due to security considerations.

It is meant for client side navigation only, not for server side (including crawling servers).

first http 1.1 spec Disclosure of Fragment after Redirects

iOS mobile fallback

last updated: Sep 15, 2024

To add fallback for styles in iOS devices - mobile

@supports (-webkit-overflow-scrolling: touch) {
  /* css classes/selectors */
}

For example: background-attachment: fixed don’t work in safari mobile, add fallback for mobile iOS like

@supports (-webkit-overflow-scrolling: touch) {
  body {
    /*switch to scroll which is default - iOS mobile*/
    background-attachment: scroll;
  }
}

communication-protocols

last updated: Sep 09, 2024

Listed down the number of ways to transmit/exchange data between server and browser, we might use:

  • traditional way (http request/response)
  • chunked-response (streams data)
  • SSE (streams - text only, base64)
  • Web Sockets (streams)
  • grpc web (needs proxy)
  • Web Transport (alternative to web sockets BUT major browser support is lacking - as of 2024)
  • WebRTC (to send audio/video/text-blob) - designed for p2p but can be extended to client-to-server by treating server as its peer connection

send/recv data between browser to browser itself (new tab/window/browser/remote browser)

  • Broadcast Channel
  • Webrtc Data Channel (text/blob), Webrtc Media stream (audio/video/screen sharing) - p2p connection
  • MessageChannel (iframe to main, main thread to workers, tabs, window and vice versa)
  • PostMessage (iframe to main, main thread to workers, tabs, window and vice versa)

types of concurrency

last updated: Aug 20, 2024

There are two types of concurrency in general.

  1. co-operative
  2. non-co-operative

co-operative

Co-operative
task#1 making  network call, what happens here is 'I can't processed
further until i get the network call returns'.  control goes to
the main (Event loop) where other tasks can be executed (task #2 here) without blocking

Event loop manages the state of async/await functions where it
checks if the network call is returned or not.

- If returned, then switches to task #1 and proceeds further next line(console.log)
- If not, nothing and continues to checks in the event loop until it is returned..
meanwhile, other tasks are executed

Co-operative since the functions decides when they willingly to pause by the using “await” and execute further instead of executing at some arbitarty point (ie: flow would be disturbed if it executes next lines of the code which depends on the result of the network call arbitrarily instead of waiting on the network call)

  • more like “concurrency on controlled manner”
  • explicit yielding since we are explicitly using await keyword to pause

Non co-operative

There’s non co-operative concurrency where context switch happens arbitrary implicit yielding instead of explicitly yielding to execute (usage of await keyword means explicit yielding).

implicit yielding would be os threads/go routines where runtime scheduler handles the yielding internally without needing to await explicitly to control the concurrency ..

  • more like “concurrency on unhinged manner”
  • implicit yielding since it depends on how os system thread scheduling/go-routine handles it.
Related Bytes:
concurrency-sketch

concurrency sketch

last updated: Jun 09, 2024

Concurrency is illusion of parallelism. parallelism comes under concurrency techniques but it may execute concurrently but not necessarily in parallel. The actual execution (concurrent or parallel) depends on single-core or multi-core, os ability to manage threads etc. In conclusion, all parallel programs are concurrent but not all concurrent programs are parallel..

concurrency context switches between two tasks to create a illusion of running parallely and parallel executes two tasks in parallel manner
Related Bytes:
types-of-concurrency

Design Patterns out in the wild

last updated: Jun 09, 2024

I was tired of seeing some unrelated examples when it comes to explaining design patterns like cars, students etc. And looked for a technical explanation which I couldn’t find it all in a single place. And below are the list of examples for the design pattern that I have seen/used so far in the modern software/web

  • Singleton - Initializing DB, Redis, firebase instance
  • Factory - Initializing like with options createConfig() for dev/prod/staging env
  • Builder - constructor with many params to use builder pattern. In Jest, we use builder pattern via expect().toBe();
  • Abstract Factory - For example we are writing a application for both online/offline we can define a factory like this: Connectivity -> ConnectivityLocal or Remote
  • Bridge Pattern - Capacitor Plugin For Android/IOS/Web (Platform Independent)
  • Prototype - cloned object instead of creating new
  • Adapter - In modern web dev, if you want to deploy to different hosting sites like cloudflare/vercel, you will use the adapter as target in vite that converts your build to appropriate api of the hosting environment.
  • Proxy - new Proxy() in js to change the few language features of js (get/set) etc.
  • Decorator - python has @decorator; Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated
  • Observer(like pub/sub) + Iterator (Rxjs)
  • Strategy - It may prove useful for specifying policies in framework design. Using STRATEGY, clients may parameterize the implementation. For example, error-handling is typically delegated to the application. Such a design may be realized by letting the client provide a strategy to be invoked upon an error. By those means, the error may be handled in an application specific manner, which may stretch between simply ignoring the error to logging it or even reboot the system (Patterns in C book)
  • Mediator - Middleware (Auth, CORS etc)

form accessibility

last updated: Oct 30, 2023

For <form>,

  • use semantic html tags like <label>, <input> with appropriate type, <select> rather than div all around
  • <fieldset> and <legend> to group elements
  • to group/associate label and input, use for and id attributes on it
  • to handle error in the forms use (aria-invalid, aria-describedBy with appropriate id)
  • to navigate to the next form element, use enterkeyhint (look up on MDN), it will improve UX when using virtual keyboard (for example: mobile keyboard) along with event listeners for handling keydown events.
  • make sure to handle events (keyboard events) (for example: if used <div> to create checkbox, ensure keydown space/enter is handled, aria-checked, role, focusable).. ie: if creating custom components, make sure to add appropriate role, aria attributes, handle aria states, events, label, focusable.
  • Test using NVDA / TalkBack
  • Remember Placeholder text is not a replacement for labels