Eindhoven Updated 2025-07-16
In this example, posts have tags. When a post is deleted, we check to see if there are now any empty tags, and now we want to delete any empty tags that the post deletion may have created.
If we are creating and deleting posts concurrently, a naive implementation might wrongly delete the tags of a newly created post.
This could be due to a concurrency issue of the following types.
Failure case 1:
  • thread 2: delete old post
  • thread 2: find all tags with 0 posts. Finds tag0 from the deleted old post which is now empty.
  • thread 1: create new post, which we want to have tag tag0
  • thread 1: try to create a new tag tag0, but don't because it already exists, this is done using SQLite's INSERT OR IGNORE INTO or PostgreSQL's INSERT ... ON CONFLICT DO NOTHING
  • thread 1: assign tag0 to the new post by adding an entry to the join table
  • thread 2: delete all tags with 0 posts. It still sees from its previous search that tag0 is empty, and deletes it, which then cascades into the join table
which would result in the new post incorrectly not having the tag0.
Failure case 2:
  • thread 2: delete old post
  • thread 2: find all tags with 0 posts
  • thread 1: create new post
  • thread 1: try to create a new tag tag0, but don't because it already exists
  • thread 2: delete all tags with 0 posts. It still sees from its previous search that tag0 is empty, and deletes it
  • thread 1: assign tag0 to the new post
which leads to a foreign key failure, because the tag does not exist anymore when the assignment happens.
Failure case 3:
  • thread 2: delete old post
  • thread 1: create new post, which we want to have tag tag0
  • thread 1: try to create a new tag tag0, and succeed because it wasn't present
  • thread 2: find all tags with 0 posts, finds the tag that was just created
  • thread 2: delete all tags with 0 posts, deleting the new tag
  • thread 1: assign tag0 to the new post
which leads to a foreign key failure, because the tag does not exist anymore when the assignment happens.
Sample executions:
  • node --unhandled-rejections=strict ./parallel_create_delete_empty_tag.js p 9 1000 'READ COMMITTED': PostgreSQL, 9 tags, DELETE/CREATE the tag0 test tag 1000 times, use READ COMMITTED
    Execution often fails, although not always. The failure is always:
    error: insert or update on table "PostTag" violates foreign key constraint "PostTag_tagId_fkey"
    because the:
    INSERT INTO "PostTag"
    tries to insert a tag that was deleted in the other thread, as it didn't have any corresponding posts, so this is the foreign key failure.
    TODO: we've never managed to observe the failure case in which tag0 is deleted. Is it truly possible? And if not, by which guarantee?
  • node --unhandled-rejections=strict ./parallel_create_delete_empty_tag.js p 9 1000 'READ COMMITTED' 'FOR UPDATE': do a SELECT ... FOR UPDATE before trying to INSERT.
    This is likely correct and the fastest correct method according to our quick benchmarking, about 20% faster than REPEATABLE READ.
    We are just now 100% sure it is corret becase we can't find out if the SELECT in the DELETE subquery could first select some rows, which are then locked by the tag creator, and only then locked by DELETE after selection. Or does it re-evaludate the SELECT even though it is in a subquery?
  • node --unhandled-rejections=strict ./parallel_create_delete_empty_tag.js p 9 1000 'REPEATABLE READ': repeatable read
    We've never observed any failures with this level. This should likely fix the foreign key issue according to the PostgreSQL docs, since:
    • the DELETE "Post" commit cannot start to be seen only in the middle of the thread 1 transaction
    • and then if DELETE happened, the thread 1 transaction will detect it, ROLLBACK, and re-run. TODO how does it detect the need rollback? Is it because of the foreign key? It is very hard to be sure about this kind of thing, just can't find the information. Related: postgreSQL serialization failure.
  • node --unhandled-rejections=strict ./parallel_create_delete_empty_tag.js p 9 1000 'SERIALIZABLE': serializable
  • node --unhandled-rejections=strict ./parallel_create_delete_empty_tag.js p 9 1000 'NONE': magic value, don't use any transaction. Can blow up of course, since even less restrictions than READ COMMITTED
All executions use 2 threads.
Some theoretical notes:
  • Failure case 3 is averted by a READ COMMITTED transaction, because thread 2 won't see the uncommitted tag that thread 1 created, and therefore won't be able to delete it
