HN user

aivarsk

152 karma

http://fuxedo.io/ - An Open Source alternative to Oracle Tuxedo http://aivarsk.com/

Posts31
Comments25
View on HN
www.youtube.com 5mo ago

Architecture as Science – Barry O'Reilly – NDC Oslo 2025

aivarsk
2pts0
www.youtube.com 5mo ago

Modular Monoliths and Other Facepalms – Kevlin Henney – NDC London 2026

aivarsk
2pts0
kevlinhenney.medium.com 5mo ago

Code Cleanliness On the origins of 'clean code'

aivarsk
3pts2
www.youtube.com 5mo ago

"Clean Code" a Timeless Truth or a Myth We Keep Telling Ourselves?

aivarsk
1pts0
solid-is-not-solid.com 6mo ago

Solid is not so solid

aivarsk
4pts2
aivarsk.com 7mo ago

TigerBeetle as a File Storage

aivarsk
41pts4
aivarsk.com 7mo ago

Running TigerBeetle without a control plane database. Part one

aivarsk
2pts1
aivarsk.com 9mo ago

The Lost Art of Semaphores

aivarsk
2pts0
www.youtube.com 10mo ago

Pycon UK 2025: Principle Misunderstandings, Kevlin Henney [video]

aivarsk
8pts0
aivarsk.com 10mo ago

Ring Buffer in the Database

aivarsk
1pts0
www.youtube.com 11mo ago

Discussing "99 Bottles of OOP": Our First DNF (Did Not Finish) [video]

aivarsk
1pts0
vimeo.com 11mo ago

Solid Deconstruction – Kevlin Henney [video]

aivarsk
1pts0
www.youtube.com 11mo ago

Handmade Hero – Getting rid of the OOP mindset [video]

aivarsk
3pts0
aivarsk.com 1y ago

A broker-less distributed messaging system from the previous century

aivarsk
3pts0
aivarsk.com 1y ago

Python JSON encoder apples and oranges and making it faster

aivarsk
2pts0
aivarsk.com 1y ago

Ledgers are simple, stop spreading FUD

aivarsk
1pts0
aivarsk.com 1y ago

Making sense of card range query EXPLAIN plans

aivarsk
1pts0
2023.djangoday.dk 1y ago

Pessimism, optimism, realism and Django database concurrency

aivarsk
1pts0
aivarsk.com 1y ago

The COST of double-entry accounting with a PoC in Django

aivarsk
1pts0
www.tonymarston.net 1y ago

Not-So-Solid OO Principles

aivarsk
2pts0
aivarsk.com 1y ago

The O of Solid

aivarsk
2pts0
aivarsk.com 1y ago

The S of Solid

aivarsk
2pts0
www.youtube.com 2y ago

Building a Python ORM from scratch in 25 minutes

aivarsk
1pts0
www.youtube.com 2y ago

Building a Python debugger in 20 minutes

aivarsk
11pts0
aivarsk.com 2y ago

Accounting Systems Before TigerBeetle

aivarsk
1pts0
aivarsk.com 4y ago

FastAPI and Cooperative Multi-Threading

aivarsk
2pts0
pypi.org 5y ago

Show HN: Python3 bindings for writing Oracle Tuxedo clients and servers

aivarsk
1pts0
github.com 6y ago

Show HN: Fuxedo – An Open Source Alternative to Oracle Tuxedo

aivarsk
7pts0
www.infoq.com 7y ago

Going Pro: Lifestyle Systems for the Exceptional Developer

aivarsk
2pts0
aivarsk.github.io 7y ago

How many PINs your payment card has?

aivarsk
3pts0

SQL is complete but ugly: everything is expressible, but nothing is reusable; simple ideas are complex to express; the language is verbose and lacks smart defaults.

It begs for examples of the ugly/verbose/complex SQL and the beautiful/succinct/simple Malloy. Looking at the samples folder did no work for me.

Not mentioned by others, http://atlantic.net starts at $5 a month. DigitalOcean has a similar offer with much better documentation. I run a couple of larger servers at DigitalOcean and am really satisfied with uptime, management console, etc. So my vote goes for DigitalOcean.

But Atlantic had a 256Mb RAM, 10Gb disk option years ago for just $0.99 I still have one server there for hosting static HTML, running some scraping tasks, MS document to PDF conversion service (Python Twisted) for a customer, etc. All that for just $1.20 a month (including VAT)

I work from home 1-3 days a week. I'm also father of 3 boys (2, 8, 10) and wife is working full-time.

My only setup is my ThinkPad T450s. That's all.

At some point in my carrier I used 4 monitors, specific low profile keyboards and mice at the office but I don't miss that. It took some time (years!) to adjust my workflow to a single screen and maybe I'm not as productive as I could be but I'm still among the most productive employees at my company.

What I achieved is that I'm equally productive and +/- comfortable anywhere: at work, on the couch or office room at home, on a train, at airport, in the garden, anywhere. That consistency is more important to me than maximum efficiency.

So that and I choose what kind of tasks I work on when I'm alone or when family is at home because you can't expect to fully isolate yourself.

