This post was originally published in the Wikimedia Tech blog, authored by
Arturo Borrero Gonzalez.
NFS is a central piece of infrastructure that is essential to services like Toolforge.
Recently, the Cloud Services team at Wikimedia had been reviewing how we do NFS.
The current situation
NFS is a central piece of technology for some of the services that the
Wikimedia Cloud Services team offers to the community. We have several shares that power
different use cases: Toolforge user home directories live on NFS, and
Cloud VPS users can also access dumps using this protocol. The current setup involves
several physical hardware servers, with about 20TB of storage, offering shares over 10G links to
the cloud. For the system to be more fault-tolerant, we duplicate each share for redundancy using
DRBD.
Running NFS on dedicated hardware servers has traditionally offered us advantages: mostly on the
performance and the capacity fields.
As time has passed, we have been enumerating more and more reasons to review how we do NFS. For
one, the current setup is in violation of some of our internal rules regarding realm separation.
Additionally, we had been longing for additional flexibility managing our servers: we wanted to use
virtual machines managed by Openstack Nova. The DRBD-based high-availability system
required mostly a hand-crafted procedure for failover/failback. There s also some scalability
concerns as NFS is easy to grow up, but not to grow horizontally, and of course, we have to be able
to keep the tenancy setup while doing so, something that NFS does by using LDAP/Unix users and may
get complicated too when growing. In general, the servers have become too big to fail , clearly
technical debt, and it has taken us years to decide on taking on the task to rethink the
architecture. It s worth mentioning that in an ideal world, we wouldn t depend on NFS, but the
truth is that it will still be a central piece of infrastructure for years to come in services like
Toolforge.
Over a series of brainstorming meetings, the WMCS team evaluated the situation and sorted out the
many moving parts. The team managed to boil down the potential service future to two competing
options:
Adopt and introduce a new Openstack component into our cloud: Manila this was the right choice
if we were interested in a general NFS as a service offering for our Cloud VPS users.
Put the data on Cinder volumes and serve NFS from a couple of virtual machines created by hand
this was the right choice if we wanted something that required low effort to engineer and adopt.
Then we decided to research both options in parallel. For a number of reasons, the evaluation was
timeboxed to three weeks. Both ideas had a couple of points in common: the NFS data would be stored
on our Ceph farm via Cinder volumes, and we would rely on Ceph reliability to avoid using DRBD.
Another open topic was how to back up data from Ceph, to store our important bits in more than one
basket. We will get to the back up topic later.
The manila experiment
The Wikimedia Foundation was an early adopter of some Openstack components (Nova,
Glance, Designate, Horizon), but Manila was never
evaluated for usage until now. Our approach for this experiment was to closely follow the upstream
guidelines. We read the documentation and tried to understand the different setups you can build
with Manila. As we often feel with other Openstack components, the documentation doesn t perfectly
describe how to introduce a given component in your particular local setup. Here we use an
admin-controller flat-topology Neutron network. This network is shared by all tenants (or projects)
in our Openstack deployment. Also, Manila can use many different driver backends, for
things like NetApps or CephFS that we don t use , yet. After some research, the
generic driver was the one that seemed to better fit our use case. The generic driver
leverages Nova virtual machines instances plus Cinder volume to create and manage the shares. In
general, Manila supports two operational modes, whether it should create/destroy the share servers
(i.e, the virtual machine instances) or not. This option is called driver_handles_share_server (or
DHSS) and takes a boolean value.
We were interested in trying with DHSS=true, to really benefit from the potential of the setup.
NFS idea 6, original image in Wikitech
So, after sorting all these variables, we moved on with our initial testing. We built a PoC setup
as depicted in the diagram above, with the manila-share component running in a virtual machine
inside the cloud. The PoC led to us reporting several bugs upstream:
It s worth mentioning that the upstream community was extra-welcoming to us, and we re thankful for
that. However, at the end of our three-week period, our Manila setup still wasn t working as
expected. Your experience may change with other drivers perhaps the ZFSonLinux or the CephFS ones.
In general, we were having trouble making the setup work as expected, so we decided to abandon this
approach in favor of the other option we were considering at the beginning.
Simple virtual machine serving NFS
The alternative was to create a Nova virtual machine instance by hand and to configure it using
puppet. We have been investing in an automation framework lately, so the idea is to
not actually create the server by hand. Anyway, the data would be decoupled from the instance into
Cinder volumes, which led us to the question we left for later: How should we back up those
terabytes of important information? Just to be clear, the backup problem was independent of the above
options; with Manila we would still have had to solve the same challenge. We would like to see our
data be backed up somewhere else other than in Ceph. And that s exactly where we are at right now.
We ve been exploring different backup strategies and will finally use the Cinder backup
API.
Conclusion
The iteration will end with the dedicated NFS hardware servers being stopped, and the shares being
served from within the cloud. The migration will take some time to happen because we will check and
double-check that everything works as expected (including from the performance point of view)
before making definitive changes. We already have some plans to make sure our users experience as
little service impact as possible. The most troublesome shares will be those related to Toolforge.
At some point we will need to disallow writes to the NFS share, rsync the data out of the hardware
servers into the Cinder volumes, point the NFS clients to the new virtual machines, and then enable
writes again. The main Toolforge share has about 8TB of data, so this will take a while.
We will have more updates in the future. Who knows, perhaps our next-next iteration, in a couple of
years, will see us adopting Openstack Manila for good.
Featured image credit: File:(from break water) Manila Skyline panoramio.jpg, ewol, CC BY-SA 3.0This post was originally published in the Wikimedia Tech blog, authored
by Arturo Borrero Gonzalez.
Active noise cancellation (ANC) has been all the rage lately in the headphones
and in-ear monitors market. It seems after Apple got heavily praised for their
AirPods Pro, every somewhat serious electronics manufacturer released their
own design incorporating this technology.
The first headphones with ANC I remember trying on (in the early 2010s) were
the Bose QuietComfort 15. Although the concept did work (they indeed cancelled
some sounds), they weren't amazing and did a great job of convincing me ANC
was some weird fad for people who flew often.
As the years passed, chip size decreased, battery capacity improved and machine
learning blossomed truly a perfect storm for the wireless ANC headphones
market. I had mostly stayed a sceptic of this tech until recently a kind friend
offered to let me try a pair of Sony WH-1000X M3.
Having tested them thoroughly, I have to say I'm really tempted to buy them
from him, as they truly are fantastic headphones1. They are
very light, comfortable, work without a proprietary app and sound very good
with the ANC on2 if a little bass-heavy for my taste3.
The ANC itself is truly astounding and is leaps and bounds beyond what was
available five years ago. It still isn't perfect and doesn't cancel ALL sounds,
but transforms the low hum of the subway I find myself sitting in too often
these days into a light *swoosh*. When you turn the ANC on, HVAC simply
disappears. Most impressive to me is the way they completely cancel the dreaded
sound of your footsteps resonating in your headphones when you walk with them.
I won't be keeping them though.
Whilst I really like what Sony has achieved here, I've grown to understand ANC
simply isn't for me. Some of the drawbacks of ANC somewhat bother me: the ear
pressure it creates is tolerable, but is an additional energy drain over long
periods of time and eventually gives me headaches. I've also found ANC
accentuates the motion sickness I suffer from, probably because it messes up
with some part of the inner ear balance system.
Most of all, I found that it didn't provide noticeable improvements over good
passive noise cancellation solutions, at least in terms of how high I have to
turn the volume up to hear music or podcasts clearly. The human brain works in
mysterious ways and it seems ANC cancelling a class of noises (low hums,
constant noises, etc.) makes other noises so much more noticeable. People
talking or bursty high pitched noises bothered me much more with ANC on than
without.
So for now, I'll keep using my trusty Senheiser HD 280 Pro4 at work
and good in-ear monitors with Comply foam tips on the go.
This blog post certainly doesn't aim to be a comprehensive
review of these headphones. See Zeos' review if you want something
more in-depth.
As most ANC headphones, they don't sound as good when used
passively through the 3.5mm port, but that's just a testament of how a great
job Sony did of tuning the DSP.
Easily fixed using an EQ.
Retrofitted with aftermarket sheepskin earpads, they provide more
than 32db of passive noise reduction.
JMP offers VoIP calling via XMPP, but it's also
possibly to use the VoIP using SIP.
The underlying VoIP calling functionality in JMP is provided by
Bandwidth, but their old Asterisk
instructions
didn't quite work for me. Here's how I set it up in my Asterisk server.
Get your SIP credentials
After signing up for JMP and setting it up in your favourite XMPP client,
send the following message to the cheogram.com gateway contact:
reset sip account
In response, you will receive a message containing:
a numerical username
a password (e.g. three lowercase words separated by spaces)
Add SIP account to your Asterisk config
First of all, I added the following near the top of my
/etc/asterisk/sip.conf:
Note that you can have more than one register line in your config if you
use more than one SIP provider, but you must register with the server
whether you want to receive incoming calls or not.
Then I added a new blurb to the bottom of the same file:
I checked that the registration was successful by running asterisk -r and
then typing:
sip set debug on
before reloading the configuration using:
reload
Create Asterisk extensions to send and receive calls
Once I got registration to work, I hooked this up with my other extensions
so that I could send and receive calls using my JMP number.
In /etc/asterisk/extensions.conf, I added the following:
[from-jmp]
include => home
exten => s,1,Goto(1000,1)
where home is the context which includes my local SIP devices and 1000
is the extension I want to ring.
Then I added the following to enable calls to any destination within the
North American Numbering Plan:
Here 5551231234 is my JMP phone number, not my bwsip numerical username.
For reference, here's the rest of my dialplan in /etc/asterisk/extensions.conf:
Firewall
Finally, I opened a few ports in my firewall by putting the following in
/etc/network/iptables.up.rules:
# SIP and RTP on UDP (jmp.cbcbc7.auth.bandwidth.com)
-A INPUT -s 67.231.2.13/32 -p udp --dport 5008 -j ACCEPT
-A INPUT -s 216.82.238.135/32 -p udp --dport 5008 -j ACCEPT
-A INPUT -s 67.231.2.13/32 -p udp --sport 5004:5005 --dport 10001:20000 -j ACCEPT
-A INPUT -s 216.82.238.135/32 -p udp --sport 5004:5005 --dport 10001:20000 -j ACCEPT
Outbound calls not working
While the above setup works for me for inbound calls, it doesn't currently
work for outbound calls.
The hostname currently resolves to one of two IP addresses:
My home automation setup has been fairly static recently; it does what we need and generally works fine. One area I think could be better is controlling it; we have access Home Assistant on our phones, and the Alexa downstairs can control things, but there are no smart assistants upstairs and sometimes it would be nice to just push a button to turn on the light rather than having to get my phone out. Thanks to the fact the UK generally doesn t have neutral wire in wall switches that means looking at something battery powered. Which means wifi based devices are a poor choice, and it s necessary to look at something lower power like Zigbee or Z-Wave.
Zigbee seems like the better choice; it s a more open standard and there are generally more devices easily available from what I ve seen (e.g. Philips Hue and IKEA TR DFRI). So I bought a couple of Xiaomi Mi Smart Home Wireless Switches, and a CC2530 module and then ignored it for the best part of a year. Finally I got around to flashing the Z-Stack firmware that Koen Kanters kindly provides. (Insert rant about hardware manufacturers that require pay-for tool chains. The CC2530 is even worse because it s 8051 based, so SDCC should be able to compile for it, but the TI Zigbee libraries are only available in a format suitable for IAR s embedded workbench.)
Flashing the CC2530 is a bit of faff. I ended up using the CCLib fork by Stephan Hadinger which supports the ESP8266. The nice thing about the CC2530 module is it has 2.54mm pitch pins so nice and easy to jumper up. It then needs a USB/serial dongle to connect it up to a suitable machine, where I ran Zigbee2MQTT. This scares me a bit, because it s a bunch of node.js pulling in a chunk of stuff off npm. On the flip side, it Just Works and I was able to pair the Xiaomi button with the device and see MQTT messages that I could then use with Home Assistant. So of course I tore down that setup and went and ordered a CC2531 (the variant with USB as part of the chip). The idea here was my test setup was upstairs with my laptop, and I wanted something hooked up in a more permanent fashion.
Once the CC2531 arrived I got distracted writing support for the Desk Viking to support CCLib (and modified it a bit for Python3 and some speed ups). I flashed the dongle up with the Z-Stack Home 1.2 (default) firmware, and plugged it into the house server. At this point I more closely investigated what Home Assistant had to offer in terms of Zigbee integration. It turns out the ZHA integration has support for the ZNP protocol that the TI devices speak (I m reasonably sure it didn t when I first looked some time ago), so that seemed like a better option than adding the MQTT layer in the middle.
I hit some complexity passing the dongle (which turns up as /dev/ttyACM0) through to the Home Assistant container. First I needed an override file in /etc/systemd/nspawn/hass.nspawn:
(I m not clear why the VirtualEthernet needed to exist; without it networking broke entirely but I couldn t see why it worked with no override file.)
A udev rule on the host to change the ownership of the device file so the root user and dialout group in the container could see it was also necessary, so into /etc/udev/rules.d/70-persistent-serial.rules went:
In the container itself I had to switch PrivateDevices=true to PrivateDevices=false in the home-assistant.service file (which took me a while to figure out; yay for locking things down and then needing to use those locked down things).
Finally I added the hass user to the dialout group. At that point I was able to go and add the integration with Home Assistant, and add the button as a new device. Excellent. I did find I needed a newer version of Home Assistant to get support for the button, however. I was still on 2021.1.5 due to upstream dropping support for Python 3.7 and not being prepared to upgrade to Debian 11 until it was actually released, so the version of zha-quirks didn t have the correct info. Upgrading to Home Assistant 2021.8.7 sorted that out.
There was another slight problem. Range. Really I want to use the button upstairs. The server is downstairs, and most of my internal walls are brick. The solution turned out to be a TR DFRI socket, which replaced the existing ESP8266 wifi socket controlling the stair lights. That was close enough to the server to have a decent signal, and it acts as a Zigbee router so provides a strong enough signal for devices upstairs. The normal approach seems to be to have a lot of Zigbee light bulbs, but I have mostly kept overhead lights as uncontrolled - we don t use them day to day and it provides a nice fallback if the home automation has issues.
Of course installing Zigbee for a single button would seem to be a bit pointless. So I ordered up a Sonoff door sensor to put on the front door (much smaller than expected - those white boxes on the door are it in the picture above). And I have a 4 gang wireless switch ordered to go on the landing wall upstairs.
Now I ve got a Zigbee setup there are a few more things I m thinking of adding, where wifi isn t an option due to the need for battery operation (monitoring the external gas meter springs to mind). The CC2530 probably isn t suitable for my needs, as I ll need to write some custom code to handle the bits I want, but there do seem to be some ARM based devices which might well prove suitable
The diffoscope maintainers are pleased to announce the release of diffoscope
version 184. This version includes the following changes:
[ Chris Lamb ]
* Fix the semantic comparison of R's .rdb files after a refactoring of
temporary directory handling in a previous version.
* Support a newer format version of R's .rds files.
* Update tests for OCaml 4.12. (Closes: reproducible-builds/diffoscope#274)
* Move diffoscope.versions to diffoscope.tests.utils.versions.
* Use assert_diff in tests/comparators/test_rdata.py.
* Reformat various modules with Black.
[ Zbigniew J drzejewski-Szmek ]
* Stop using the deprecated distutils module by adding a version
comparison class based on the RPM version rules.
* Update invocations of llvm-objdump for the latest version of LLVM.
* Adjust a test with one-byte text file for file(1) version 5.40.
* Improve the parsing of the version of OpenSSH.
[ Benjamin Peterson ]
* Add a --diff-context option to control the unified diff context size.
(reproducible-builds/diffoscope!88)
Colson Whitehead's latest novel, Harlem Shuffle, was always going to be widely reviewed, if only because his last two books won Pulitzer prizes. Still, after enjoying both The Underground Railroad and The Nickel Boys, I was certainly going to read his next book, regardless of what the critics were saying indeed, it was actually quite agreeable to float above the manufactured energy of the book's launch.
Saying that, I was encouraged to listen to an interview with the author by Ezra Klein. Now I had heard Whitehead speak once before when he accepted the Orwell Prize in 2020, and once again he came across as a pretty down-to-earth guy. Or if I were to emulate the detached and cynical tone Whitehead embodied in The Nickel Boys, after winning so many literary prizes in the past few years, he has clearly rehearsed how to respond to the cliched questions authors must be asked in every interview. With the obligatory throat-clearing of 'so, how did you get into writing?', for instance, Whitehead replies with his part of the catechism that 'It seemed like being a writer could be a cool job. You could work from home and not talk to people.' The response is the right combination of cute and self-effacing... and with its slight tone-deafness towards enforced isolation, it was no doubt honed before Covid-19.
Harlem Shuffle tells three separate stories about Ray Carney, a furniture salesman and 'fence' for stolen goods in New York in the 1960s. Carney doesn't consider himself a genuine criminal though, and there's a certain logic to his relativistic morality. After all, everyone in New York City is on the take in some way, and if some 'lightly used items' in Carney's shop happened to have had 'previous owners', well, that's not quite his problem. 'Nothing solid in the city but the bedrock,' as one character dryly observes. Yet as Ezra pounces on in his NYT interview mentioned abov, the focus on the Harlem underworld means there are very few women in the book, and Whitehead's circular response ah well, it's a book about the criminals at that time! was a little unsatisfying. Not only did it feel uncharacteristically slippery of someone justly lauded for his unflinching power of observation (after all, it was the author who decided what to write about in the first place), it foreclosed on the opportunity to delve into why the heist and caper genres (from The Killing, The Feather Thief, Ocean's 11, etc.) have historically been a 'male' mode of storytelling.
Perhaps knowing this to be the case, the conversation quickly steered towards Ray Carney's wife, Elizabeth, the only woman in the book who could be said possesses some plausible interiority. The following off-hand remark from Whitehead caught my attention:
My wife is convinced that [Elizabeth] knows everything about Carney's criminal life, and is sort of giving him a pass. And I'm not sure if that's true. I have to have to figure out exactly what she knows and when she knows it and how she feels about it.
I was quite taken by this, although not simply due to its effect on the story it self. As in, it immediately conjured up a charming picture of Whitehead's domestic arrangements: not only does Whitehead's wife feel free to disagree with what one of Whitehead's 'own' characters knows or believes, but that Colson has no problem whatsoever sharing that disagreement with the public at large. (It feels somehow natural that Whitehead's wife believes her counterpart knows more than she lets on, whilst Whitehead himself imbues the protagonist's wife with a kind of neo-Victorian innocence.) I'm minded to agree with Whitehead's partner myself, if only due to the passages where Elizabeth is studiously ignoring Carney's otherwise unexplained freak-outs.
But all of these meta-thoughts simply underline just how emancipatory the Death of the Author can be. This product of academic literary criticism (the term was coined by Roland Barthes' 1967 essay of the same name) holds that the original author's intentions, ideas or biographical background carry no especial weight in determining how others should interpret their work. It is usually understood as meaning that a writer's own views are no more valid or 'correct' than the views held by someone else. (As an aside, I've found that most readers who encounter this concept for the first time have been reading books in this way since they were young. But the opposite is invariably true with cinephiles, who often have a bizarre obsession with researching or deciphering the 'true' interpretation of a film.) And with all that in mind, can you think of a more wry example of how freeing (and fun) nature of the Death of the Author than an author's own partner dissenting with their (Pulitzer Prize-winning) husband on the position of a lynchpin character?
The 1964 Harlem riot began after James Powell, a 15-year-old African American, was shot and killed by Thomas Gilligan, an NYPD police officer in front of 10s of witnesses. Gilligan was subsequently cleared by a grand jury.
As it turns out, the reviews for Harlem Shuffle have been almost universally positive, and after reading it in the two days after its release, I would certainly agree it is an above-average book. But it didn't quite take hold of me in the way that The Underground Railroad or The Nickel Boys did, especially the later chapters of The Nickel Boys that were set in contemporary New York and could thus make some (admittedly fairly explicit) connections from the 1960s to the present day that kind of connection is not there in Harlem Shuffle, or at least I did not pick up on it during my reading.
I can see why one might take exception to that, though. For instance, it is certainly true that the week-long Harlem Riot forms a significant part of the plot, and some events in particular are entirely contingent on the ramifications of this momentous event. But it's difficult to argue the riot's impact are truly integral to the story, so not only is this uprising against police brutality almost regarded as a background event, any contemporary allusion to the murder of George Floyd is subsequently watered down. It's nowhere near the historical rubbernecking of Forrest Gump (1994), of course, but that's not a battle you should ever be fighting.
Indeed, whilst a certain smoothness of affect is to be priced into the Whitehead reading experience, my initial overall reaction to Harlem Shuffle was fairly flat, despite all the action and intrigue on the page. The book perhaps belies its origins as a work conceived during quarantine after all, the book is essentially comprised of three loosely connected novellas, almost as if the unreality and mental turbulence of lockdown prevented the author from performing the psychological 'deep work' of producing a novel-length text with his usual depth of craft. A few other elements chimed with this being a 'lockdown novel' as well, particularly the book's preoccupation with the sheer physicality of the city compared to the usual complex interplay between its architecture and its inhabitants. This felt like it had been directly absorbed into the book from the author walking around his deserted city, and thus being able to take in details for the first time:
The doorways were entrances into different cities no, different entrances into one vast, secret city. Ever close, adjacent to all you know, just underneath. If you know where to look.
And I can't fail to mention that you can almost touch Whitehead's sublimated hunger to eat out again as well:
Stickups were chops they cook fast and hot, you re in and out. A stakeout was ribs fire down low, slow, taking your time.
[ ]
Sometimes when Carney jumped into the Hudson when he was a kid, some of that stuff got into his mouth. The Big Apple Diner served it up and called it coffee.
More seriously, however, the relatively thin personalities of minor characters then reminded me of the simulacrum of Zoom-based relationships, and the essentially unsatisfactory endings to the novellas felt reminiscent of lockdown pseudo-events that simply fizzle out without a bang. One of the stories ties up loose ends with: 'These things were usually enough to terminate a mob war, and they appeared to end the hostilities in this case as well.' They did? Well, okay, I guess.
The corner of 125th Street and Morningside Avenue in 2019, the purported location of Carney's fictional furniture store. Signage plays a prominent role in Harlem Shuffle, possibly due to the author's quarantine walks.
Still, it would be unfair to characterise myself as 'disappointed' with the novel, and none of this piece should be taken as really deep criticism. The book certainly was entertaining enough, and pretty funny in places as well:
Carney didn t have an etiquette book in front of him, but he was sure it was bad manners to sit on a man s safe.
[ ]
The manager of the laundromat was a scrawny man in a saggy undershirt painted with sweat stains. Launderer, heal thyself.
Yet I can't shake the feeling that every book you write is a book that you don't, and so we might need to hold out a little longer for Whitehead's 'George Floyd novel'. (Although it is for others to say how much of this sentiment is the expectations of a White Reader for The Black Author to ventriloquise the pain of 'their' community.)
Some room for personal critique is surely permitted. I dearly missed the junk food energy of the dry and acerbic observations that run through Whitehead's previous work. At one point he had a good line on the model tokenisation that lurks behind 'The First Negro to...' labels, but the callbacks to this idea ceased without any payoff. Similar things happened with the not-so-subtle critiques of the American Dream:
Entrepreneur? Pepper said the last part like manure. That s just a
hustler who pays taxes.
[ ]
One thing I ve learned in my job is that life is cheap, and when things start getting expensive, it gets cheaper still.
Ultimately, though, I think I just wanted more. I wanted a deeper exploration of how the real power in New York is not wielded by individual street hoodlums or even the cops but in the form of real estate, essentially serving as a synecdoche for Capital as a whole. (A recent take of this can be felt in Jed Rothstein's 2021 documentary, WeWork: Or the Making and Breaking of a $47 Billion Unicorn and it is perhaps pertinent to remember that the US President at the time this novel was written was affecting to be a real estate tycoon.). Indeed, just like the concluding scenes of J. J. Connolly's Layer Cake, although you can certainly pull off a cool heist against the Man, power ultimately resides in those who control the means of production... and a homespun furniture salesman on the corner of 125 & Morningside just ain't that. There are some nods to kind of analysis in the conclusion of the final story ('Their heist unwound as if it had never happened, and Van Wyck kept throwing up buildings.'), but, again, I would have simply liked more.
And when I attempted then file this book away into the broader media landscape, given the current cultural visibility of 1960s pop culture (e.g. One Night in Miami (2020), Judas and the Black Messiah (2021), Summer of Soul (2021), etc.), Harlem Shuffle also seemed like a missed opportunity to critically analyse our (highly-qualified) longing for the civil rights era. I can certainly understand why we might look fondly on the cultural products from a period when politics was less alienated, when society was less atomised, and when it was still possible to imagine meaningful change, but in this dimension at least, Harlem Shuffle seems to merely contribute to this nostalgic escapism.
This is the fifth and final post in a series about the interface description language Candid.
If you made it this far, you now have a good understanding of what Candid is, what it is for and how it is used. For this final post, I ll put the spotlight on specific aspects of Candid that are maybe surprising, or odd, or quirky. This section will be quite opinionated, and could maybe be called what I d do differently if I d re-do the whole thing .
Note that these quirks are not serious problems, and they don t invalidate the overall design. I am writing this up not to discourage the use of Candid, but merely help interested parties to understand it better.
References in the wire format
When the work on Candid began at DFINITY, the Internet Computer was still far away from being a thing, and many fundamental aspects about it were still in the air. I particular, there was still talk about embracing capabilities as a core feature of the application model, which would be implemented as opaque references on the system level, likely building on WebAssembly s host reference type proposal (which only landed recently), and could be used to model access permissions, custom tokens and many other things.
So Candid is designed with that in mind, and you ll find that its wire format is not just a type table and a value table, but actually
a triple (T, M, R), where T ( type ) and M ( memory ) are sequences of bytes and R ( references ) is a sequence of references.
Also the wire format for values of function service tyeps have an extra byte to distinguish between public references (represented by a principal and possible a method name in the data part), and these opaque references.
Alas, references never made it into the Internet Computer, so all Candid implementations simply ignore that part of the specification. But it s still in the spec, and if it confused you before, now you know why.
Hashed field names
Candid record and variant types look like they have textual field names:
type T = record syndactyle : nat; trustbuster: bool
But that is actually only true superficially. The wire format for Candid only stores hashes of field names. So the above is actually equivalent to
type T = record 4260381820 : nat; 3504418361 : bool
or, for that matter, to
type T = record destroys : bool; rectum : nat
(Yes, I used an english word list to find these hash collisions. There aren t that many actually.)
The benefit of such hashing is that the messages are a bit smaller in most (not all) cases, but it is a big annoyance for dynamic uses of Candid. It s the reason why tools like dfx, if they don t know the Candid interface of a service, will print the result with just the numerical hash, letting you guess which field is which.
It also complicates host languages that derive Candid types from the host language, like Motoko, as some records (e.g. record trustbuster: bool; destroys : int ) with field name hash collisions can not be represented in Candid, and either the host language s type system needs to be Candid aware now (as is the case of Motoko), or serialization/deserialization will fail at runtime, or odd bugs can happen.
(More discussion of this issue).
Tuples
Many languages have a built-in notion of a tuple type (e.g. (Int, Bool)), but Candid does not have such a type. The only first class product type is records.
This means that tuples have to encoded as records somehow. Conveniently(?) record fields are just numbers after all, so the type (Int, Bool) would be mapped to the type
record 0 : int; 1 : bool
So tuples can be expressed. But from my experience implementing the type mappings for Motoko and Haskell this is causing headaches. To get a good experience when importing from Candid, the tools have to try to reconstruct which records may have been tuples originally, and turn them into tuples.
The main argument for the status quo is that Candid types should be canonical, and there should not be more than one product type, and records are fine, and there needs to be no anonymous product type. But that has never quite resonated with me, given the practical reality of tuple types in many host languages.
Argument sequences
Did I say that Candid does not have tuple types? Turns out it does, sort of. There is no first class anonymous product, but since functions take sequences of arguments and results, there is a tuple type right there:
func foo : (bool, int) -> (int, bool)
Again, I found that ergonomic interaction with host languages becomes relatively unwieldy by requiring functions to take and return sequences of values. This is especially true for languages where functions take one argument value or return one result type (the latter being very common). Here, return sequences of length one are turned into that type directly, longer argument sequences turn into the host language s tuple type, and nullary argument sequences turn into the idiomatic unit type. But this means that the types (int, bool) -> () and (record 0: int, 1: bool ) -> () may be mapped to the same host language type, which causes problems when you hope to encode all necessary Candid type information in the host language.
Another oddity with argument and result sequences is that you can give names to the entries, e.g. write
without breaking clients, this does not have the effect you think it has and will likely break.
My suggestion is to never put names on function arguments and result values in Candid interfaces, and for anything that might be extended with new fields or where you want to name the arguments, use a single record type as the only argument:
This allows you to add and remove arguments more easily and reliably.
Type shorthands
The Candid specification defines a system of types, and then adds a number of syntactic short-hands . For example, if you write blob in a Candid type description, it ought to means the same as vec nat8.
My qualm with that is that it doesn t always mean the same. A Candid type description is interpreted by a number of, say, consumers . Two such consumers are part of the Candid specification:
The specification that defines the wire format for that type
The upgrading (subtyping) rules
But there are more! For every host language, there is some mapping from Candid types to host language types, and also generic tools like Candid UI are consumers of the type algebra. If these were to take the Candid specification as gospel, they would be forced to treat blob and vec nat8 the same, but that would be quite unergonomic and might cause performance regressions (most language try to map blob to some compact binary data type, while vec t tends to turn into some form of array structure).
So they need to be pragmatic and treat blob and vec nat8 differently. But then, for all practical purposes, blob is not just a short-hand of vec nat8. They are different types that just happens to have the same wire representations and subtyping relations.
This affects not just blob, but also tuples (record blob; int; bool ) and field names , as discussed above.
The value text format
For a while after defining Candid, the only implementation was in Motoko, and all the plumbing was automatic, so there was never a need for users to to explicitly handle Candid values, as all values were Motoko values. Still, for debugging and testing and such things, we eventually needed a way to print out Candid values, so the text format was defined ( To enable convenient debugging, the following grammar specifies a text format for values ).
But soon the dfx tool learned to talk to canisters, and now users needed to enter Candid value on the command line, possibly even when talking to canisters for which the interface was not known to dfx. And, sure enough, the textual interface defined in the Candid spec was used.
Unfortunately, since it was not designed for that use case, it is rather unwieldy:
It is quite verbose. You have to write record , not just . Vectors are written vec ; instead of some conventional syntax like [ , ]. Variants are written as variant error = " " with braces that don t any value here, and something like #error " " might have worked as well.
With a bit more care, a more concise and ergonomic syntax might have been possible.
It wasn t designed to be sufficient to create a Candid value from it. If you write 5 it s unclear whether that s a nat or an int16 or what (and all of these have different wire representations). Type annotations were later added, but are relatively unwieldy, and don t cover all cases (e.g. a service reference with a recursive type cannot be represented in the textual format at the moment).
Not really the fault of the textual format, but some useful information about the types is not reflected in the type description that s part of the wire format. In particular not the field names, and whether a value was intended to be binary data (blob) or a list of small numbers (vec nat8), so pretty-printing such values requires guesswork. The Haskell library even tries to brute-force the hash to guess the field name, if it is short or in a english word list!
In hindsight I think it was too optimistic to assume that correct static type information is always available, and instead of actively trying to discourage dynamic use, Candid might be better if we had taken these (unavoidable?) use cases into account.
Custom wire format
At the beginning of this post, I have a Candid is list. The list is relatively long, and the actual wire format is just one bullet point. Yes, defining a wire format that works isn t rocket science, and it was easiest to just make one up. But since most of the interesting meat of Candid is in other aspects (subtyping rules, host language integration), I wonder if it would have been better to use an existing, generic wire format, such as CBOR, and build Candid as a layer on top.
This would give us plenty of tools and libraries to begin with. And maybe it would have reduced barrier of entry for developers, which now led to the very strange situation that DFINITY advocates for the universal use of Candid on the Internet Computer, so that all services can smoothly interact, but two of the most important services on the Internet Computer (the registry and the ledger) use Protobuf as their primary interface format, with Candid interfaces missing or an afterthought.
Sideways Interface Evolution
This is not a quirk of Candid itself, but rather an idiom of how you can use Candid that emerged from our solution for record extensions and upgrades.
Consider our example from before, a service with interface
service add_user : (record login : text; name : text ) -> ()
where you want to add an age field, which should be a number.
The official way of doing that is to add that field with an optional type:
service add_user : (record login : text; name : text; age : opt nat ) -> ()
As explained above, this will not break old clients, as the decoder will treat a missing argument as null. So far so good.
But often when adding such a field you don t want to bother new clients with the fact that this age was, at some point in the past, not there yet. And you can do that! The trick is to distinguish between the interface you publish and the interface you implement. You can (for example in your documentation) state that the interface is
service add_user : (record login : text; name : text; age : nat ) -> ()
which is not a subtype of the old type, but it is the interface you want new clients to work with. And then your implementation uses the type with opt nat. Calls from old clients will come through as null, and calls from new clients will come through as opt 42.
We can see this idiom used in the Management Canister of the Internet Computer. The current documented interface only mentions a controllers : vec principal field in the settings, but the implementation still can handle both the old controller : principal and the new controllers field.
It s probably advisable to let your CI system check that new versions of your service continue to implement all published interfaces, including past interfaces. But as long as the actual implementation s interface is a subtype of all interfaces ever published, this works fine.
This pattern is related to when your service implements, say, http_request (so its implemented interface is a subtype of that common interface), but does not include that method in the published documentation (because clients of your service don t need to call it).
Self-describing Services
As you have noticed, Candid was very much designed assuming that all parties always have the service type of services they want to interact with. But the Candid specification does not define how one can obtain the interface of a given service, and there isn t really a an official way to do that on the Internet Computer.
That is unfortunate, because many interesting features depend on that: Such as writing import C "ic:7e6iv-biaaa-aaaaf-aaada-cai" in your Motoko program, and having it s type right there. Or tools like ic.rocks, that allow you to interact with any canister right there.
One reason why we don t really have that feature yet is because of disagreements about how dynamic that feature should be. Should you be able to just ask the canister for its interface (and allow the canister to vary the response, for example if it can change its functionality over time, even without changing the actual wasm code)? Or is the interface a static property of the code, and one should be able to query the system for that data, without the canister s active involvement. Or, completely different, should interfaces be distributed out of band, maybe together with API documentation, or in some canister registry somewhere else?
I always leaned towards the first of these options, but not convincingly enough. The second options requires system assistance, so more components to change, more teams to be involved that maybe intrinsically don t care a lot about this feature. And the third might have emerged as the community matures and builds such infrastructure, but that did not happen yet.
In the end I sneaked in an implementation of the first into Motoko, arguing that even if we don t know yet how this feature will be implemented eventually, we all want the feature to exist somehow, and we really really want to unblock all the interesting applications it enables (e.g. Candid UI). That s why every Motoko canister, and some rust canisters too, implements a method
__get_candid_interface_tmp_hack : () -> (text)
that one can use to get the Candid interface file.
The name was chosen to signal that this may not be the final interface, but like all good provisional solutions, it may last longer than intended. If that s the case, I m not sorry.
This concludes my blog post series about Candid, for now. If you want to know more, feel free to post your question on the DFINTY developer forum, and I ll probably answer.
The Glasgow Haskell Compiler (GHC) has support for user-supplied rewrite rules,
which applied during one of the compiler optimisation stages. An example rule is
-# RULES
"streamFilter fuse" forall f g xs.
streamFilter f (streamFilter g xs) = streamFilter (f.g) xs
#-
I spent some time today looking at these more closely.
In order for rewrite rules to be applied, optimisation needs to be enabled. This
conflicts with interactive use of GHC, so you can't explore these things in GHCi.
I think rewrite rules are enabled by default (with optimisation), but you can ask
for them explicitly. When investigating these it's also useful to ask ghc to
always recompile, otherwise you have to change the source or manually remove .hi
or .o files (etc.) between invocations.
A starting set of command-line options to use then, are
-O -fenable-rewrite-rules -fforce-recomp
GHC runs several compilation stages, and the source program is transformed into
several different languages or language dialects as it goes. Before the phase
where rewrite rules are applied, some other optimisations take place, and the
source gets desugared. You can see the results of the desugaring by passing the
argument -ddump-ds. Here's an example program
main = print (unStream (streamFilter (>3) (streamFilter (<10)
(mkStream [0..20]))))
And here's what it looks like after the first pass optimisation and desugaring:
(Note: I used -dsuppress-all and -dsuppress-uniques to improve the clarity
of the above output. See Suppressing unwanted
information for further details).
Those short-hand sections ((<3)) in the input program are expanded to
something quite a lot longer. Out of curiosity I tried it again with plain
lambdas, not sections, and the result was smaller
main
= print
($fShow[] $fShowInteger)
(unStream
(streamFilter
(\ x -> > $fOrdInteger x 3)
(streamFilter
(\ x -> < $fOrdInteger x 10)
(mkStream (enumFromTo $fEnumInteger 0 20)))))
Rewrite rules happen after this. Once they're done (and several other passes),
the program is translated into an intermediate representation called Tiny
Core. This language
faintly resembles the input Haskell. GHC will output the Tiny Core program
if you supply the argument -ddump-simpl. Here's (most) of the program in Tiny
Core (I've substituted some constants for clarity):
main = hPutStr' stdout main1 True
main1 = $fShowInteger_$cshowList (catMaybes1 (main_go 0)) []
main_go
= \ x ->
case gtInteger# x 20 of
DEFAULT ->
case ltInteger# x 10 of
DEFAULT -> main_go (plusInteger x 1);
1# ->
case gtInteger# x 3 of
DEFAULT -> main_go (plusInteger x 1);
1# -> : (Just x) (main_go (plusInteger x 1))
;
1# -> []
After Tiny Core, GHC continues to translate the program into other forms
(including STG, CMM, ASM) and you can ask GHC to dump those representations too,
but this is all downstream from the rewrites so not relevant to them.
The rewrite rule at the top of this blog post is never applied: It doesn't get
a chance, because the function it operates on (streamFilter) is inlined by
GHC. GHC can detect this in some circumstances (-Winline-rule-shadowing). You
instruct GHC to report on which rules fired with -ddump-rule-firings and can
see before-and-after snippets of Tiny Core for each rule applied with
-ddump-rule-rewrites.
I played around with adding -# NOINLINE functionName #- pragmas to disable
inlining various functions to try and provoke a situation where the above rule
could match, but it was a losing battle: GHC's built-in optimisations are just
too good. But, it's also moot: the outcome I want (the filters to be fused) is
happening, it's just the built-in rewrite rules are achieving it,
once striot's functions
have been inlined away.
On Saturday 28 August 2021, the annual Debian Developers
and Contributors Conference came to a close.
DebConf21 has been held online for the second time, due to the coronavirus
(COVID-19) disease pandemic.
All of the sessions have been streamed, with a variety of ways of participating:
via IRC messaging, online collaborative text documents,
and video conferencing meeting rooms.
With 740 registered attendees from more than 15 different countries and a
total of over 70 event talks, discussion sessions,
Birds of a Feather (BoF) gatherings and other activities,
DebConf21 was a large success.
The setup made for former online events involving Jitsi, OBS,
Voctomix, SReview, nginx, Etherpad, a web-based
frontend for voctomix has been improved and used for DebConf21 successfully.
All components of the video infrastructure are free software, and configured through the
Video Team's public ansible repository.
The DebConf21 schedule included
a wide variety of events, grouped in several tracks:
Introduction to Free Software and Debian,
Packaging, policy, and Debian infrastructure,
Systems administration, automation and orchestration,
Cloud and containers,
Security,
Community, diversity, local outreach and social context,
Internationalization, Localization and Accessibility,
Embedded and Kernel,
Debian Blends and Debian derived distributions,
Debian in Arts and Science
and other.
The talks have been streamed using two rooms, and several of these activities
have been held in different languages: Telugu, Portuguese, Malayalam, Kannada,
Hindi, Marathi and English, allowing a more diverse audience to enjoy and participate.
Between talks, the video stream has been showing the usual sponsors on the loop, but also
some additional clips including photos from previous DebConfs, fun facts about Debian
and short shout-out videos sent by attendees to communicate with their Debian friends.
The Debian publicity team did the usual live coverage to encourage participation
with micronews announcing the different events. The DebConf team also provided several
mobile options to follow the schedule.
For those who were not able to participate, most of the talks and sessions are already
available through the
Debian meetings archive website,
and the remaining ones will appear in the following days.
The DebConf21 website
will remain active for archival purposes and will continue to offer
links to the presentations and videos of talks and events.
Next year, DebConf22 is planned to be held
in Prizren, Kosovo, in July 2022.
DebConf is committed to a safe and welcome environment for all participants.
During the conference, several teams (Front Desk, Welcome team and Community team)
have been available to help so participants get their best experience
in the conference, and find solutions to any issue that may arise.
See the web page about the Code of Conduct in DebConf21 website
for more details on this.
Debian thanks the commitment of numerous sponsors
to support DebConf21, particularly our Platinum Sponsors:
Lenovo,
Infomaniak,
Roche,
Amazon Web Services (AWS)
and Google.
About Debian
The Debian Project was founded in 1993 by Ian Murdock to be a truly
free community project. Since then the project has grown to be one of
the largest and most influential open source projects. Thousands of
volunteers from all over the world work together to create and
maintain Debian software. Available in 70 languages, and
supporting a huge range of computer types, Debian calls itself the
universal operating system.
About DebConf
DebConf is the Debian Project's developer conference. In addition to a
full schedule of technical, social and policy talks, DebConf provides an
opportunity for developers, contributors and other interested people to
meet in person and work together more closely. It has taken place
annually since 2000 in locations as varied as Scotland, Argentina, and
Bosnia and Herzegovina. More information about DebConf is available from
https://debconf.org/.
About Lenovo
As a global technology leader manufacturing a wide portfolio of connected products,
including smartphones, tablets, PCs and workstations as well as AR/VR devices,
smart home/office and data center solutions, Lenovo
understands how critical open systems and platforms are to a connected world.
About Infomaniak
Infomaniak is Switzerland's largest web-hosting company,
also offering backup and storage services, solutions for event organizers,
live-streaming and video on demand services.
It wholly owns its datacenters and all elements critical
to the functioning of the services and products provided by the company
(both software and hardware).
About Roche
Roche is a major international
pharmaceutical provider and research company dedicated to personalized
healthcare. More than 100.000 employees worldwide work towards solving some
of the greatest challenges for humanity using science and technology. Roche
is strongly involved in publicly funded collaborative research projects with
other industrial and academic partners and have supported DebConf since 2017.
About Amazon Web Services (AWS)
Amazon Web Services (AWS) is one of the world's
most comprehensive and broadly adopted cloud platform,
offering over 175 fully featured services from data centers globally
(in 77 Availability Zones within 24 geographic regions).
AWS customers include the fastest-growing startups, largest enterprises
and leading government agencies.
About Google
Google is one of the largest technology companies in the
world, providing a wide range of Internet-related services and products such
as online advertising technologies, search, cloud computing, software, and hardware.
Google has been supporting Debian by sponsoring DebConf for more than
ten years, and is also a Debian partner sponsoring parts
of Salsa's continuous integration infrastructure
within Google Cloud Platform.
Contact Information
For further information, please visit the DebConf21 web page at
https://debconf21.debconf.org/
or send mail to press@debian.org.
The record extension problem
Initially, the upgrade rules of Candid were a straight-forward application of the canonical subtyping rules. This worked and was sound, but it forbid one very commonly requested use case: Extending records in argument position.
The subtyping rule for records say that
record old_field : nat; new_field : int
<: record old_field : nat
or, in words, that subtypes can have more field than supertypes. This makes intuitive sense: A user of a such a record value that only expects old_field to be there is not bothered if suddenly a new_field appears. But a user who expects new_field to be there is thrown off if it suddenly isn t anymore. Therefore it is ok to extend the records returned by a service with new fields, but not to extend the record in your methods s argument types.
But users want to extend their record types over time, also in argument position!
In fact, they often want to extend them in both positions. Consider a service with the following interface, where the CUser record appears both in argument and result position:
type CUser = record login : text; name : text ;
service C :
register_user : (CUser) -> ();
get_user_data : (text) -> (CUser);
It seems quite natural to want to extend the record with a new field (say, the age of the user). But simply changing the definition of CUser to
type CUser = record login : text; name : text; age : nat
is not ok, because now register_user requires the age field, but old clients don t provide it.
So how can we allow developers to make changes like this (because they really really want that), while keeping the soundness guarantees made by Candid (because we really really want that)? This question has bothered us for over two years, and we even created a meta issue that records the dozen approached we considered, discussed and eventually ditched.
Dynamic subtyping checks in opt
I will spare you the history lesson, though, and explain the solution we eventually came up with.
In the example above it seems unreasonable to let the developer add a field age of type nat. Since there may be old clients around, the service unavoidably has to deal with records that don t have an age field. If the code expects an age value, what should it do in that case?
But one can argue that changing the record type to
type CUser = record login : text; name : text; age : opt nat
could work: If the age field is present, use the value. If the field is absent, inject a null value during decoding.
In the first-order case, this rather obvious solution would work just fine, and we d be done. But Candid aims to solve the higher order case, and I said things get tricky here, didn t I?
Consider another, independent service D with the following interface:
type DUser = record login : text; name : text ;
service D :
on_user_added : (func (DUser) -> ()) -> ()
This service has a method that takes a method reference, presumably with the intention of calling it whenever a new user was added to service D. And because the types line up nicely, we can compose these two services, by once calling D.on_user_added(C.register_user), so that from now on D calls C.register_user( ). These kind of service mesh-ups are central to the vision of the Internet Computer!
But what happens if the services now evolve their types in different ways, e.g. towards
type CUser = record login : text; name : text; age : opt nat
and
type DUser = record login : text; name : text; age : opt variant under_age; adult
Individually, these are type changes that we want to allow. But now the call from D to C may transmit a value of record ; age = opt variant under_age when C expects a natural number! This is precisely what we want to prevent by introducing types, and it seems we have lost soundness.
The best solution we could find is to make the opt type somewhat special, and apply these extra rules when decoding at an expected type of opt t.
If this was a record field, and the provided record value doesn t even have a field of that name, don t fail but instead treat this as null. This handles the first-order example above.
If there is a value, look at its type (which, in Candid, is part of the message).
If it is opt t' and t' <: t, then decode as normal.
If it is opt t' but t' <: t does not hold, then treat that as null.
This should only happen in these relatively obscure higher-order cases where services evolved differently and incompatibly, and makes sure that the calls that worked before the upgrades will continue to work afterwards.
It is not advisable to actually use that rule when changing your service s interface. Tools that assist the developer with an upgrade check should prevent or warn about the use of this rule.
Not strictly required here, but since we are making opt special anyways:
If its type t' is not of the form opt , pretend it was opt t', and also pretend that the given value was wrapped in opt.
This allows services to make record field in arguments that were required in the old version optional in a new version, e.g. as a way to deprecated them. So it is mildly useful, although I can report that it makes the meta-theory and implementation rather complex, in particular together with equirecursion and beasts like type O = opt O. See this discussion for a glimpse of that.
In the above I stress that we look at the type of the provided value, and not just the value. For example, if the sender sends the value opt vec at type opt vec nat, and the recipient expects opt vec bool, then this will decode as null, even though one could argue that the value opt vec could easily be understood at type opt vec bool. We initially had that, but then noticed that this still breaks soundness when there are references inside, and we have to do a full subtyping check in the decoder. This is very unfortunate, because it makes writing a Candid decoder a noticeably harder task that requires complicated graph algorithms with memoization (which I must admit Motoko has not implemented yet), but it s the least bad solution we could find so far.
Isn t that just dynamic typing?
You might have noticed that with these rules, t <: opt t' holds for all types t and t'. In other words, every opt is a top type (like reserved), thus all optional types are equivalent. One could argue that we are throwing all of the benefits of static typing over board this way. But it s not quite as bad: It s true that decoding Candid values now involves a dynamic check inserting null values in certain situations, but as long as everyone plays by the rules (i.e. upgrades their services according to the Candid safe upgrade rules, and heeds the warning alluded to above), these certain situations will only happen in the obscurest of cases.
It is, by the way, not material to this solution that the special subtyping behavior is applied to the opt type, and a neighboring point in the design space would be a dedicated upgraded t type constructor. That would allow developers to use the canonical opt type with the usual subtyping rules and communicate their intent ( clients should consider this field optional vs. old clients don t know about this field, but new clients should use it ) more cleanly at the expense of having more non-canonical types in the type system.
To see why it is convenient if Candid has mostly just the normal types, read the next post, which will describe how Candid can be integrated into a host language.
It seems that every cloud service of note has a free tier nowadays and the Oracle Cloud is the latest that I ve discovered (thanks to r/homelab which I highly recommend reading). Here s Oracle s summary of what they offer for free [1].
Oracle s always free tier (where presumable always is defined as until we change our contract ) currently offers ARM64 VMs to a total capacity of 4 CPU cores, 24G of RAM, and 200G of storage with a default VM size of 1/4 that (1 CPU core and 6G of RAM). It also includes 2 AMD64 VMs that each have 1G of RAM, but a 64bit VM with 1G of RAM isn t that useful nowadays.
Web Interface
The first thing to note is that the management interface is a massive pain to use. When a login times out for security reasons it redirects to a web page that gives a 404 error, maybe the redirection works OK if you are using it when it times out, but if you go off and spend an hour doing something else you will return to a 404 page. A web interface should never refer you to a page with a 404.
There doesn t seem to be a way of bookmarking the commonly used links (as AWS does) and the set of links on the left depend on the section you are in with no obvious way of going between sections. Sometimes I got stuck in a set of pages about authentication controls (the identity cloud ) and there seems to be no link I could click on to get me back to cloud computing, I had to go to a bookmarked link for the main cloud login page. A web interface should never force the user to type in the main URL or go to a bookmark, you should be able to navigate from every page to every other page in a logical manner. An advanced user might have their own bookmarks in their browser to suit their workflow. But a beginner should be able to go to anywhere without breaking the session.
Some parts of the interface appear to be copied from AWS, but unfortunately not the good parts. The way AWS manages IP access control is not easy to manage and it s not clear why packets are dropped, Oracle copies all this. On the upside Oracle has some good Datadog style analytics so for a new deployment you can debug IP access control by seeing records of rejected packets. Just to make it extra annoying when you create a rule with multiple ports specified the web interface will expand it out to multiple rules for one port each, having ports 80 and 443 on separate lines doesn t make things easier. Also it forces you to have IPv4 and IPv6 as separate rules, so if you want HTTP and HTTPS on both IPv4 and IPv6 (a common requirement) then you need 4 separate rules.
One final annoying thing is that the web interface doesn t make your previous settings a default. As I ve created many ARM images and haven t created a single AMD image it should know that the probability that I want to create an AMD image is very low and stop defaulting to that.
Recovery
When trying a new system you will inevitably break things and have to recover things. The way to recover from a configuration error that prevents your VM from booting and getting to a state of allowing a login is to go to stop the VM, then go to the Boot volume section under Resources and use the settings button to detach the boot volume. Then you go to another VM (which must be running), go to the Attached block volumes menu and attach it as Paravirtualised (not iSCSI and not default which will probably be iSCSI). After some time the block device will appear and you can mount it and do stuff to it. Then after umounting it you detach it from the recovery VM and attach it again to the original VM (where it will still have an entry in the Boot volume section) and boot the original VM.
As an aside it s really annoying that you can t attach a volume to a VM that isn t running.
My first attempt at image recovery started with making a snapshot of the Boot volume, this didn t work well because the image uses EFI and therefore GPT and because the snapshot was larger than the original block device (which incidentally was the default size). I admit that I might have made a mistake making the snapshot, but if so it shouldn t be so easy to do. With GPT if you have a larger block device then partitioning tools complain about the backup partition table not being found, and they complain even more if you try to go back to the smaller size later on. Generally GPT partition tables are a bad idea for VMs, when I run the host I don t use partition tables, I have a separate block device for each filesystem or swap space.
Snapshots aren t needed for recovery, they don t seem to work very well, and if it s possible to attach a snapshot to a VM in place of it s original Boot volume I haven t figured out how to do it.
Console Connection
If you boot Oracle Linux a derivative of RHEL that has SE Linux enabled in enforcing mode (yay) then you can go to the Console connection . The console is a Javascript console which allows you to login on a virtual serial console on device /dev/ttyAMA0. It tells you to type help but that isn t accepted, you have a straight Linux console login prompt.
If you boot Ubuntu then you don t get a working serial console, it tells you to type help for help but doesn t respond to that.
It seems that the Oracle Linux kernel 5.4.17-2102.204.4.4.el7uek.aarch64 is compiled with support for /dev/ttyAMA0 (the default ARM serial device) while the kernel 5.11.0-1016-oracle compiled by Oracle for their Ubuntu VMs doesn t have it.
Performance
I haven t done any detailed tests of VM performance. As a quick test I used zstd to compress a 154MB file, on my home workstation (E5-2620 v4 @ 2.10GHz) it took 11.3 seconds of CPU time to compress with zstd -9 and 7.2s to decompress. On the Oracle cloud it took 7.2s and 5.4s. So it seems that for some single core operations the ARM CPU used by the Oracle cloud is about 30% to 50% faster than a E5-2620 v4 (a slightly out of date server processor that uses DDR4 RAM).
If you ran all the free resources in a single VM that would make a respectable build server. If you want to contribute to free software development and only have a laptop with 4G of RAM then an ARM build/test server with 24G of RAM and 4 cores would be very useful.
Ubuntu Configuration
The advantage of using EFI is that you can manage the kernel from within the VM. The default Oracle kernel for Ubuntu has a lot of modules included and is compiled with a lot of security options including SE Linux.
Competitors
https://aws.amazon.com/free
AWS offers 750 hours (just over 31 days) per month of free usage of a t2.micro or t3.micro EC2 instance (which means 1GB of RAM). But that only lasts for 12 months and it s still only 1GB of RAM. AWS has some other things that could be useful like 1 million free Lambda requests per month. If you want to run your personal web site on Lambda you shouldn t hit that limit. They also apparently have some good offers for students.
https://cloud.google.com/free
The Google Cloud Project (GCP) offers $300 of credit.
https://cloud.google.com/free/docs/gcp-free-tier#free-tier-usage-limits
GCP also has ongoing free tier usage for some services. Some of them are pretty much unlimited use (50GB of storage for Cloud Source Repositories is a heap of source code). But for VMs you get the equivalent of 1*e2-micro instance running 24*7. A e2-micro has 1G of RAM. You also only get 30G of storage and 1GB of outbound data. It s clearly not as generous an offer as Oracle, but Oracle is the underdog so they have to try harder.
https://azure.microsoft.com/en-us/free/
Azure appears to be much the same as AWS, free Linux VM for a year and then other less popular services free forever (or until they change the contract).
https://www.ibm.com/cloud/free
The IBM cloud free tier is the least generous offer, a VM is only free for 30 days. But what they offer for 30 days is pretty decent. If you want to try the IBM cloud and see if it can do what your company needs then this will do well. If you want to have free hosting for your hobby stuff then it s no good.
Oracle seems like the most generous offer if you want to do stuff, but also one of the least valuable if you want to learn things that will help you at a job interview. For job interviews AWS seems the most useful and then GCP and Azure vying for second place.
Another release of the tidyCpp package arrived on CRAN earlier today. The packages offers a clean C++ layer on top of the C API for R which aims to make its use a little easier and more consistent.
The vignette has been extended once more with a new example, and added a table of contents. The package now supports a (truly minimal) C++ class for a numeric vector which is the most likely use case.
The NEWS entry follows and includes the 0.0.3 release earlier in the year which did not get the usual attention of post-release blog post.
Changes in tidyCpp version 0.0.4 (2021-09-05)
Minor updates to DESCRIPTION
New snippet rollminmaxExample with simple vector use
New class NumVec motivated from rolling min/max example
Expand the vignette with C++ example based on NumVec
tl;dr:
With these two crazy proc-macros you can
hand out multipe (perhaps mutable) references to suitable subsets/views of the same struct.
Why
In Otter I have adopted
a style where I try to avoid giving code mutable access that doesn't need it, and try to make mutable access come with some code structures to prevent "oh I forgot a thing" type mistakes. For example, mutable access to a game state is only available in contexts that have to return a value for the updates to send to the players. This makes it harder to forget to send the update.
But there is a downside. The game state is inside another struct, an Instance, and much code needs (immutable) access to it. I can't pass both &Instance and &mut GameState because one is inside the other.
My workaround involves passing separate references to the other fields of Instance, leading to some functions taking far too many arguments. 14 in one case. (They're all different types so argument ordering mistakes just result in compiler errors talking about arguments 9 and 11 having wrong types, rather than actual bugs.)
I felt this problem was purely a restriction arising from limitations of the borrow checker. I thought it might be possible to improve on it. Weeks passed and the question gradually wormed its way into my consciousness. Eventually, I tried some experiments. Encouraged, I persisted.
What and how
partial-borrow is a Rust library which solves this problem. You sprinkle #[Derive(PartialBorrow)] and
partial!(...) and then you can
pass a reference which grants mutable access to only some of the fields. You can also pass a reference through which some fields are inaccessible. You can even split a single mut reference into multiple compatible references, for example granting mut access to mutually-nonverlapping subsets.
The core type is Struct__Partial (for some Struct).
It is a zero-sized type, but we prevent anyone from constructing one.
Instead we magic up references to it, always ensuring that they have the same address as some Struct.
The fields of Struct__Partial are also ZSTs that exist ony as references, and they Deref to the actual field (subject to compile-type borrow compatibility checking).
Soundness and testing
partial-borrow is primarily a nontrivial procedural macro which autogenerates reams of unsafe.
Of course I think it's sound, but I thought that the last two times before I added a test which demonstrated otherwise. So it might be fairer to say that I have tried to make it sound and that I don't know of any problems...
Reasoning about the correctness of macro-generated code is not so easy. One problem is that there is nowhere good to put the kind of soundness arguments you would normally add near uses of unsafe.
I decided to solve this by annotating an instance of the macro output. There's a not very complicated script using diff3 to help fold in changes if the macro output changes - merge conflicts there mean a possible re-review of the argument text. Of course I also have test cases that run with miri, and test cases for expected compiler errors for uses that need to be forbidden for soundness.
But this is quite hairy and I'm worried that it might be rather "my first insane unsafe contraption".
Also the pointer/reference trickery is definitely subtle, and depends heavily on knowing what Rust's aliasing and pointer provenance rules really are. Stacked Borrows is not entirely trivial to reason about in fiddly corner cases.
So for now I have only called it 0.1.0 and left a note in the docs. I haven't actually made Otter use it yet but that's the rather more boring software integration part, not the fun "can I do this mad thing" part so I will probably leave that for a rainy day. Possibly a rainy day after someone other than me has looked at partial-borrow (preferably someone who understands Stacked Borrows...).
Fun!
This was great fun. I even enjoyed writing the docs.
The proc-macro programming environment is not entirely straightforward and there are a number of things to watch out for. For my first non-adhoc proc-macro this was, perhaps, ambitious. But you don't learn anything without trying...
edited 2021-09-02 16:28 UTC to fix a typo
Safe upgrades
A central idea behind Candid is that services evolve over time, and so also their interfaces evolve. As they do, it is desirable to keep the interface usable by clients who have not been updated. In particular on a blockchainy platform like the Internet Computer, where some programs are immutable and cannot be changed to accommodate changes in the interface of the services they use, this is of importance.
Therefore, Candid defines which changes to an interface are guaranteed to be backward compatible. Of course it s compatible to add new methods to a service, but some changes to a method signature can also be ok. For example, changing
service A1 :
get_value : (variant current; previous : nat )
-> (record value : int; last_change : nat )
is fine: It doesn t matter that clients that still use the old interface don t know about the new constructor of the argument variant. And the extra field in the result record will silently be ignored by old clients.
In the Candid spec, this relation is written as A2 <: A1 (note the order!), and the formal footing this builds on is subtyping. We thus say that it is safe to upgrade a service to a subtype , and that A2 s interface is a subtype of A1 s.
In small examples, I often use nat and int, because every nat is also a int, but some int values are not not nat values, namely the negative ones. We say nat is a subtype of int, nat <: int. So a function that in the first returns a int can in the new version return a nat without breaking old clients. But the other direction doesn t work: If the old version s method had a return type of nat, then changing that to int would be a breaking change, as old clients would not be prepared to handle negative numbers.
Note that arguments of function types follow different rules. In fact, the rules are simply turned around, and in argument position (also called negative position ), we can evolve the interface to accept supertypes. Concretely, a function that originally expected an nat can be changed to expect an int, but the other direction doesn t work, because there might still be old clients around that send negative numbers. This reversing-of-the-rules is called contravariance.
The vision is that the developer s tooling will warn the developer before they upgrade the code of a running service to a type that is not a subtype of the old interface.
Let me stress, though, that all this is about not breaking existing clients that use the old interface. It does not mean that a client developer who fetches the new interface for your service won t have to change their code to make his programs compile again.
Higher order composition
So far, we considered the simple case of one service with a bunch of clients, i.e. the first order situation. Things get much more interesting if we have multiple services that are composed, and that pass around references to each other, and we still want everything to be nicely typed and never fail even as we upgrade services.
Therefore, Candid s type system can express that a service s method expects or a returns a reference to another service or method, and the type that this service or method should have. For example
service B : add_listener : (text, func (int) -> ()) -> ()
says that the service with interface B has a method called add_listener which takes two arguments, a plain value of type text and a reference to a function that itself expects a int-typed argument.
The contravariance of the subtyping rules explained above also applies to the types of these function reference. And because the int in the above type is on the left of two function arrows, the subtyping rule direction flips twice, and it is therefore safe to upgrade the service to accept the following interface:
service B : add_listener : (text, func (nat) -> ()) -> ()
Soundness theorem and Coq proof
The combination of these higher order features and the safe upgrade mechanism is maybe the unique selling point of Candid, but also what made its design quite tricky sometimes. And although the conventional subtyping rules work well, we wanted to do some less conventional things (more on that below), and more than once thought we had a good solution, only to notice that it did not hold water in complicated higher-order cases.
But what does it mean to hold water? I felt the need to precisely define a soundness criteria for higher order interface description languages, which you can find in the document An IDL Soundness Proposition. This is a general framework which you can instantiate with your concrete IDL language and rules, and then it tells you what you have to prove to consider your language to be sound. Intuitively, it simulates all possible ways in which services can be defined and upgraded, and in which they can pass around references to each other, and the soundness property is that then that for all messages sent between services, they can always be understood.
The document also shows, in general, that any system that builds on canonical subtyping in sound, as expected. That is still a generic theorem that you can instantiate with a concrete system, but now there is less to do.
Because these proofs can get tricky in corner cases, it is valuable to mechanize them in an interactive theorem prover and have the computer check the proofs. So I have created a Coq formalization that defines the soundness criteria, including the reduction to canonical subtyping. It also defines MiniCandid, a greatly simplified variant of Candid, proves various properties about it (transitivity etc.) and finally instantiates the soundness theorem.
I am particularly fond of the use of coinduction to model the equirecursive types, and the use of named cases, as we know them from Isabelle, to make the proofs a bit more readable and maintainable.
I am less fond of how much work it seems to be to extend MiniCandid with more of Candid s types. Already adding vec was more work than it s worth it, and I defensively blame Coq s not-so-great support for nested recursion.
The soundness relies on subtyping, and that is all fine and well as long as we stick to canonical rules. Unfortunately, practical considerations force us to deviate from these a bit, as we see in the next post of this series.
The Debian Janitor is an automated
system that commits fixes for (minor) issues in Debian packages that can be
fixed by software. It gradually started proposing merges in early
December. The first set of changes sent out ran lintian-brush on sid packages maintained in
Git. This post is part of a series about the progress of the Janitor.
Linux distributions like Debian fulfill an important function in the FOSS ecosystem - they are system integrators that take existing free and open source software projects and adapt them where necessary to work well together. They also make it possible for users to install more software in an easy and consistent way and with some degree of quality control and review.
One of the consequences of this model is that the distribution package often lags behind upstream releases. This is especially true for distributions that have tighter integration and standardization (such as Debian), and often new upstream code is only imported irregularly because it is a manual process - both updating the package, but also making sure that it still works together well with the rest of the system.
The process of importing a new upstream used to be (well, back when I started working on
Debian packages) fairly manual and something like this:
Go to the upstream s homepage, find the tarball and signature and verify the tarball
Make modifications so the tarball matches Debian s format
Diff the original and new upstream tarballs and figure out whether changes
are reasonable and which require packaging changes
Update the packaging, changelog, build and manually test the package
Upload
Ecosystem Improvements
However, there have been developments over the last decade that make it easier to import new upstream releases into Debian packages.
Uscan and debian QA watch
Uscan and
debian/watch have been around for a
while and make it possible to find upstream tarballs.
A debian watch file usually looks something like this:
The QA watch service regularly polls
all watch locations in the archive and makes the information available, so it s
possible to know which packages have changed without downloading each one of them.
Git
Git is fairly ubiquitous nowadays, and most upstream projects and packages in Debian use it. There are still exceptions that do not use any version control system or that use a different control system, but they are becoming increasingly rare. [1]
debian/upstream/metadata
DEP-12 specifies a file format with metadata about the upstream project that a package was based on. In particular relevant for our case is the fact it has fields for the location of the upstream version control location.
debian/upstream/metadata files look something like this:
While DEP-12 is still a draft, it has already been widely adopted - there are about 10000 packages in Debian that ship a debian/upstream/metadata file with Repository information.
Autopkgtest
The Autopkgtest
standard and associated tooling provide a way to run a defined set of tests
against an installed package. This makes it possible to verify that a package
is working correctly as part of the system as a whole. ci.debian.net regularly runs these tests against Debian packages to
detect regressions.
Vcs-Git headers
The Vcs-Git headers in debian/control are the equivalent of the Repository field in debian/upstream/metadata, but for the packaging repositories (as opposed to the upstream ones).
They ve been around for a while and are widely adopted, as can be seen from zack s stats:
The vcswatch service that regularly
polls packaging repositories to see whether they have changed makes it a lot
easier to consume this information in usable way.
Debhelper adoption
Over the last couple of years, Debian has slowly been converging on a single
build tool - debhelper s dh interface.
Being able to rely on a single build tool makes it easier to write code to
update packaging when upstream changes require it.
Debhelper DWIM
Debhelper (and its helpers) increasingly can figure out how to do the Right
Thing in many cases without being explicitly configured. This makes packaging
less effort, but also means that it s less likely that importing a new upstream
version will require updates to the packaging.
With all of these improvements in place, it actually becomes feasible in a lot
of situations to update a Debian package to a new upstream version
automatically. Of course, this requires that all of this information is
available, so it won t work for all packages. In some cases, the packaging for
the older upstream version might not apply to the newer upstream version.
The Janitor has attempted to import a new upstream Git snapshot and a new
upstream release for every package in the archive where a debian/watch file or
debian/upstream/metadata file are present.
These are the steps it uses:
Find new upstream version
If release, use debian/watch - or maybe tagged in upstream repository
If snapshot, use debian/upstream/metadata s Repository field
If neither is available, use guess-upstream-metadata from upstream-ontologist to guess the upstream Repository
Merge upstream version into packaging repository, possibly importing tarballs using pristine-tar
Update the changelog file to mention the new upstream version
Run some checks to ensure there are no unintentional changes, e.g.:
Scan diff between old and new for surprising license changes
Today, abort if there are any - in the future, maybe update debian/copyright
Check for obvious compatibility breaks - e.g. sonames changing
Attempt to update the packaging to reflect upstream changes
Refresh patches
Attempt to build the package with deb-fix-build, to deal with any missing dependencies
Run the autopkgtests with deb-fix-build to deal with missing dependencies, and abort if any tests fail
Results
When run over all packages in unstable (sid), this process works for a surprising number of them.
Fresh Releases
For fresh-releases (aka imports of upstream releases), processing all packages maintained in Git for which QA watch reports new releases (about 11,000):
That means about 2300 packages updated, and about 4000 unchanged.
Fresh Snapshots
For fresh-snapshots (aka imports of latest Git commit from upstream), processing all packages maintained in Git (about 26,000):
Or 5100 packages updated and 2100 for which there was nothing to do, i.e. no upstream commits since the last Debian upload.
As can be seen, this works for a surprising fraction of packages. It s possible to get the numbers up even higher, by both improving the tooling, the autopkgtests and the metadata that is provided by packages.
Using these packages
All the packages that have been built can be accessed from the Janitor APT repository. More information can be found at https://janitor.debian.net/fresh, but in short - run:
1
2
3
4
5
6
echo deb "[arch=amd64 signed-by=/usr/share/keyrings/debian-janitor-archive-keyring.gpg]" \ https://janitor.debian.net/ fresh-snapshots main sudo tee /etc/apt/sources.list.d/fresh-snapshots.listecho deb "[arch=amd64 signed-by=/usr/share/keyrings/debian-janitor-archive-keyring.gpg]" \ https://janitor.debian.net/ fresh-releases main sudo tee /etc/apt/sources.list.d/fresh-releases.listsudo curl -o /usr/share/keyrings/debian-janitor-archive-keyring.gpg https://janitor.debian.net/pgp_keysapt update
And then you can install packages from the fresh-snapshots (upstream git snapshots) or fresh-releases suites on a case-by-case basis by running something like:
1
apt install -t fresh-snapshots r-cran-roxygen2
Most packages are updated based on information provided by vcswatch and qa watch, but it s also possible for upstream repositories to call a web hook to trigger a refresh of a package.
These packages were built against unstable, but should in almost all cases also work for testing.
Caveats
Of course, since these packages are built automatically without human supervision it s likely that some of them will have bugs in them that would otherwise have been caught by the maintainer.
Hello there.
So here we are near the end of GSoC 2021 and with that, I am sharing details of the work I completed in the second phase of the coding period.
Continuing with details of the task I left on
Task: Adding support for testing security uploads and Debian LTS
The extra-apt-sources parameter is added to both API and Self-Service section for the test request object and the part which took some time was deciding on its validation since if you ever deal with apt sources, you would know that there exist a lot of combinations of a valid apt source and in the end, the decision was taken to just add the minimal checks.
Since, we have enough setup to request private tests, it made sense to have a way of looking them up in the Self-Service section. So a new column is added to the test records in Job-History marking the visibility of a test (private or public) and a new filter to filter out records based on the visibility.
The option to retry tests is also added in Self-Service in the Job-History section so that private tests can also be retried. As earlier, this option was only available in Package History pages but those pages do not show the private tests.
The next thing in the list was to publish these test results of private tests at some point.
For the API section, a new endpoint is added to accept a string of run_ids which is ready to be published, and for the Self-Service , in the Job-History page a Publish button is added to be clicked after check boxing the required tests.
This ends the list of my planned work for the project.
Some more interesting stuff
As we got some more time for the coding period to end, my mentor Antonio Terceiro suggested that I could pick any issue from the opened issues list to work on so I picked up the one to add a user menu for the Self-Service section and completed that.
Antonio also gave me insights into Debian Packaging and even let me try packaging a newer upstream version of the package itamae which is one of the packages maintained by him.
I also worked on creating a video about my GSoC project for DebConf21 and this was truly the hardest thing to do. From setting up everything to final editing, it took me about 2 days to create something sane to submit. Now, I am excited about DebConf21
That concludes my work in the second phase of the coding period and next, I will be sharing my Final Evaluation Submission real soon.
Stay tuned!
Serapio has been crafted and trained to be the vessel for a god. He grew
up in Obregi land, far from his ancestral home, but he will return to Tova
at the appropriate time and carry the hopes of the Carrion Crow clan with
him.
Xiala is a ship captain, a woman, and a Teek. That means she's a target.
Teek have magic, which makes them uncanny and dangerous. They're also
said to carry that magic in their bones, which makes them valuable in ways
that are not pleasant for the Teek. Running afoul of the moral codes of
Cuecola is therefore even more dangerous to her than it would be to
others, which is why she accepts a bargain to run errands for a local lord
for twelve years, paid at the end of that time with ownership of a ship
and crew. The first task: ferry a strange man to the city of Tova.
Meanwhile, in Tova, the priestess Naranpa has clawed her way to the top of
the Sky Made hierarchy from an inauspicious beginning in the poor district
of Coyote's Maw. She's ruthlessly separated herself from her despised
beginnings and focused her attention on calming Tova in advance of the
convergence, a rare astronomical alignment at the same time as the winter
solstice. But Carrion Crow holds a deep-seated grudge at their slaughter
by the priesthood during the Night of Knives, and Naranpa's position atop
the religious order that partly rules Tova's fractious politics is more
precarious than she thinks.
I am delighted that more fantasy is drawing on mythologies and histories
other than the genre default of western European. It's long overdue for
numerous reasons and a trend to be rewarded. But do authors writing
fantasy in English who reach for Mesoamerican cultures have to gleefully
embrace the excuse to add more torture? I'm developing an aversion to
this setting (which I do not want to do!) because every book seems to
feature human sacrifice, dismemberment, or some other horror show.
Roanhorse at least does not fill the book with that (there's lingering
child abuse but nothing as sickening as the first chapter), but that makes
the authorial choice to make the torture one's first impression of this
book even odder. Our introduction to Serapio is a scene that I would have
preferred to have never read, and I don't think it even adds much to the
plot. Huge warnings for people who don't want to read about a mother
torturing her son, or about eyes in that context.
Once past that introduction, Black Sun settles into a two-thread
fantasy, one following Xiala and Serapio's sea voyage and the other
following Naranpa and the political machinations in Tova. Both the magic
systems and the political systems are different enough to be refreshing,
and there are a few bits of world-building I enjoyed (a city built on top
of rocks separated by deep canyons and connected with bridges, giant
intelligent riding crows, everything about the Teek). My problem was that
I didn't care what happened to any of the characters. Naranpa spends most
of the book dithering and whining despite a backstory that should have
promised more dynamic and decisive responses. The other character from
Tova introduced somewhat later in the book is clearly "character whose
story will appear in the next volume"; here, he's just station-keeping and
representing the status quo. And while it's realistic given the plot that
Serapio is an abused sociopath, that didn't mean I enjoyed reading his
viewpoint or his childhood abuse.
Xiala is the best character in the book by far and I was warming to the
careful work she has to do to win over an unknown crew, but apparently
Roanhorse was not interested in that. Instead, the focus of Xiala's
characterization turns to a bad-boy romance that did absolutely nothing
for me. This will be a matter of personal taste; I know this is a plot
feature for many readers. But it had me rolling my eyes and turning the
pages to get to something more interesting (which, sadly, was not
forthcoming). It also plays heavily on magical disabled person cliches,
like the blind man being the best fighter anyone has met.
I did not enjoy this book very much, but there were some neat bits of
world-building and I could see why other people might disagree. What
pushed me into actively recommending against it (at least for now) is the
publishing structure.
This is the first book of a trilogy, so one can expect the major plot to
not be resolved by the end of the book. But part of the contract with the
reader when publishing a book series is that each volume should reach some
sense of closure and catharsis. There will be cliffhangers and unanswered
questions, but there should also be enough plot lines that are
satisfactorily resolved to warrant publishing a book as a separate novel.
There is none of that here. This is the first half (or third) of a novel.
It introduces a bunch of plot lines, pulls them together, describes an
intermediate crisis, and then simply stops. Not a single plot line is
resolved. This is made worse by the fact this series (presumably, as I
have only seen the first book) has a U-shaped plot: everything gets worse
and worse until some point of crisis, and then presumably the protagonists
will get their shit together and things will start to improve. I have
soured on U-shaped plots since the first half of the story often feels
like a tedious grind (eat your vegetables and then you can have dessert),
but it's made much worse by cutting the book off at the bottom of the U.
You get a volume, like Black Sun, that's all setup and horror and
collapse, with no payoff or optimism.
After two tries, I have concluded that Roanhorse is not for me. This is
clearly a me problem rather than a Roanhorse problem, given how many other
people love both Black Sun and her Sixth
World series, but this is the second book of hers where I mildly enjoyed
the world building but didn't care about any of the characters. Ah well,
tastes will differ. Even if you get along with Roanhorse, though, I
recommend against starting this book until the second half of it is
published (currently scheduled for 2022). As it stands, it's a wholly
unsatisfying reading experience.
Followed by the not-yet-published Fevered Star.
Rating: 4 out of 10
Review: The Galaxy, and the Ground Within, by Becky Chambers
Series:
Wayfarers #4
Publisher:
Harper Voyager
Copyright:
April 2021
ISBN:
0-06-293605-0
Format:
Kindle
Pages:
325
The name of the planet Gora is the Hanto word for useless. It's a
bone-dry, resource-poor planet with nothing to recommend it except that it
happened to be conveniently located between five other busy systems and
had well-established interspacial tunnels. Gora is therefore a transit
hub: a place lots of people visit for about half a day while waiting for a
departure time, but where very few people stay. It is the interstellar
equivalent of an airport.
Ouloo is a Laru, a species physically somewhat similar to a giant dog.
She is the owner of the Five-Hop One-Stop in a habitat dome on Gora, where
she lives with her child (who is not yet old enough to choose a gender).
On the day when this novel begins, she's expecting three ships to dock:
one Aeluon, one Quelin, and, to Ouloo's significant surprise and moderate
discomfort, an Akarak. But apart from that, it's a normal day.
A normal day, that is, until maintenance work on the solar satellite array
leads to a Kessler syndrome collision cascade that destroys most of the
communication satellites and makes it unsafe to leave the surface of the
planet. Ouloo and her guests are stuck with each other for longer than
they expected.
In a typical SF novel, you would expect the characters to have to fix the
satellite cascade, or for it to be a sign of something more nefarious.
That is not the case here; the problem is handled by the Goran
authorities, the characters have no special expertise, and there is no
larger significance to the accident. Instead, the accident functions as
storm in a very old story-telling frame: three travelers and their host
and her child, trapped together by circumstance and forced to entertain
each other until they can go on their way.
Breaking from the formula, they do not do that primarily by telling
stories to each other, although the close third-person narration that
moves between the characters reveals their backgrounds over the course of
the book. Instead, a lot of this book is conversation, sometimes prompted
by Ouloo's kid Tupo (who I thought was a wonderfully-written tween,
complete with swings between curiosity and shyness, random interests,
occasionally poor impulse control, and intense but unpredictable learning
interest). That leads to some conflict (and some emergencies), but,
similar to Record of a Spaceborn Few,
this is more of a character study book than a things-happen book.
An interesting question, then, is why is this story science fiction? A
similar story could be written (and has been, many times) with human
travelers in a mundane inn or boarding house in a storm. None of the
aliens are all that alien; despite having different body shapes and
senses, you could get more variation from a group of university students.
And even more than with Chambers's other books, the advanced technology is
not the point and is described only enough to provide some background
color and a bit of characterization.
The answer, for me, is that the cognitive estrangement of non-human
characters relieves my brain of the baggage that I bring to human
characters and makes it easier for me to empathize with the characters as
individuals rather than representatives of human archetypes. With human
characters, I would be fitting them into my knowledge of history and
politics, and my reaction to each decision the characters make would be
influenced by the assumptions prompted by that background. I enjoy the
distraction of invented worlds and invented histories in part because
they're simplified compared to human histories and therefore feel more
knowable and less subtle. I'm not trying to understand the political
angle from which the author is writing or wondering if I'm missing a
reference that's important to the story.
In other words, the science fiction setting gives the narrator more power.
The story tells me the important details of the background; there isn't
some true history lurking beneath that I'm trying to ferret out. When
that's combined with interesting physical differences, I find myself
imagining what it would be like to be the various aliens, trying to insert
myself into their worlds, rather than placing them in a historical or
political context. That puts me in a curious and empathetic mindset, and
that, in turn, is the best perspective from which to enjoy Chambers's
stories.
The characters in this story don't solve any large-scale problems. They
do make life decisions, some quite significant, but only on a personal
scale. They also don't resolve all of their suspicions and disagreements.
This won't be to everyone's taste, but it's one of the things I most
enjoyed about the book: it shows a small part of the lives of a collection
of average individuals, none of whom are close to the levers of power and
none of whom are responsible for fixing their species or galactic
politics. They are responsible for their own choices, and for how their
lives touch the lives of others. They can make the people they encounter
happier or sadder, they can chose how to be true to their own principles,
and they can make hard choices without right answers.
When I describe a mainstream fiction book that way, I often find it
depressing, but I came away from The Galaxy, and the Ground Within
feeling better about the world and more open-hearted towards other people.
I'm not sure what Chambers does to produce that reaction, so I'm not sure
if it will have the same effect on other people. Perhaps part of it is
that while there is some drama, her characters do not seek drama for its
own sake, none of the characters are villains, and she has a way of
writing sincerity that clicks with my brain.
There is a scene, about two-thirds of the way through the book, where the
characters get into a heated argument about politics, and for me this is
the moment where you will either love this book or it will not work for
you. The argument doesn't resolve anything, and yet it's one of the most
perceptive, accurate, and satisfying portrayals of a political argument
among normal people that I've seen in fiction. It's the sort of
air-clearing conversation in which every character is blunt with both
their opinion and their emotions rather than shading them for politeness.
Those positions are not necessarily sophisticated or deeply philosophical,
but they are deeply honest.
"And you know what? I truly don't care which of them is right so long
as it fixes everything. I don't have an... an ideology. I don't know
the right terms to discuss these things. I don't know the science
behind any of it. I'm sure I sound silly right now. But I just want
everyone to get along, and to be well taken care of. That's it. I
want everybody to be happy and I do not care how we get there." She
exhaled, her broad nostrils flaring. "That's how I feel about it."
I am not Ouloo, but I think she represents far more people than fiction
normally realizes, and I found something deeply satisfying and revealing
in seeing that position presented so clearly in the midst of a heated
argument.
If you like what Chambers does, I think you will like this book. If it's
not for you, this is probably not the book that will change your mind,
although there is a bit less hand-wavy technology to distract the people
whom that distracts. The Galaxy, and the Ground Within didn't have
the emotional resonance that Record of a Spaceborn Few had for me,
or the emotional gut punch of A Closed and
Common Orbit. But I loved every moment of reading it.
This will apparently be the last novel in the Wayfarers universe, at least
for the time being. Chambers will be moving on to other settings
(starting with A Psalm for the Wild-Built).
Rating: 8 out of 10
Several issues were brought before the Debian Community team regarding responsiveness, tone, and needed software updates to forums.debian.net. The question was asked, who s in charge?
Over the course of the discussion several Debian Developers volunteered to help by providing a presence on the forums from Debian and to assist with the necessary changes to keep the service up and running.
We are happy to announce the following changes to the (NEW!) forums.debian.net, which have and should address most of the prior concerns with accountability, tone, use, and reliability:
Debian Developers: Paulo Henrique de Lima Santana (phls), Felix Lechner (lechner), and Donald Norwood (donald) have been added to the forum's Server and Administration teams.
The server instance is now running directly within Debian's infrastructure.
The forum software and back-end have been updated to the most recent versions where applicable.
DNS resolves for both IPv4 and IPv6.
SSL/HTTPS are enabled. (It s 2021!)
New Captcha and Anti-spam systems are in place to thwart spammers, bots, and to make it easier for humans to register.
New Administrators and Moderation staff were added to provide additional coverage across the hours and to combine years of experience with forum operation and Debian usage.
New viewing styles are available for users to choose from, some of which are ideal for mobile/tablet viewing.
We inadvertently fixed the time issue that the prior forum had of running 11 minutes fast. :)
We have clarified staff roles and staff visibility.
Responsiveness to users on the forums has increased.
Email addresses for mods/admins have been updated and checked for validity, it has seen direct use and response.
The guidelines for forum use by users and staff have been updated.
The Debian COC has been made into a Global Announcement as an accompanyist to the newly updated guidelines to give the moderators/administrators an additional rule-set for unruly or unbecoming behavior.
Some of the discussion areas have been renamed and refocused, along with the movement of multiple threads to make indexing and searching of the forums easier.
Many (New!) features and extensions have been added to the forum for ease of use and modernization, such as a user thanks system and thread hover previews.
There are some server administrative tasks that were upgraded as well which don't belong on a public list, but we are backing up regularly and secure. :)
We have a few minor details here and there to attend to and the work is ongoing.
Many Thanks and Appreciation to the Debian System Administrators (DSA) and Ganneff who took the time to coordinate and assist with the instance, DNS, and network and server administration minutiae, our helpful DPL Jonathan Carter, many thanks to the current and prior forum moderators and administrators: Mez, sunrat, 4D696B65, arochester, and cds60601 for helping with the modifications and transition, and to the forum users who participated in lots of the tweaking. All in all this was a large community task and everyone did a significant part. Thank you!
If I have seen further, it is by standing on the shoulders of Giants Issac Newton, 1675. Although it should be credited to 12th century Bernard of Chartres. You will know why I have shared this, probably at the beginning of Civil Aviation history itself.
Comments on the BBI court case which happened in Kenya, then and the subsequent appeal.
I am not going to share much about the coverage of the BBI appeal as Gautam Bhatia has shared quite eloquently his observations, both on the initial case and the subsequent appeal which lasted 5 days in Kenya and was shown all around the world thanks to YouTube. One of the interesting points which stuck with me was that in Kenya, sign language is one of the official languages. And in fact, I was able to read quite a bit about the various sign languages which are there in Kenya. It just boggles the mind that there are countries that also give importance to such even though they are not as rich or as developed as we call developed economies. I probably might give more space and give more depth as it does carry some important judicial jurisprudence which is and which will be felt around the world. How does India react or doesn t is probably another matter altogether But yes, it needs it own space, maybe after some more time.
Report on Standing Committee on IP Regulation in India and the false promises.
Again, I do not want to take much time in sharing details about what the report contains, as the report can be found here. I have uploaded it on WordPress, in case of an issue. An observation on the same subject can be found here. At least, to me and probably those who have been following the IP space as either using/working on free software or even IP would be aware that the issues shared have been known since 1994. And it does benefit the industry rather than the country. This way, the rent-seekers, and monopolists win. There is ample literature that shared how rich countries had weak regulation for decades and even centuries till it was advantageous for them to have strong IP. One can look at the history of Europe and the United States for it. We can also look at the history of our neighbor China, which for the last 5 decades has used some provision of IP and disregarded many others. But these words are of no use, as the policies done and shared are by the rich for the rich.
Fighting between two State Borders
Ironically or because of it, two BJP ruled states Assam and Mizoram fought between themselves. In which 6 policemen died. While the history of the two states is complicated it becomes a bit more complicated when one goes back into Assam and ULFA history and comes to know that ULFA could not have become that powerful until and unless, the Marwaris, people of my clan had not given generous donations to them. They thought it was a good investment, which later would turn out to be untrue. Those who think ULFA has declined, or whatever, still don t have answers to this or this.
Interestingly, both the Chief Ministers approached the Home Minister (Mr. Amit Shah) of BJP. Mr. Shah was supposed to be the Chanakya but in many instances, including this one, he decided to stay away. His statement was on the lines of you guys figure it out yourself.
There is a poem that was shared by the late poet Rahat Indori. I am sharing the same below as an image and will attempt to put a rough translation.
kisi ke baap ka hindustan todi hain Rahat Indori
Poets, whether in India or elsewhere, are known to speak truth to power and are a bit of a rebel. This poem by Rahat Indori is provocatively titled Kisi ke baap ka Hindustan todi hai , It challenges the majoritarian idea that Hindustan/India only belongs to the majoritarian religion. He also challenges as well as asserts at the same time that every Indian citizen, regardless of whatever his or her religion might be, is an Indian and can assert India as his home. While the whole poem is compelling in itself, for me what hits home is in the second stanza
:Lagegi Aag to aayege ghat kayi zad me, Yaha pe sirf hamara makan todi hai
The meaning is simple yet subtle, he uses Aag or Fire as a symbol of hate sharing that if hate spreads, it won t be his home alone that will be torched. If one wants to literally understand what he meant, I present to you the cult Russian movie No Escapes or Ogon as it is known in Russian.
If one were to decipher why the Russian film doesn t talk about climate change, one has to view it from the prism of what their leader Vladimir Putin has said and done over the years. As can be seen even in there, the situation is far more complex than one imagines. Although, it is interesting to note that he decried Climate change as man-made till as late as last year and was on the side of Trump throughout his presidency. This was in 2017 as well as perhaps this. Interestingly, there was a change in tenor and note just a couple of weeks back, but that could be only politicking or much more. Statements that are not backed by legislation and application are usually just a whitewash. We would have to wait to see what concrete steps are taken by Putin, Kremlin, and their Duma before saying either way.
Civil Aviation and the broad structure
Civil Aviation is a large topic and I would not be able to do justice to it all in one article/blog post. So, for e.g. I will not be getting into Aircraft (Boeing, Airbus, Comac etc., etc.) or the new electric aircraft as that will just make the blog post long. I will not be also talking about cargo or Visa or many such topics, as all of them actually would and do need their own space. So this would be much more limited to Airports and to some extent airlines, as one cannot survive without the other. The primary reason for doing this is there is and has been a lot of myth-making in India about Civil Aviation in general, whether it has to do with Civil Aviation history or whatever passes as of policy in India.
A little early history
Man has always looked at the stars and envisaged himself or herself as a bird, flying with gay abandon. In fact, there have been many paintings, sculptors who imagined how we would fly. The Steam Engine itself was invented in 82 BCE. But the attempt to fly was done by a certain Monk called Brother Elmer of Malmesbury who attempted the same in 1010., shortly after the birth of the rudimentary steam engine The most famous of all would be Leonardo da Vinci for his amazing sketches of flying machines in 1493. There were a couple of books by Cyrano de Bergerac, apparently wrote two books, both sadly published after his death. Interestingly, you can find both the book and the gentleman in the Project Gutenberg archives. How much of M/s Cyrano s exploits were his own and how much embellished by M/S Curtis, maybe a friend, a lover who knows, but it does give the air of the swashbuckling adventurer of the time which many men aspired to in that time. So, why not an author???
L Autre Monde: ou les tats et Empires de la Lune (Comical History of the States and Empires of the Moon) and Les tats et Empires du Soleil (The States and Empires of the Sun). These two French books apparently had a lot of references to flying machines. Both of them were authored by Cyrano de Bergerac. Both of these were sadly published after his death, one apparently in 1656 and the other one a couple of years later.
By the 17th century, while it had become easy to know and measure the latitude, measuring longitude was a problem. In fact, it can be argued and probably successfully that India wouldn t have been under British rule or UK wouldn t have been a naval superpower if it hadn t solved the longitudinal problem. Over the years, the British Royal Navy suffered many blows, one of the most famous or infamous among them might be the Scilly naval disaster of 1707 which led to the death of 2000 odd British Royal naval personnel and led to Queen Anne, who was ruling over England at that time via Parliament and called it the Longitude Act which basically was an open competition for anybody to fix the problem and carried the prize money of 20,000. While nobody could claim the whole prize, many did get smaller amounts depending upon the achievements.
The best and the nearest who came was John Harrison who made the first sea-watch and with modifications, over the years it became miniaturized to a pocket-sized Marine chronometer although, I doubt the ones used today look anything in those days. But if that had not been invented, we surely would have been freed long ago. The assumption being that the East India Company would have dashed onto rocks so many times, that the whole exercise would have been futile. The downside of it is that maritime trade routes that are being used today and the commerce would not have been. Neither would have aircraft or space for that matter, or at the very least delayed by how many years or decades, nobody knows. If one wants to read about the Longitudinal problem, one can get the famous book Longitude .
In many mythologies, including Indian and Arabian tales, in which we had the flying carpet which would let its passengers go from one place to the next. Then there is also mention of Pushpak Vimana in ancient texts, but those secrets remain secrets. Think how much foreign exchange India could make by both using it and exporting the same worldwide. And I m being serious. There are many who believe in it, but sadly, the ones who know the secret don t seem to want India s progress. Just think of the carbon credits that India could have, which itself would make India a superpower. And I m being serious.
Western Ideas and Implementation.
Even in the late and early 18th century, there were many machines that were designed to have controlled flight, but it was only the Wright Flyer that was able to demonstrate a controlled flight in 1903. The ones who came pretty close to what the Wrights achieved were the people by the name of Cayley and Langley. They actually studied what the pioneers had done. They looked at what Otto Lilienthal had done, as he had done a lot of hang-gliding and put a lot of literature in the public domain then.
Furthermore, they also consulted Octave Chanute. The whole system and history of the same are a bit complicated, but it does give a window to what happened then. So, it won t be wrong to say that whatever the Wright Brothers accomplished would probably not have been possible or would have taken years or maybe even decades if that literature and experiments, drawings, etc. in the commons were not available. So, while they did experimentation, they also looked at what other people were doing and had done which was in public domain/commons.
They also did a lot of testing, which gave them new insights. Even the propulsion system they used in the 1903 flight was a design by Nicolaus Otto. In fact, the Aircraft would not have been born if the Chinese had not invented kites in the early sixth century A.D. One also has to credit Issac Newton because of the three laws of motion, again without which none of the above could have happened. What is credited to the Wilbur brothers is not just they made the Kitty Hawk, they also made it commercial as they sold it and variations of the design to the American Air Force and also made a pilot school where pilots were trained for warfighting. 119 odd pilots came out of that school. The Wrights thought that air supremacy would end the war early, but this turned out to be a false hope.
Competition and Those Magnificent Men and their flying machines
One of the first competitions to unlock creativity was the English Channel crossing offer made by Daily Mail. This was successfully done by the Frenchman Louis Bl riot. You can read his account here. There were quite a few competitions before World War 1 broke out. There is a beautiful, humorous movie that does dedicate itself to imagining how things would have gone in that time. In fact, there have been two movies, this one and an earlier movie called Sky Riders made many a youth dream. The other movie sadly is not yet in the public domain, and when it will be nobody knows, but if you see it or even read it, it gives you goosebumps.
World War 1 and Improvements to Aircraft
World War 1 is remembered as the Great War or the War to end all wars in an attempt at irony. It did a lot of destruction of both people and property, and in fact, laid the foundation of World War 2. At the same time, if World War 1 hadn t happened then Airpower, Plane technology would have taken decades. Even medicine and medical techniques became revolutionary due to World War 1. In order to be brief, I am not sharing much about World War 1 otherwise that itself would become its own blog post. And while it had its heroes and villains who, when, why could be tackled perhaps another time.
The Guggenheim Family and the birth of Civil Aviation
If one has to credit one family for the birth of the Civil Aviation, it has to be the Guggenheim family. Again, I would not like to dwell much as much of their contribution has already been noted here.
There are quite a few things still that need to be said and pointed out. First and foremost is the fact that they made lessons about flying from grade school to college and afterward till college and beyond which were in the syllabus, whereas in the Indian schooling system, there is nothing like that to date. Here, in India, even in Engineering courses, you don t have much info. Unless until you go for professional Aviation or Aeronautical courses and most of these courses cost a bomb so either the very rich or the very determined (with loans) only go for that, at least that s what my friends have shared. And there is no guarantee you will get a job after that, especially in today s climate.
Even their fund, grants, and prizes which were given to people for various people so that improvements could be made to the United States Civil Aviation. This, as shared in the report/blog post shared, was in response to what the younger child/brother saw as Europe having a large advantage both in Military and Civil Aviation. They also made several grants in several Universities which would not only do notable work during their lifetime but carry on the legacy researching on different aspects of Aircraft.
One point that should be noted is that Europe was far ahead even then of the U.S. which prompted the younger son. There had already been talks of civil/civilian flights on European routes, although much different from what either of us can imagine today. Even with everything that the U.S. had going for her and still has, Europe is the one which has better airports, better facilities, better everything than the U.S. has even today. If you look at the lists of the Airports for better value of money or facilities, you would find many Airports from Europe, some from Asia, and only a few from the U.S. even though they are some of the most frequent users of the service. But that debate and arguments I would have to leave for perhaps the next blog post as there is still a lot to be covered between the 1930s, 1950s, and today. The Guggenheims archives does a fantastic job of sharing part of the story till the 1950s, but there is also quite a bit which it doesn t. I will probably start from that in the next blog post and then carry on ahead.
Lastly, before I wind up, I have to share why I felt the need to write, capture and share this part of Aviation history. The plain and simple reason being, many of the people I meet either on the web, on Twitter or even in real life, many of them are just unaware of how this whole thing came about. The unawareness in my fellow brothers and sisters is just shocking, overwhelming. At least, by sharing these articles, I at least would be able to guide them or at least let them know how it all came to be and where things are going and not just be so clueless. Till later.