MySQL 8.0: New Lock free, scalable WAL design

MySQL 8.0: New Lock free, scalable WAL design

MySQL Server Blog
News from the MySQL Server Team
Menu Skip to content
Search for:
MySQL 8.0: New Lock free, scalable WAL design
June 18, 2018InnoDB, IO, PerformanceREDO, WALPaweł Olchawa
The Write Ahead Log (WAL) is one of the most important components of a database. All the changes to data files are logged in the WAL (called the redo log in InnoDB). This allows to postpone the moment when the modified pages are flushed to disk, still protecting from data losses.

The write intense workloads had performance limited by synchronization in which many user threads were involved, when writing to the redo log. This was especially visible when testing performance on servers with multiple CPU cores and fast storage devices, such as modern SSD disks.

We needed a new design that would address the problems faced by our customers and users today and also in the future. Tweaking the old design to achieve scalability was not an option any more. The new design also had to be flexible, so that we can extend it to do sharding and parallel writes in the future. With the new design we wanted to ensure that it would work with the existing APIs and most importantly not break the contract that the rest of InnoDB relies on. A challenging task under these constraints.

Redo log can be seen as a producer/consumer persistent queue. The user threads that do updates can be seen as the producers and when InnoDB has to do crash recovery the recovery thread is the consumer. InnoDB doesn’t read from the redo log when the server is running.

But writing a scalable log with multiple producers is only one part of the problem. There are InnoDB specific details that also need to work. The biggest challenge was to preserve the total order of the dirty page list (a.k.a the flush list). There is one per buffer pool. Changes to pages are applied within so-called mini transactions (mtr), which allow to modify multiple pages in atomic way. When a mini transaction commits, it writes its own log records to the log buffer, increasing the global modification number called LSN (Log Sequence Number). The mtr has the list of dirty pages that need to be added to the buffer pool specific flush list. Each flush list is ordered on the LSN. In the old design we held the log_sys_t::mutex and the log_sys_t::flush_order_mutex in a lock step manner to ensure that the total order on modification LSN was maintained in the flush lists.

Note that when some mtr was adding its dirty pages (holding flush_order_mutex), another thread could be waiting to acquire the flush_order_mutex (even if it wanted to add pages to other flush list). In such case the waiting thread was holding log_sys_t::mutex (to maintain the total order), so any other thread that wanted to write to the log buffer had to wait… With the removal of these mutexes there is no guarantee on the order of the flush list.

Second problem is that we cannot write the full log buffer to disk because there could be holes in the LSN sequence, because writes to the log buffer are not finished in any particular order.

The solution for the second problem is to track which writes were finished, and for that we invented a new lock-free data structure.

The new data structure has a fixed size array of slots. The slots are updated in atomic way and reused in a circular fashion. A single thread is used to traverse and clear them, making a pause at a hole (empty slot). This thread updates the maximum reachable LSN (M).Two instances of this data structure are used: the recent_written and the recent_closed. The recent_written instance is used for tracking the finished writes to the log buffer. It can provide maximum LSN, such that all writes to the log buffer, for smaller LSN values, were finished. Potential crash recovery would need to end at such LSN, so it is a maximum LSN up to which we consider a next write. The slots are traversed by the same thread that writes the log buffer to disk afterwards. The proper memory ordering for reads and writes to the log buffer is guaranteed by the barriers set when reading/writing the slots.

Let’s look at the picture above. Suppose that we finished one more write to the log buffer:

Now, the dedicated thread (log_writer) comes in, traverses the slots:

and updates the maximum LSN reachable without the holes – buf_ready_for_write_lsn:

The recent_closed instance of the new data structure is used to address problems related to the missing log_sys_t::flush_order_mutex. To understand the flush list order problem and the lock free solution there is a little more detail required to explain.

Individual flush lists are protected by their internal mutexes. But we no longer preserve the guarantee that we add dirty pages to flush lists in the order of increasing LSN values. However, the two constraints that must be satisfied are:

Checkpoint – We must not write fuzzy checkpoint at LSN = L2, if there is a dirty page for LSN = L1, where L1 < L2. That’s because recovery starts at such checkpoint_lsn.
Flushing – Flushing by flush list should always be from the oldest page in the flush list. This way we prefer to flush pages that were modified long ago, and also help to advance the checkpoint_lsn.
In the recent_closed instance we track the concurrent executions of adding dirty pages to the flush lists, and track the maximum LSN (called M), such that all executions, for smaller LSN values have completed. Before a thread adds its dirty pages to the flush lists, it waits until M is not that far away. Then it adds the pages and then reports the finished operation to the recent_closed.

Let’s take an example. Suppose that some mtr, during its commit, copied all its log records to the log buffer for LSN range between start_lsn and end_lsn. It reported the finished write to the recent_written (the log records might be written to disk since now). Then the mtr must wait until it holds: start_lsn – M = last_lsn. In the new design it is only guaranteed that all the pages in the flush list have oldest_modification >= last_lsn – L. The condition holds because we always wait if M is too far away before inserting pages.

Proof. Let’s suppose we had two pages: P1 with LSN = L1, and P2 with LSN = L2, and P1 was added to flush list first, but L2 < L1 – L. Before P1 was inserted we ensured that L1 – M < L. We had M L1 – M >= L1 – L2, so L2 > L1 – L. Contradiction – we assumed that L2 = X, selects a shard to which the X belongs. This decreases the synchronization required when attempting a wait. But what is even more important, thanks to such split, we can wake up only these threads that will be happy with the advanced flushed_to_disk_lsn (except some of those waiting in the last block).

When flushed_to_disk_lsn is advanced, the log_flush_notifier thread wakes up threads waiting on intermediate values of LSN. Note that when log_flush_notifier is busy with the notifications, next fsync() call could be started within the log_flusher thread!

The same approach is used when innodb_flush_log_at_trx_commit =2, in which case users don’t care about fsyncs() that much and wait only for finished writes to OS cache (they are notified by the log_write_notifier thread in such case, which synchronizes with the log_writer thread on the write_lsn).

Because waiting on an event and being woken up increases latency, there is an optional spin-loop which might be used in front of that. It’s by default being used unless we don’t have too much free CPU resources on the server. You can control that via new dynamic system variables: innodb_log_spin_cpu_abs_lwm, and innodb_log_spin_cpu_pct_hwm.

As we mentioned at the very beginning, redo log can be seen as producer/consumer queue. InnoDB relies on fuzzy checkpoints from which potential recovery would need to start. By flushing dirty pages, InnoDB allows to move the checkpoint LSN forward. This allows us to reclaim free space in the redo log (blocks before the checkpoint LSN are basically considered free) and also makes a potential recovery faster (shorter queue).

In the old design user threads were competing with each other when selecting the one that will write the next checkpoint. In the new design there is a dedicated log_checkpointer thread that monitors what are the oldest pages in flush lists and decides to write the next checkpoint (according to multiple criteria). That’s why no longer the master thread has to take care of periodical checkpoints. With the new lock free design we have also decreased the default period from 7s to 1s. This is because we can handle transactions much faster since the 7s were set (we write more data/s so faster potential recovery was the motivation for this change).

The new WAL design provides higher concurrency when updating data and a very small (read negligible) synchronization overhead between user threads!

Let’s have a look at simple comparison made between version just before the new redo log, and just after. It’s a sysbench oltp update_nokey test for 8 tables, each with 10M rows, innodb_flush_log_at_trx_commit = 1.

For details about different tests please read:

Thank you for using MySQL !

Facebook Twitter Google+ LinkedIn

About Paweł Olchawa
InnoDB developer, co-founder of polish social network – View all posts by Paweł Olchawa →

Post navigation
← MySQL 8.0: Optimizing Small Partial Update of LOB in InnoDB The connection_control plugin : Keeping brute force attack in check →
3 thoughts on “MySQL 8.0: New Lock free, scalable WAL design”
Pingback: MySQL 8.0: New Lock free, scalable WAL design – 지락문화예술공작단
Pingback: MySQL Performance : 8.0 GA on IO-bound Sysbench OLTP with Optane -vs- SSD
Pingback: innodb_thread_concurrencyに関する話 | GREE Engineers’ Blog
Leave a Reply
You must be logged in to post a comment.

Recent Posts
JSON_TABLE – The Best of Both Worlds
MySQL Shell 8.0.12 – What’s New?
Getting Help in MySQL Shell
The MySQL 8.0.12 Maintenance Release is Generally Available
MySQL Shell 8.0.12 – storing MySQL passwords securely
Recent Comments
Bernt Marius Johnsen on Projected Spatial Reference Systems in MySQL 8.0
Geir Hoydalsvik on MySQL 8.0.4 : New Default Authentication Plugin : caching_sha2_password
Paul on MySQL 8.0.4 : New Default Authentication Plugin : caching_sha2_password
John on What’s New in MySQL 8.0? (Generally Available)
Reggie Burnett on What’s New in MySQL 8.0? (Generally Available)
Search for:
Search …
Log in
Entries RSS
Comments RSS
Subscribe via Email
Enter your email address to receive notifications of new posts by email.

Email Address
Email Address

Proudly powered by WordPress



Gapminder – About

Custom Search
About Gapminder
Our mission Contact Our Supporters History Awards Request a speaker Our Team Press and media Constitution
Gapminder is an independent Swedish foundation with no political, religious or economic affiliations. Gapminder is a fact tank, not a think tank. Gapminder fights devastating misconceptions about global development. Gapminder produces free teaching resources making the world understandable based on reliable statistics. Gapminder promotes a fact-based worldview everyone can understand. Gapminder collaborates with universities, UN, public agencies and non-governmental organizations. All Gapminder activities are governed by the board. We do not award grants. Gapminder Foundation is registered at Stockholm County Administration Board. Our constitution can be found here.

We humans are born with a craving for fat and sugar. But we are also born with a craving for drama. We pay attention to dramatic stories and we get bored if nothing happens.

Journalists and lobbyists tell dramatic stories. That’s their job. They tell stories about extraordinary events and unusual people. The piles of dramatic stories pile up in people’s minds into an overdramatic worldview and strong negative stress feelings: “The world is getting worse!”, “It’s we vs. them!” , “Other people are strange!”, “The population just keeps growing!” and “Nobody cares!”

For the first time in human history reliable statistics exist. There’s data for almost every aspect of global development. The data shows a very different picture: a world where most things improve; a world that is not divided. People across cultures and religions make decisions based on universal human needs, which are easy to understand. The fast population growth will soon be over. The total number of children in the world has stopped growing. The remaining population growth is an inevitable consequence of large generations born decades back. We live in a globalized world, not only in terms of trade and migration. More people than ever care about global development! The world has never been less bad. Which doesn’t mean it’s perfect. The world is far from perfect.

The dramatic worldview has to be dismantled, because it is stressful and wrong. It leads to bad focus and bad decisions. We know this because we have measured the global ignorance among the world’s top decision makers in public and private sector. Their global ignorance is high, just like the ignorance of journalists, activists, teachers and the general public. This has nothing to do with intelligence. It’s a problem of factual knowledge. Facts don’t come naturally. Drama and opinions do. Factual knowledge has to be learned. We need to teach global facts in schools and in corporate training. This is an exciting problem to work on and we invite all our users to join the Gapminder movement for global factfulness. The problem can be solved, because the data exists.

Instead of wasting our time blaming the media or condemning the human brain, we develop free teaching material to dismantle misconceptions and promote a fact-based worldview.

Gapminder measures ignorance about the world
We identify the most ignored global facts by comparing what people think against the official statistics. We run public polls and we ask knowledge questions to live audiences from stage.

Gapminder makes global data easy to use and understand
We develop data visualization tools to let people explore the vast treasure of global statistics. Since many people hate statistics, we use photos as data to give the numbers meaning. We have sent photographers to 240 homes across the world to show how people really live. That’s what we call a fact-based worldview.

Gapminder provides courses and certificates
We also develop teaching materials and knowledge certificates. With our teacher certificate we want to create a global network of trusted Gapminder teachers who can represent us locally.

Gapminder promotes Factfulness, a new way of thinking
We promote a new way of thinking about the world and the society which we call Factfulness. It is the relaxing habit of carrying opinions that are based on solid facts.

Gapminder collaborates with educators across the world
Subscribe to our Newsletter and we’ll let you know how you can participate.

Help Gapminder provide a fact-based worldview for free!
$10 $100 $1 000 $10 000 $100 000 $
Enter amount

Swish number: 123 327 55 75

Terms of Use


Online Video Converter

Online Video Converter