I developed and maintained CI scripts for large modular C++ application 10+ years ago. Someone added `rm -rf $(SOME_TEMP_DIR)/` to global Makefile that was run before building anything. My CI scripts did not set SOME_TEMP_DIR...

Came to work the next day, nightly build still had not finished on slave servers, had errors about non-existent home folder when tried to log in.

What made it worst was that every server mounted a NFS share that contained fingerprints and binaries of different versions of software modules built on different platforms.

Killed all slaves, restored the NFS share from week old backups on tapes, tens of developers could not create new versions of software and send previous versions/patches to customers for a while.

I quickly looked at it and "don't use envelopes by default", "paginate using Link headers" contradict what http://jsonapi.org/ specification says. json:api might not be the best standard and there might be better ones but using something that has many implementations in different languages is better that rolling your own.

I probably should have started by telling it was years ago when applications had to work on OSes other than Linux and BSD (AIX, HP-UX, Solaris). Today it's libev or Boost.Asio.

why not just use poll(2) instead?

Because as I mentioned later poll basically is the same as select but requires more memory to be copied to/from kernel and was slower in some test cases although I can come up with cases where poll will be faster than select. Networking libraries like libev and others allocate fd_set the same way.

> To find out which sockets have events some loop through data structures and check each socket they contain. But a much better way is to iterate through fd_set as array of long and check 32-64 bits at a time.

you're better off switching to a socket API that scales well (epoll or kevent) and does this filtering for you. Or like another commenter suggested, using a library that abstracts this functionality.

That's how kernel, libev and others work with fd_set.

> The correct way is to maintain a descriptor set all the time and create a copy of it and pass the copy to select.

Again -- if you've reached the point where this tradeoff matters, just go directly to epoll/kevent.

Again -- libev and others do this

Maybe your program deals with non-socket fds, and the set of socket fds is fairly sparse. Using a map is actually pretty reasonable even if fds are dense.

Yes, there might be cases where you have non-sockets and you can't use array indexed by socket. But it's great in most of the cases and kernel will keep it as dense as possible. It might be that you have 10,001 connections and then 10,000 are closed and highest socket is still in use and array memory is wasted. But it will not require more memory than during peaks.

libev use of select: http://cvs.schmorp.de/libev/ev_select.c?revision=1.56

What you wrote about the design flaws of select is correct but a feed set with 10,000 sockets is just 1250 bytes or 157 longs and hardware is very good at sequential memory access. I agree it will be slower than kqueue or epoll for long-lived connections because there is more work to do for the kernel and application but for many applications select is good enough when used correctly.

I have my doubts about select causing 100% cpu utilization, I suspect you were doing other suboptimal things as well. The sample code I wrote is running well with both 100 and 10,000 connections. I have my own anecdotal evidence where application was barely handling just 100 mostly inactive connections and OPS guys suggested limits of just 50 connections per application. After I fixed how feed sets were created and how the result of select was processed the same application was running just fine with 8,000 connections. We had to support Linux, Solaris, AIX and HP-UX at that time and select/poll were available on all of them. That's why I invested time in optimizing the code instead of switching to epoll. OPS guys still suggested limit of 1,000 connections per application but this time it was for availability and other non-performance reasons.

I did some tests years ago and a single-threaded event loop was able to handle more than 10,000 short-lived connections per second sending and receiving ISO 8583 bitmaps (38,000 with 2 threads if I remember correctly). And the bottleneck was not in networking APIs or code but in middleware (Oracle Tuxedo) calls that were done in the same thread. I think you can do even more with modern hardware.

You just have to use select() correctly:

1) You can raise the 1024 limit of feed set size by "#define FD_SETSIZE 65536" (required for SunOS to use select_large_fdset() instead of select()) and allocating memory for fd_set yourself.

2) Do not loop over descriptors and use FD_ISSET to check if file descriptor is in set. Instead loop over fd_set one word at a time: if word != 0 then go and analyze each bit of that word (see how Linux kernel does it).

3) The other thing is to limit number of select() calls you make per second and do short sleeps if needed. That allows for events to be processed in batches and the cost of select() calls gets relatively smaller compared to the "real work" done. It also increases latency but you can work out a reasonable number of select() per second. This idea I got from "Efficient Network I/O Polling with Fine-Grained Interval Control by Eiji Kawai, Youki Kadobayashi, Suguru Yamaguchi"

I learned how to use accept() correctly from "Scalability of Linux Event-Dispatch Mechanisms by Abhishek Chandra, David Mosberger". The main idea is to call accept() in a loop until EAGAIN or EWOULDBLOCK is returned or you have accepted "enough" connections.

I don't get why author claims that epoll() fixes the problem with registering and unregistering descriptors. If you use epoll then adding or removing a descriptor is a system call but in case of select() you just modify a local data structure and call select() when you're done adding and removing all of descriptors. And you shouldn't call accept() from multiple threads, a single thread calling accept() is enough for most of us unless you're web scale ;-D

I have some questions:

Have you experienced malloc failing a lot? How do you test to ensure error handling code paths work as expected?

Have you read 'notes' section of Linux malloc manpage? It says:

By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer.