Tag Archives: Rust

Hyper Websocket

As much as I do like Rust I have to admit there are some disadvantages of using this language – one common problem is immaturity and fragmentation of libraries –  I encountered this recently when I was looking for a way how create a websocket endpoint for audioserve.  audioserve is using low level HTTP library hyper – as it’s API is quite simple (which was it’s key design principle). I wanted to add websocket support on lowest possible level.  Actually it turned out as not totally trivial –  some frameworks like warp or actix have build in websocket support, but for pure hyper + websocket we have to start from bottom.  Continue reading Hyper Websocket

Static Build of Rust Executables

Recently I wanted to create completely static build of audioserve – so it can be easily moved and  run on any modern 64bit linux without any other actions. Rust provides some guidelines for static building, but it still took me some time to make it work, mainly due to dependencies on other C/C++ libraries (libssl, libavformat …). So here I my experiences: Continue reading Static Build of Rust Executables

Future Is A State Machine

I think I noticed in this article that Rust Future is basically a state machine, which is propagated through its states via appropriate runtime (and parked when not ready to move to a next state). But I did not appreciate this fact fully until recently I was making a small utility for creating tar archive asynchronously – it should be a Stream that produces chunks of data – first file header and then pieces of it’s content. When file is done move to next file, until all required files are sent to stream, then finally send two empty blocks, each of 512 bytes of binary zeros. I needed this Stream for my audioserve project, where I wanted to download content of whole directory as a tar archive. Stream is a kind of Future (which produces many values instead of just one), so it’s also a state machine. And when I started to think about it this way, implementation was obvious. Rust algebraic type system is of great help here as we can represent state  with one complex enum type ( called TarState in this case) and it’s variants represent states of this state machine and also contain necessary internal variables for each state.  So lets see state diagram for our TarStream: Continue reading Future Is A State Machine

Sqlite3 – How Slow Is Write?

Sqlite3 is lightweight relational database, mainly focused on smaller local systems. Being used in Android it’s now probably most spread relational database in world with billions of instances running. Lite in the name means that it is not client-server architecture and it’s intended for lower data volumes – ideal usage profile is read mostly, with occasional writes. Sqlite3 is often used as an embedded data store in various applications (Firefox and Chrome are most prominent ones). Recently I’ve been playing a bit with sqlite3 interface in Rust and had run couple of simple tests especially focused on writes. So how does sqlite3 performs and how it compares with other more typical client-server RDBMS like PostgreSQL?  It’s not any serious benchmark, just couple of toy tests to highlight few things. Continue reading Sqlite3 – How Slow Is Write?

Future Never Sleeps

Recently I’ve been reading this book:  “Network Programming with Rust” by Abhishek Chanda. I found this book bit problematic. It’s just collection of many unrelated examples (often taken from crates documentation), with just little of background and concepts explanation and in some parts this book is just wrong, in other parts it’s using too much simplifications, so the result does not make much sense or worst it introduces some dangerous ideas. One of these  places is part about futures and streams – let’s look at one example: Continue reading Future Never Sleeps

Fearless Upgrades with Typed Languages

One of many advantages of statically typed programing languages like Rust or Java is their resilience to changes in dependent libraries, usually caused by new library versions with modified interface – e.g. the major version changes. In statically typed language we usually see problems in compile time and it should be relatively easy to fix, but in dynamic languages such as Python or Javascript upgrade is more challenging and problems  demonstrate themselves during tests (in better case, when we have good test coverage) or in production in worst case. I had recently came through this process for couple of  relatively small projects in Rust. Couple of dependencies (hyper and tokio) had been upgraded to new versions with significant changes to their interface. With update compilation broke with tens of errors, but gradually I was able to fix all of them (in one case it required to improve error handling with custom error type, plus using additional new library, as typed headers were removed form hyper) and after code compiled and run through basic tests I was pretty sure that I’m fine with new libraries. In similar situation in python I would need much more work to be sure that code works after such major upgrade of dependencies. In practice it enables easier maintenance of code and less effort  to keep it up to date with latest libraries. For library authors it provides more freedom and they can introduce breaking changes more often (with great cargo build tool in Rust library users can pin themselves to older version, if they do not want to upgrade).