Mit kannst du kostenlos Videos von YouTube, Dailymotion und Clipfish online in MP3, MP4 und in weitere Formate konvertieren und downloaden. Der Service ist schnell, legal, kostenlos und ohne Registrierung.

Videolink (URL) einfügen und Zielformat wählen

mp3 umwandeln
Suchbegriff (Videotitel) eingeben

Dein Suchbegriff…
Suchen und umwandeln
Suche ein Video

auf YouTube, Dailymotion, Clipfish oder bei uns.

Kopiere den Link

des gewünschten Videos und füge ihn oben ein.

Format wählen, umwandeln

und dann downloaden.

Mit der Verwendung unseres Services akzeptierst du unsere Nutzungsbedingungen.

So einfach gehts:
Suche ein Video, dass du umwandeln möchtest z.B. auf YouTube, Dailymotion oder Clipfish und kopiere den Link (Adresse bzw. URL) von dem gewünschten Video in das obere Feld. Alternativ kannst du auch über unsere Seite nach einem Video auf YouTube suchen, dazu einfach den Videotitel in das untere Feld eingeben. Dann nur noch das das Zielformat auswählen und den umwandeln-Button drücken.
Nachlesen, warum legal ist.

Cedric Nugteren

Cedric Nugteren

I received my Bachelors (Electrical Engineering) and Masters (Embedded Systems) from Eindhoven University of Technology. In April 2014, I successfully defended my PhD thesis at the same university. During the PhD I gained experience through two internships: with the OpenCL compiler group of ARM in Cambridge (UK), and with the cuFFT team of NVIDIA in Santa Clara (CA). After that, I worked as a GPU consultant at the SURFsara supercomputing centre and as a C++ performance engineer for a computer vision and machine learning team at Blippar. Currently, I work at TomTom on deep learning for autonomous driving.
Interests and expertise
My main expertise is C++11/14 and GPU programming (CUDA/OpenCL). On top of this, I also have experience with Python, compilers, high-performance computing, computer architecture, performance modelling, computer vision, and machine learning / deep learning.

My passion lies with the development of beautiful and performant C++11 codes, possibly accelerated by GPUs. Examples are CLTune, an OpenCL auto-tuner, and CLBlast, an OpenCL BLAS library.
Profiles on other pages
Google Scholar
Work experience
07/2016 – current
TomTom (Amsterdam)
Deep learning / GPU specialist for autonomous driving
I work as a deep learning and GPU performance specialist on computer vision and machine learning algorithms for autonomous driving.
11/2015 – 06/2016
Layar / Blippar (Amsterdam)
R&D engineer performance optimization
I worked as a C++11 performance engineer on computer vision and machine learning algorithms for an augmented reality company. My work included multi-threading, vectorisation and GPU-acceleration.
05/2014 – 10/2015
SURFsara (Amsterdam)
GPU/Supercomputing consultant
I worked as a consultant for the Dutch national supercomputing/HPC centre, specialised in accelerator programming (Xeon Phi, GPU). My job involves tuning scientific codes (C/C++/Fortran) for multi-cores (OpenMP), multiple nodes (MPI), and accelerators (OpenCL/CUDA). I have worked on codes from various domains, including finite element methods, fluid dynamics, and quantum chemistry.
01/2014 – 04/2014
NVIDIA Santa Clara (California)
CUDA software engineer
I worked for four months as an intern GPU programmer at the NVIDIA headquarters in Silicon Valley within the math libraries group, developing and performance tuning the CUDA Fast Fourier Transform library (cuFFT).
08/2012 – 12/2012
ARM Cambridge (United Kingdom)
Research intern
As part of a 4-month HiPEAC sponsored internship, I performed research within the ARM Mali OpenCL compiler team. I created a machine-code level mathematical performance model for the Mali T600-series, one of the first OpenCL capable low-power GPU architectures. Additionally, I worked on a GPU cache model, and was involved in the design of the PENCIL language, part of the CARP EU project.
11/2009 – 11/2010
Eindhoven University of Technology (Netherlands)
Scientific Programmer
Within the Electronic Systems group, I worked full-time as a scientific programmer, which included research into processor architecture (GPUs, SIMD) targeted at image and video processing applications (histogram, motion estimation).
10/2009 – 12/2014
Kinento (Netherlands)
Founder and owner of Kinento
Kinento is a privately owned e-commerce company. Three PHP extensions to Magento were developed and maintained. From 2015 onwards, they are open-sourced and available for free on GitHub.
11/2010 – 04/2014
Eindhoven University of Technology (Netherlands)
Doctor of Philosophy (PhD)
Under the supervision of prof. Henk Corporaal, I performed research on GPUs. This covered most aspects of GPUs, including micro-architecture, compilers, performance modelling, and programmability issues. This has led to two journal articles, a patent application, and several publications in international conferences and workshops. During my PhD, I interned for 4 months at both ARM and NVIDIA. My PhD thesis is titled ‘Improving the Programmability of GPU Architectures’ and is available in PDF form.
08/2008 – 02/2009
Universidad Polytecnica de Valencia (Spain)
MSc. in Computer Science
Master degree program in Spanish, part of a six month Erasmus exchange.
08/2007 – 08/2009
Eindhoven University of Technology (Netherlands)
MSc. in Embedded Systems
Two year master degree program with a focus on (multi-)processor architectures. Master thesis carried out at the Electronic Systems group, titled ‘Improving CUDA’s compiler through the visualization of decoded GPU binaries’.
08/2004 – 08/2007
Eindhoven University of Technology (Netherlands)
BSc. Electrical Engineering
Three year bachelor degree program.
tutorial profile_picture
Current job:
Machine learning software engineer