stackoverflow.com/questions/10935850/when-to-use-select-for-update from SELECT FOR UPDATE also talks about a similar example, and has relevant answers.
Hadean Updated 2025-07-16
No life, earth too hot, until formation of water.
Proterozoic Updated 2025-07-16
Sinophile Updated 2025-07-16
Tael Updated 2025-07-16
Notably used for measuring gold and silver as a form of Chinese currency.
Tokyo Updated 2025-07-16
Literally: "capital of the East". Note that the Chinese term 东京 (dong1 jing1) is highly ambiguous in historical contexts, as many places throughout history have been known as "the capital of the East".Of of those other places is the Kaifeng, which is the Capital in Water Margin and in real life during the Song dynasty. The novel is also likely highly popular in Japan apparently as well BTW, e.g. it merited a well funded adaptation: The Water Margin.
Bird Updated 2025-07-16
Mojim Updated 2025-07-16
TODO didn't manage from source Ubuntu 22.04, their setup bitrotted way too fast... it's shameful even. Until I gave up and went for the magic Docker of + github.com/bbcmicrobit/micropython, and it bloody worked:
git clone https://github.com/bbcmicrobit/micropython
cd micropython
git checkout 7fc33d13b31a915cbe90dc5d515c6337b5fa1660
docker pull ghcr.io/carlosperate/microbit-toolchain:latest
docker run -v $(pwd):/home --rm ghcr.io/carlosperate/microbit-toolchain:latest yt target bbc-microbit-classic-gcc-nosd@https://github.com/lancaster-university/yotta-target-bbc-microbit-classic-gcc-nosd
docker run -v $(pwd):/home --rm ghcr.io/carlosperate/microbit-toolchain:latest make all

# Build one.
tools/makecombinedhex.py build/firmware.hex examples/counter.py -o build/counter.hex
cp build/counter.hex "/media/$USER/MICROBIT/"

# Build all.
for f in examples/*; do b="$(basename "$f")"; echo $b; tools/makecombinedhex.py build/firmware.hex "$f" -o "build/${b%.py}.hex"; done
The pre-Docker attempts:
sudo add-apt-repository -y ppa:team-gcc-arm-embedded
sudo apt update
sudo apt install gcc-arm-embedded
sudo apt install cmake ninja-build srecord libssl-dev

# Rust required for some Yotta component, OMG.
sudo snap install rustup
rustup default 1.64.0

python3 -m pip install yotta
The line:
sudo add-apt-repository -y ppa:team-gcc-arm-embedded
warns:
E: The repository 'https://ppa.launchpadcontent.net/team-gcc-arm-embedded/ppa/ubuntu jammy Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
and then the update/sudo apt-get install gcc-arm-embedded fails, bibliography:
Attempting to install Yotta:
sudo -H pip3 install yotta
or:
python3 -m pip install --user yotta
was failing with:
Exception: Version mismatch: this is the 'cffi' package version 1.15.1, located in '/tmp/pip-build-env-dinhie_9/overlay/local/lib/python3.10/dist-packages/cffi/api.py'.  When we import the top-level '_cffi_backend' extension module, we get version 1.15.0, located in '/usr/lib/python3/dist-packages/_cffi_backend.cpython-310-x86_64-linux-gnu.so'.  The two versions should be equal; check your installation.
Running:
python3 -m pip install --user cffi==1.15.1
did not help. Bibliography:
From a clean virtualenv, it appears to move further, and then fails at:
Building wheel for cmsis-pack-manager (pyproject.toml) ... error
error: [Errno 2] No such file or directory: 'cargo'
So we install Rust and try again, OMG:
sudo snap install rustup
rustup default stable
which at the time of writing was rustc 1.64.0, and then OMG, it worked!! We have the yt command.
However, it is still broken, e.g.:
git clone https://github.com/lancaster-university/microbit-samples
cd microbit-samples
git checkout 285f9acfb54fce2381339164b6fe5c1a7ebd39d5
cp source/examples/invaders/* source
yt clean
yt build
blows up:
annot import name 'soft_unicode' from 'markupsafe'
bibliography:
WhatsApp Updated 2025-07-16
Video 1.
WhatsApp founder Jan Koum talks about their Journey by Roots (2017)
Source. Good talk, explains how everything happened in the perfect location at the perfect time: unemployed people who knew how to code, bought an iPhone, the next big platform, at its very beginning, they had just release the required push notifications API, and he travelled a lot and knew how much SMS sucked, especially international.
Douhua Updated 2025-07-16
Freshly made douhua is a blessing.
Marketing Updated 2025-07-16

There are unlisted articles, also show them or only show them.