From Ignorance to Enlightenment – Playing with Tokio

I have been playing with tokio already in couple of small projects (ptunnel-rust and indirectly (via hyper) in audioserve), but I cannot say that I’m proficient.  Also tokio is very much moving target –  what I used couple month ago is already bit outdated now(old version is tokio_core crate – where default executor was on current thread, now it’s work stealing thread pool). So I decided to refresh and deepen my knowledge and created a toy project –  stupid jokes server –  it’s a TCP sever, which sends a random  joke to client after it connects and then closes connection. Jokes are stored in text file, separated by dashed lines.  My main interest was to test how to use local file system I/Os, which are blocking by nature, with tokio asynchronous approach (so I initially skipped easiest and probably most efficient implementation, where all jokes would be cached in memory).  Usually in a real project you’ll have some blocking code, so I need to know how to handle it. This article is history of my attempts (and failures) recorded in a hope that it might help others in learning tokio (and also writing it down helped me to absorb gained knowledge). Continue reading From Ignorance to Enlightenment – Playing with Tokio

How much better is the thread pool?

Is thread pool worth to consider for my project?   I was  looking for some opinions around the net and as usual they  differ and most common wisdom is it matters. Generally it’s “known” that creating and tearing down thread is “significant” overhead, so if you have a lot of small tasks thread pool is much better solution then spawning new thread for each task.  But what is significant overhead?  According to what I read time to create thread on Linux should be about 10μs (which does not look as too much to me) and app. 2MB of memory allocated for stack (configurable).   I was considering thread pool in context of audioserve project, where I started with simplest possible solution (e.g. spawning individual threads ) and was wondering how much I’m loosing by not using thread pool. So I implemented simple thread pool (as learning exercise – long term audioserve solution should use tokio-threadpool)  and add it to audioserve.  In the remainder of this short article I’d like to share my findings and  roughly quantify benefits of thread pool for such small project. Continue reading How much better is the thread pool?

Asynchronous Again – Rewriting ptunnel in Rust

Asynchronous programing model is quite popular for I/0 intensive tasks – it enables you effective use of resources, while maintaining agility of and assuring scalability of the application. I myself used asynchronous programming many times –   in JavaScript (where it’s omnipresent) , Python ( mainly  in asyncio recently, but also bit in twisted, which was one of first network asynchronous libraries I met) and also in OCAML with  lwt or Core Async. The concept is always similar for all implementations –  I/O operations are returning handles to future results – they are called either  Futures, Promises, or Deferred  – and they are returned immediately.  These futures can have functions attached to them, which are executed later, when I/O result becomes available.  Asynchronous  programming is very much about functions, it requires first class functions  and anonymous functions are very useful here, that’s why asynchronous model flourishes in functional languages.  Apart of I/O deferred processing usually there are other utilities for later execution – like timeouts, pausing execution for some time (sleep), tasks synchronization (events, locks). Futures are executed in an “event loop”,   a loop that monitors various events from OS (availability of data from I/O), timers, etc. to execute futures (meaning functions attached to them), when appropriate. It’s also very common to chain futures, executing second one with result of first one , when first one is resolved and result is available and the third one with results from the second one and so on. Apart of this basic scheme languages may provide some syntactic sugar around asynchronous model like await and async keywords in Python or C#, which makes it easier to write the code.

Recently, as I’m progressing in learning of Rust,  I wondered how asynchronous programing is done in Rust. I decided to remake my old project ptunnel (written in Python) into Rust – ptunnel is a program that tunnels arbitrary connection/protocol through HTTPS proxy, so it can be used to connect IMAP, SMTP or SSH through proxy. In the rest of this article I”l share my experiences from this project. Continue reading Asynchronous Again – Rewriting ptunnel in Rust