Current location:
Amsterdam, NL

Year of birth:



Why Unix?

Why Unix?

hosted services
why unixwet shavingunix beardsabout this sitebooksRBL serviceforum


6tunnel, 6tunnel, allowing v6 for v4 programs
DNS, sooner AXFR is gone the better
encryption, be sure to hide the plain text
netmon, interface throughput
nt proxy authentication
my perforce quick start guide service
TCP port scanner
ppp settings
snmp counters
socat, SOCKS and SSL
three (3)
throttling connections with iptables and traffic control
what is my IP

ata over ethernet
fcgid notes
fonts, not as simple as you may think
htaccess tips and tricks
jsp notes
locating computers: how to find that lost host
mediawiki for weblogs
meminfo and other useful bits of /proc
MS powershell on linux
printing in linux
qmail goodness
TAL, Template Attribute Language
why is unix better
why is xterm better

advent 4211 netbook
dell latitude e5430 amusement
english dictionary lookup
sun oracle T5240 disk brackets
freenas on artigo a2000
ZFS and the HP N54L
Digital photography

digital photography notes
GIMP shopping notes


chicken keeping
Hosting providers


good service
bad service
connection problem generator
1930’s spouse test
mixcloud stream retrieval
easy to remember password generator
RBL checker
royal jelly
qr barcode generator
vitality point tracking
yahoo messes up mail for b3ta
yahoo group mail box retrieval
Last modified: Tue, 24 Oct 2017 22:42:15 BST

This site needs your support

PayPal ? The safer, easier way to pay online.

SmallWM is an extended version of TinyWM

SmallWM is an extended version of TinyWM

adamnew123456 / SmallWM
Code Issues 0 Pull requests 0 Projects 0 Pulse

What is SmallWM?
SmallWM is an extended version of TinyWM, made for actual desktop use.

Screenshot of SmallWM

Improvements over TinyWM
Window Iconification
Window Layering
Click-To-Focus and Focus Cycling
Moving/Resizing Placeholders
Multiple Virtual Desktops
Window Snapping
Window Packing
Class Actions
Note that these are the default controls. See the Configuration for details on how to setup keybindings. The only non-configurable key bindings are the ones that involve clicking the mouse, and the Super+1 … Super+9 bindings.

Super+[: Move a window to the previous desktop (client-prev-desktop).
Super+]: Move a window to the next desktop (client-next-desktop).
Super+,: Switch to the previous desktop (prev-desktop).
Super+.: Switch to the next desktop (next-desktop).
Super+\: Sticks/unsticks a window; a stuck window is shown on all desktops (toggle-stick).
Super+h: Iconifies the current window (iconify).
Super+m: Maximizes the current window (maximize).
Super+c, Requests the current window to close (request-close).
Super+x: Force-closes the current window (force-close).
Super+Up, Super+Down, Super+Left, Super+Right: Snaps a window to either the top-half, bottom-half, left-half or right-half of the screen.
Actions: snap-top, snap-bottom, snap-left, snap-right
Super+Ctrl+Up, Super+Ctrl+Down, …: Moves a window to the screen in the relative direction of the arrow key.
Actions: screen-top, screen-bottom, screen-left, screen-right
Super+PageUp, Super+PageDown: Increments or decrements the layer of this window.
Actions: layer-above, layer-below
Super+Home, Super+End: Puts a window on the topmost or bottommost layer.
Actions: layer-top, layer-bottom
Super+Tab: Focuses the next visible window in the focus list (cycle-focus).
Super-Alt-Tab: Focuses the previous visible window in the focus list (cycle-focus-back)
Super+LClick: Dragging the left mouse button starts moving a window – to place it, let go.
Super+RClick: Dragging the right mouse button starts resizing a window – to scale it, let go.
Super+1 … Super+5 … Super+9: These change the layer to the specified value (1, 5, or 9 respectively, in this example)
Super+LClick: Left-clicking the root window launches a new terminal.
Super+Escape: Quits SmallWM.
As a dependency, you’ll need to have access to the headers for Xlib and XRandR. You should be able to easily obtain these via your package manager. You’ll also need a C++ compiler – GNU G++ and clang++ work well. You’ll also need a C compiler to build the inih library included with SmallWM – GNU C and clang work well for this purpose also.

Other than the dependencies, the Makefile contains everything you need to build and test SmallWM.

make compiles a version with symbols useful for debugging. Note that there is no optimized build – if you want an optimized version, open the Makefile and change -g to -O3 in CXXFLAGS.
For modifying SmallWM, the other target that you should be aware of is make check which compiles everything but does no linking. This is useful for incremental building to track compiler errors in source files.

Typically, the easiest place to put the smallwm binary is in /usr/local/bin.

If you want to run SmallWM from your login manager, you should put a file like the following in /usr/share/xsessions/smallwm.desktop:

[Desktop Entry]
Inside the script /usr/local/bin/, you should enter something like the following:

if [ -x $HOME/.smallwmrc ]; then
$HOME/.smallwmrc &

exec /usr/local/bin/smallwm
At this point, you may choose to write a .smallwmrc file to start any programs you wish to run for the duration of your session. Note that SmallWM does not include a process manager to handle session programs (unlike say, XFCE, which will restart components like the panel or the desktop if they crash). I use a tool I wrote myself, called jobmon, to manage my system tray and other programs, but you are free to choose whatever process manager you like, since SmallWM doesn’t care about it.

The C++ version follows a similar configuration file format to the original C version, but with some extended options. It should be placed at $HOME/.config/smallwm.

For example:

The options in the [smallwm] section are (in order):

shell The shell launched by Super+LClick (default: xterm). This can be any syntax supported by /bin/sh.
desktops The number of desktops (default: 5).
icon-width The width in pixels of icons (default: 75).
icon-height The height in pixels of icons (default: 20).
border-width The width of the border of windows (default: 4).
icon-icons Whether to (1) or not to (0) show application icons inside icon windows (default: 1).
log-level The severity of logging messages to send to syslog. By default, this is WARNING. See syslog(3) for the other log levels.
hotkey-mode What window to apply hotkeys like MINIMIZE to – this can be either focus (which means that the currently focused window is acted upon) or mouse (which means that the window under the cursor is acted upon). The default is mouse.
dump-file This is where SmallWM writes internal information dumps when you send it SIGUSR1. This is intended for development purposes only; although it will generally contain information about SmallWM’s desktops, clients and screens, this information is for human consumption and its format is not guaranteed to stay the same. By default, this value is /dev/null, so that any dumps SmallWM generates are not stored anywhere.
X has the notion of an application “class” which is supposed to be a unique identifier for a window which belongs to a particular application. For example, there is a popular system tray called stalonetray which I use personally to manage status notifiers (like for NetworkManager, Dropbox, and the like). A quick xprop of the window shows that its class name is stalonetray.

The example given in the Configuration section shows how to stick any window belonging to stalonetray and layer it on top of all other application windows. Generally speaking, any number of these class actions can be chained together by separating them with commas.

The possibilities for a class action are:

stick makes a particular window stick to all the desktops.
maximize maximizes that window.
layer:x sets the layer of the window to x where x is a number in the range 1 to 9; 9 is the highest layer, 1 is the lowest.
snap:left, snap:right, snap:top, snap:bottom snap the window to the relevant side of the screen.
xpos:X and ypos:Y set the relative position of the window on the screen. X and Y are decimals in the range 0 to 100, inclusive. For example, setting xpos:50 puts the window’s left edge in the middle of the screen (because xpos:50 is equivalent to saying that the X position should be 50 percent of the screen’s width).
pack:CORNERPRIORITY directs SmallWM to fix the position of a group of windows, re-adjusting when they are resized. The CORNER is one of NE, SE, NW or SW (indicating the upper-left, lower-left, upper-right and lower-right corners respectively), and the optional PRIORITY is a non-negative integer (0 by default). See the Packing section below.
nofocus prevents SmallWM from automatically focusing windows of the given class. This is useful for windows like system trays, clocks, or other utility windows that you don’t want to manipulate by accident.
It is important to know that xpos/ypos and pack are mutually exclusive – whatever is listed last in a class’s action list is what is applied. For example, packme is packed but posme is relative-positioned:

Packing allows SmallWM to automatically position windows, according to a very simple set of rules. However, when a window is packed, you lose the ability to manually move and resize it.

The way that the packer works is that it looks at each corner of the screen individually. It then looks at the packed windows, and starts placing them in order of priority, with the lowest priority elements going closest to the corner.

For example, if you have 3 windows:

| A |
| C |
With the priorities:

A 1
B 2
C 3
And you want to pack them into the northeast corner, the result will look like the following; A, the lowest priority, is first placed directly into the corner, with B horizontally placed on the side of A opposite the corner, and then C placed on the edge of B.

| C |B| A |
SmallWM currently does not have a way to pack on secondary monitors (it will always choose the primary minitor), or a way to pack vertically.

Keyboard Bindings
Keyboard bindings in SmallWM are almost entirely (except for Super+1 … Super+9) configurable. The mechanism isn’t that sophisticated, so make sure that you have a copy of /usr/include/X11/keysymdef.h or an equivalent file open.

In order to bind a key, you first have to know the name of the “keysym” that the key uses. To do this, search keysymdef.h for your key – the keysym name is the first word after the #define. The text that you put in the configuration file is the keysym name but with the leading XK_ removed. For example, take toggle-stick=asciitilde in the example configuration file. This binds the toggle-stick action to the XK_asciitilde keysym.

The following options can be set under the [keyboard] section to configure SmallWM’s keyboard bindings.

client-next-desktop, client-prev-desktop
These bindings move the current window to either the next or previous desktop
next-desktop, prev-desktop
These bindings move the view the next or previous desktop
This toggles the desktop stickiness of the current window
This iconifies the current window
This maximizes the current window
This requests that the current window close, allowing the application to show save prompts and the like.
This forces the current window to close. Only use this is an emergency – most applications will crash after you do this.
snap-top, snap-bottom, snap-left, snap-right
Snaps the current window to the top, bottom, left or right half of the screen.
screen-left, screen-right, screen-top, screen-bottom
Moves the current window to the screen to the left of, to the right of, above, or below the current screen it occupies.
layer-above, layer-below
Moves the current window to the layer above or below its current layer.
layer-top, layer-bottom
Moves the current window to the topmost or bottommost layer
cycle-focus, cycle-focus-back
Changes the focused window to the window next (or previous)in the focus list.
Terminates SmallWM
Note the key binding given for snap-right in the example – the ! that prefixes the ‘a’ is used to indicate that this key bindings uses a secondary modifier key (Control, by default). In order to activate snap-left, you need to press Super+Ctrl+a rather than just Super+a. Only the key bindings used to move windows between screens use this by default.

Support for the EWMH and the _NET* atoms
Nick Welch, the original TinyWM author.
Myself (Adam Marchetti
The author(s) of the inih library.
Possibly, you – assuming you make any useful changes and I accept your pull request. Refactorings are welcome, as are those who are actually knowledgeable about Xorg and could spot any obvious mistakes.
SmallWM was migrated to the 2-Clause BSD License on 2013-11-18. See LICENSE.txt for details.

The inih code, included as a part of SmallWM, is available under the New BSD License. See inih/LICENSE.txt for details.