Sunday, September 28, 2025
Thursday, August 1, 2024
Analyzing CSV files using SQL with Squirrel SQL client and Apache Calcite JDBC driver
Intro
The JDBC driver
The way this driver works is that instead of the database name, we have to point to a JSON file that defines the database model. This file will in turn specify a directory that holds the csv files. And all the csv files under that directory will be considered as tables in that model. The CSV files need to have a header for column names.
The SQL client
Installation
Configuring the client
As you see, its a schema created using the CsvSchemaFactory, that points to the directory holding our Csv files.
Sunday, July 28, 2024
Analyzing CSV files with SQL using Squirrel SQL Client and csvjdbc driver
Note
Hola. So being an SQL fan, i somehow find it much easier to work on Excel files in SQL, rather than Excel itself. SQL is so beautiful, so easy, yet so powerful !
The JDBC driver
Firstly, we need a JDBC driver that can read CSV files. I am using the one from https://github.com/simoc/csvjdbc. Its read-only, and that's okay for me, since i only wish to analyze the files. The jar can be downloaded from maven : https://mvnrepository.com/artifact/net.sourceforge.csvjdbc/csvjdbc/1.0.42
The way this driver works is that instead of the database name, we need to specify a directory that holds the csv files. And all the csv files under that directory will be considered as tables in that database. The CSV files need to have a header for column names. The separator can be mentioned in the jdbc url.
The SQL client
Installation
Configuring the client
Wednesday, November 1, 2023
IOT with the Raspberry Pi Pico
A few months ago, I got a requirement for a POC, to create a system to monitor an UPS. The inverter would provide its status, e.g. "Mains On", "Inverter On", "Battery Voltage", "Mains High", "Mains Low" etc. over a RS232 serial port. We had to read it and send it over the net to our website where the data would be stored and monitored. The readings were to be taken every 1 minute.
The Microcontroller
- Its a powerful microcontroller board, with many IOs including UART ports.
- It has a Pico W version, which comes with WiFi connectivity.
- Its cheap.( The base version is around Rs 350)
- It can be programmed with MicroPython, which is much easier to program in than C, and the Thonny IDE is very user friendly. Kudos to the MicroPython and Thonny devs !
Development
- As a USB storage device. This mode will be used only once at the start, to copy the Micropython image to the Pico's internal storage. This is necessary to support the Micropython programming environment.
- As a USB device that interacts with the Thonny IDE to develop and test the Micropython programs.
Some Gotchas
- Voltage compatibility - The serial port signals were 0-5V, whereas the Pico's IO, like the Pi, is 0-3.3V. There are various solutions for this, from transistors to chips, but I did it with a resistive voltage divider, since the RS232 baud rate used was low.
- Male and Female pinout differences - This may not be immediately clear, but is obvious when you think of it. Male and Female pinouts are different, since Rx in one has to go to Tx in another and so on. So lookup the pinout as per the type of socket.
- UART parameters matching - When you initialize the Pico's UART, make sure that its parameters like baud-rate, parity, start-stop bits match that of the port you are interfacing with.
- Reads and timeouts - If you read multiple bytes at a time, and it times out, you may be get lesser data than what you asked for.
- Sleeps - Sleeps in between can make you miss data that is being sent in a stream.
- Micropython differences - Since Micropython is not the full python version, you will not have some commonly used classes, e.g. not all data structures are available.
Tuesday, August 22, 2023
Git for Svners
Since Git is a distributed repository system, each developer has his own repository, that keeps track of local changes, as well as can sync with one or multiple remote repositories. Hence the concepts of Git are rather different from SVN, and the same terms like checkout mean different things in SVN and GIT. Being an SVNer earlier, i too found Git frustrating to start with.
Atlassian has a good tutorial that explains these concepts :
https://www.atlassian.com/git/tutorials/learn-git-with-bitbucket-cloud
Some important concepts :
- The local repository is a full fledged repository, and independently holds a history of its own branches, commits etc. One could create and work with a local repository, without ever connecting to a remote repository, say for some private work that is not shared.
- We usually start by cloning a remote repository to a local one. See clone. This creates a copy of the remote repository to the local, as well as adds a reference to the remote repository usually as "origin" to the local repo's list of remotes( See the remote command). Thus, when syncing with the original repository, we can specify it as "origin".
- The checkout command does NOT checkout files from remote. Instead it checks out the specified branch to the working directory. i.e. that branch now becomes the current one.
- GIT has a staging area where the changes to be committed are kept. We specify which files are to be staged by using the add command. Without adding, the commit command will have nothing to work on.
- When you push your changes to the remote, you are syncing changes committed in your local repo to the remote one. So you must have committed them first to your local repo. This may not be obvious to SVNers, who would expect the locally updated files to be automatically pushed !
- TODO : See the branch command
- Unlike SVN, we do not need separate working folders for branches. We can switch to another branch in the same working folder, using the checkout command. This means that uncommitted changes can be lost, unless we stash them to a temp location.
Maven for ANTers
So here's a quick summary :
- Maven executes Goals, just like Ant has targets.
- In addition, maven has Phases, each phase being a list of goals. We can also tell maven to execute one or more phases, and then each phase will execute the goals grouped under it. Phases themselves have an order, so that if we execute a given phase, the phases coming before that in the predefined order will be executed first.
- The default phases are validate, compile, test, package, verify, install, deploy.
- Each maven execution run happens in a lifecycle, which has phases under it. The default lifecycles are default, clean and site.
- We can create and define our custom goals. These are packaged in a Plugin.
- Maven also allows us to specify and manage dependencies of the project.
- Maven resources have a groupId, artifactId and version.
- Maven provides for a repository to fetch/store the artifacts. A central maven repository is the default .Also, maven keeps a local repository on the system where its run, to avoid fetching from the remote repository each time.
See also https://www.baeldung.com/maven-goals-phases
Read these links first for a basic understanding :
https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
In ANT, we specify tasks and their dependencies. We can execute a specific task, and only that, along with its specified dependent tasks will be executed. But this also means that tasks like clean, compile, generate, copy, package, install, deploy etc have be specified in details for all projects, along with config like source, staging, target dirs etc. Also external dependencies like jars have to be managed, along with their versions. These may be common amongst multiple projects. Should we check these into source control, or have a separate common location ? What if we want to add a common functionality to all builds ? How do we name and version output artifacts ?
Maven tries to answer these questions. It tries to provide a standard way to execute projects, by promoting convention over configuration :
- Standardized project directory structure. e.g. The src/main/java, src/main/resources src/test etc
- Naming conventions for articfacts using groupid, artifactid, version
- Providing a dependency configuration, and a repository mechanism to store and access needed dependencies
- Out-of-the box implementation of standard build lifecycle, so that a project can be build with minimum configuration
- An inheritance mechanism, so that a build may be shared amongst multiple projects, each overriding only the parts needed.
- Profiles to have different builds for different case, e.g we might just need compile in dev mode, and the full jar with dependencies may have to be built in production mode.
So if we have a simple java project with no dependencies, then a minimal pom with just the groupid, artifactid and version id will be able to build the project from clean to deploy.
Maven works with lifecyles, phases and goals. It has default implementations of these. We can also create our own lifecycles, which is a list of phases, in order. Then there are goals, that execute in a particular phase which do the actual work. e.g. in the default lifecycle, the install phase has a goal install:install.
Goals are usually implemented using java classes called plugins. When creating plugins, we can specify what phase the plugin should execute, tho its not mandatory. The phase in which a plugin executes can also be specified via the build configuration, and this will override the default.
What can we execute with the maven command ?
e.g. we can execute just the install goal using mvn instal:install, instal:install being the name of the goal in the install phase. Earlier phases will not be run. However, it can cause problems like in this case, since this goal looks for the anme of the output jar to install in the execution context, which is missing. In this case, it can be remedied by also installing the jar:jar goal before, so that it gets the jar name.
What does the maven build file consist of ?
- The groupid, artifactid and version id of the project being built, this the minimal info needed.
- The list of dependencies needed by the project.
- The list of dependency repositories, if using any other than the standard maven one.
- The list of repositories if any, to deploy/publish the final artifact( usually jar, war etc)
- The build section to use and configure non-standard maven plugins, in which phase and with what params are they to run. Similarly to customise/change execution of the standard maven plugins.
- A profiles
Saturday, April 9, 2022
What to watch on Prime Video
Movies
English
Youth
The Unbearable Weight of Massive Talent
Dune
Kimi
The tender bar
Notting Hill
Many Tom Cruise movies, including the MI series
Many James Bond movies
Pride and Prejudice
Sense and Sensibility
The Matrix
The Jurrasic movies
The Harry Potter movies
The Lord of the rings
The tomorrow war
Before I fall
2067
Another round
Indian
Sharmaji Namkeen
Sherni
Missing
Bonus
Dev bhoomi
Series
Thursday, January 27, 2022
Using a tplink router as wireless bridge to extend range
- Reset the new router
- Connect to it via WIFI using the default SSID and password given on the back, or WPA
- Login to the new router, at its default I.P, e.g. 192.1681.0.1 or http://tplinkwifi.net/
- You need to create a password at the first login
- Choose the range extender option
- Select your main network from the list
- Choose static I.P and use an I.P in the same subnet as the main router. E.g. if the main router is at 192.168.1.1, you can choose any 192.168.1.*
- Disable DHCP server
- If WPA_PSK does not work, try WPA2_PSK. This was the issue for me.
- Restart and check that the internet light is green
Monday, December 20, 2021
Docker stuff
Removing all docker containers in one go
docker container rm `docker ps -a | cut -f 1 -d " " | tr "\n" " "`
We are using command line substitution with the ``, and populating the container ids inside it. The cut gets the first field from docker ps, that is the id, and the tr replaces the newline with a space, so that we get all ids in a single line.
Btw, this will also work in the new Linux Subsystem for Windows(LSW) command line, its able to see the docker container created from windows command line.
Saturday, December 4, 2021
A simple timer switch using a potentiometer
A draft, not yet complete...
A digital timer that uses a potentiometer and ADC to select a time interval. The input triggering circuit is isolated from the mains using an optocoupler.
BT136 triac
MOC3061 optocoupler
pic12f675 - the cheapest microcontroller i could find, with an ADC.
The potentiometer is missing in the circuit below, its connected to the ADC
For the source code, see https://github.com/manojmo/pic_micro/blob/master/pot_minutes_calc.c
Based on the potentiometer voltage read from the ADC, it calculates the ON time, turns on the triac, waits till the ON time expires, then turns OFF the triac.
Monday, August 26, 2019
Useful online sites/services
SQL Fiddles
It happens that we want to test sql on a particular db, and do not have it installed.There are sites which provide us a testing environment for various databases. e.g.
Note that some sites may consider whatever you submit to be under commons creative license.
https://dbfiddle.uk/ ( This one has mariadb too )
http://www.sqlfiddle.com/#!3/e48975/1
Monday, August 12, 2019
Editing tips
Select Code Block
Thursday, August 1, 2019
Starting with Sails.js
On a side note, while Node is noted for its performance in handling I/O bound tasks, there are async frameworks in the Python world too like gevent and asyncio and uvloop, which can do the same, and there are some comparsions : https://magic.io/blog/uvloop-blazing-fast-python-networking/
Development wise, i think i would prefer python over Javascript.
Anyways, on to sails :
So i installed node and sails 1.1 and fired the app with sails lift. Its nice to have some example models and setup running like sails has, so we can get started quickly.
Though sails does not generate CRUD from the database, there is a sails-inverse-model module that does a basic CRUD generation. Haven't tested end to end tho.
I made some changes to the User model, added another model.
Then i wanted to point the default file-based database to my local mysql. Accordingly i toddled over to the config/datastores.js and made the necessary changes. Restarted sails and got a nasty shock ! There was a big stack trace about some auto-migration and some error about being unable to insert data. But i hadn't setup any migration. Seems that sails has a facility to apply to latest moel changes to the database, to keep the database in sync with the models. This is called migration, and is set to 'alter' by default in the config/models.js. This alter mode drops and recreates tables instead of altering them ! I fell this is a very dangerous behaviour, and should be been turned off by default.
So first thing, set migration to 'safe', or risk losing your data !
The next problem i faced was that my changes to the User model were not being reflected, and i was getting and error on account of that. I thought it might be some sort of caching. But restart or deleting the temp folder did not help either. Neither could i find any such issues reported on the internet. Finally, when looking at the files, i saw that there was a User.js~ backup file created by jedit, and this had the old User model that was getting picked up. Apparently the filter to load the files is too lenient, it will even allow a *.xml extension as a model.
In order to see where the files were being loaded, i created a syntax error in the model file. Sure enough, Sails complained about the error, and i saw from the error trace that it was being done in (node_modules/sails/lib/hooks/moduleloader/index.js:304:18). Adding a [^~]$ at the end of the regex fixed the loading-backup-files issue at least.
Another issue was about having to restart sails after every change, which is really irritating. I saw options like forever, nodemon and sails-hook-autoreload. I tried the auto-reload-hook, but it seems to trigger the auto-migration again, so i removed it. I tried forever, one issue is that the stop does not work. Also, difficult to see logs, and if there are errors, it crashes. Still to check out.
Trying to get the hang of files. Did not like the actions approach, where each action lives in a separate file, rather than all in a controller. But the controller with methods approach is also supported. Tried using the ajax-form from parasails as in the examples. However, my form was not being rendered. Read about the client asset js file, and how we need to add one and register the page there, and write form validations. What about server-side validations, these would need to be repeated there too ? There should be a way to share them. And the default layout is updated to load all of these client files at once ! Why not include the required one in the particular view instead ?
Model objects are global, tho there seems to be a setting to control this. I like to know what i am importing.
Overall, sails seems to be doing too much implicitly, and if something is not working, finding and changing the behaviour takes a lot of time. I also wonder whether how all this affects performance. The Waterline ORM has its limitations like not fetching associations data. Also, what about all those facilities like default apis, one would need to know how to turn them off. I think i would prefer to go with something minimal like express, rather than sails.
On the positive side, sails comes with responsive ui and ready-to-go facilities.
It seems that sails comes with an auto-generator, and just by defining a model, we can expose the model's api as json.
Tuesday, July 30, 2019
Single Page Applications, Server vs Client-side, Ej, React, Vue, Angular
Traditionally, typical web-applications followed the Model, View, Controller pattern, with all of these written on the server side. So a java based app would have the views in some java-related technology like JSP or JSF. Also the routing logic by the controller was in the same technology. Similarly, in a PHP app, it would all be in PHP.
Probably with the advent of AI/ML/Analytics, languages like python became the choice for those kind of applications, due to the extensive libraries/frameworks available.
So if I wanted to move from my Java application to python, I would need to rewrite not just the models, but the controllers and views too in python.
So people started thinking, could we not separate the UI part, and make it independent of the backend ? Enter the SPAs.
Single Page applications are so called because they keep all the UI and routing logic as one bundle( page) loaded once in the browser(might be split if its too large), and subsequently, no UI has to be loaded from the server. Also, usually the routing, i.e controller logic is in the same bundle and not on the server side. Other than loading the UI quickly, without page refreshes apparent to the user, another advantage is re-usability. The UI has been detached from the server side code, and communicates with the server-side thru http apis for the business logic. As long as the apis produce the same output, the server-side tech-stack can be changed, without affecting the UI part.
Some of challenges for SPAs are :
- Search engine optimization : UI pages are not really urls on the server-side, but just one javascript resource containing all the UI/routing content, and hence are not available in the traditional way to the search engines. One solution may be to render the pages that need to be indexed, on the server side, and the others on the client.
- Initial load times : Can be high for SPAs, since all UI pages are loaded in one go on the browser.
- The server side APIs exposed for the use of the SPA also become available for everyone, and increase the chance of hacking or un-authorized use. Also, since javascript for the controllers and views can be hacked thru javascript, one needs to be more careful in validating the flow on server-side as well.
What are native mobile apps ?
Native means written for a particular platform using its tools/SDK, like Swift for iOS, java for Android etc. There are also frameworks like React Native, that will generate a native app from code written in web like technologies i.e.html-js.
A hybrid app is a web-app that can access some but not all native functionality. It uses a sort of bridge component that can invoke native functionality.
What is <script type="text/template">some html</script>
It will be ignored by the browser for rendering. It is used to define an html template into which values can be substituted to create html on the fly,e.g. adding a new row to a table, by client side templating frameworks like Vue, React etc. Nothing new here, it was possible since a long time to add user-defined xml, (not just under the script tag ) into a page and use it this way.
Tuesday, July 23, 2019
Router Port Forwarding
Your P.C is usually going to be behind a router, so the internet knows only the address of the router and not your P.C. Your router is keeping your internal network separate from the internet. The router has two I.P.s, an internal one to communicate with the internal network, and an external one to communicate with the internet.
You also should have a firewall setup on your router to not allow any incoming traffic to your internal network.
But suppose you do want to expose an application on your P.C. to the internet, how to go about it ?
The internet knows only the router's external I.P. So obviously, that has to be used.
We need to configure what is called "Port Forwarding" on the router. What it allows us to do is redirect an incoming request to the router on a particular port to the same/another port on some machine in the internal network.
So for example, i might setup forwarding such that a request to http://router-external-ip:8080 is redirected to my P.C 192.168.1.200:80, thus making my application running at 192.168.1.200:80 available to the internet.
Note that the firewall rules may have to be changed to allow the incoming traffic, preferably restricted to the external address making the request, and the port being used.
There are sites online that will allow you to test whether the port forwarding is working or not, e.g. https://www.yougetsignal.com/tools/open-ports/
If you are getting connection refused errors, check that the firewall on the P.C allows the incoming call, as well as the firewall on the internet host that is making the call. E.g if its hosted, the hosting provider may have opened default ports like 80, but blocked others like 8080 for outgoing calls.
Tuesday, May 21, 2019
Eye-friendly dark styling for the browser
I can think of 2 possible approaches to achieve this :
- Setting a web-proxy in the browser settings, and manipulating HTML thru the proxy. The problem is with https traffic which is encrypted and cannot be read/changed in between. There are proxy servers like https://www.charlesproxy.com/ which get around this by generating their own certificates.
- Using a JS browser plugin/extension, which allows us to execute JS/inject CSS on the fly after the page loads. Stylish was one such user extension, which allowed custom styles. However, it had issues with snoooping on your data, so i decided not to go with it. Stylus seems to be another alternative. But doing it via javascript is more powerful. I had written one such extension for chrome : https://chrome.google.com/webstore/detail/onload-scripts/gddicpebdonjdnkhonkkfkibnjpaclok
UPDATE : The mutationsObserver seems to take too much time on FB.
The evenlistener seems to work well.
document.addEventListener("DOMNodeInserted", function(e) {
//console.log( "DNI" + e);
anode = e.target;
if( anode.tagName && (anode.tagName.toLowerCase() == 'div' || anode.tagName.toLowerCase() == 'span' || anode.tagName.toLowerCase() == 'td')){
setbgcolor(anode);
}
},
false);
let css = document.createElement('style');
css.type = 'text/css';
if (css.styleSheet) css.styleSheet.cssText = rule; // Support for IE
else css.appendChild(document.createTextNode(rule)); // Support for the rest
document.getElementsByTagName("head")[0].appendChild(css);
}
var bgcolor = 'lightgray';
function setbgcolor( elem){
// Don't change if first child elem is image. For sites like FB
if( ! elem.firstElementChild || (elem.firstElementChild && elem.firstElementChild.tagName.toLowerCase() != 'img') ){
elem.style.backgroundColor = bgcolor;
//console.log( "ONLS:" + elem.outerHTML);
}
}
// divs with images
var allDivs = document.getElementsByTagName("div");
for( var i=0; i< allDivs.length; i++){
var currDiv = allDivs[i];
setbgcolor(currDiv);
}
// CSS rules
let rule = 'body {background-color: ' + bgcolor + '} ';
//rule += 'div {background-color: ' + bgcolor + '} ';
rule += 'pre {background-color:' + bgcolor + '} ';
rule += 'td {background-color:' + bgcolor + '} ';
addCss(rule);
// Select the node that will be observed for mutations
var targetNode = document.getElementsByTagName('body')[0];
// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true, subtree: true };
// Callback function to execute when mutations are observed
var callback = function(mutationsList, observer) {
for(var mutation of mutationsList) {
if (mutation.type == 'childList') {
for (var i = 0; i < mutation.addedNodes.length; i++) {
var anode = mutation.addedNodes[i];
//console.log( "ONLSMO" + anode.tagName + anode.id );
if( anode.tagName && anode.tagName.toLowerCase() == 'div' || anode.tagName.toLowerCase() == 'span' || anode.tagName.toLowerCase() == 'td'){
setbgcolor(anode);
}
}
}
}
};
// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
// Later, you can stop observing
//observer.disconnect();
Monday, May 20, 2019
Relationships in sqlalchemy
This post will cover only a small portion of working with relationships.
What are the advantages of relationships ?
They allow us to query data of related objects along with the main object.This can be done via a join, or separate queries, either eagerly, or lazily( when the related object is accessed)
Also, they make it easy to insert/delete/update data into related tables, especially in case of OTM/MTMs
Sample Entities
Consider the entities defined below :----
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
addresses = relationship("Address", back_populates="user")
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
city = Column(String(50))
street = Column(String(50))
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship("User", back_populates="addresses")
----
Here, a user can have many addresses, reflected by the addresses relationship. An address on the other hand, belongs to a single user, reflected by the user relationship.
Sample Data
Consider the following data :ed_user = User(name='Edward')
ed_user.addresses = [ Address(city='Pune'), Address(city='Mumbai')]
bob_user = User(name='Bob')
bob_user.addresses = [ Address(city='Pune'),Address(city='Delhi')]
session.add(ed_user)
session.add(bob_user)
Creating the tables
engine = create_engine('sqlite:///:memory:') # Memory engine
Logging of sqls can be enabled with :
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
Test Scenarios
All Users, with all addresses
Users with a Mumbai address, Mumbai addresses only
However, this will filter user, not addresses, so we will get non-Mumbai addresses too for each user.
All Users, Mumbai addresses only
**Actually, with a contains_eager, one would expect to get only the User entity, with the address as a related entity. There are some inconsistencies or difficult to understand usages. Dropping the add_entity above, leads to a single User entity in the output.
All Users with Delhi address, all addresses
Friday, April 26, 2019
Interesting reads
Using java 8 features :
https://dzone.com/articles/functional-programming-patterns-with-java-8Understanding time complexity :
https://adrianmejia.com/blog/2018/04/05/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/Async with Lightweight threads in java
http://blog.paralleluniverse.co/2014/02/06/fibers-threads-strands/Go vs Java concurrency example of fetching urls :
https://dev.to/napicellatwit/go-for-java-developers-or-is-the-java-concurrency-that-bad-6ffProfiling Javscript/Node applications
https://marmelab.com/blog/2018/04/03/how-to-track-and-fix-memory-leak-with-nodejs.htmlSunday, March 17, 2019
A rant against annotations
E.g. using spring/hibernate annotations in a class tie that class to that framework. What if i later want to change from hibernate to something else ? I will have to change the source code.
Consider the following case of a service class CustomerService using a customerDao. The dao uses something @Component(name='customerDao'),
and its injected into the service as @Resource(name='customerDao')
Lets say that this Dao uses hibernate. Later on, we decide to change the dao to use JdbcTemplate instead of hibernate. But i want to keep the hibernate implementation as well. And maybe, i need to use both of them in different places. So i now have a new customerDaoSpTpl say. But the service code now needs to be changed in order to use this new customerDaoSpTpl. So did we really achieve DI, if we needed to change the service class using the dao ?
The problem is due to annotations. We are putting stuff in a class, that does not really belong in a class definition, but is about the wiring or interaction of classes.
There are also issues when old classes from a jar are to be replaced with new ones, the annotation processor can fire annotations for both. ( There probably is some exclude facility for the annotation processor ) The names used in annotated classes from a jar can't be changed either.
Ideally the wiring should be kept separate from the class definition.
Spring does support this, thru xml as well as a java annotations format, but everyone seems to be putting annotations into source code, because thats easier to use upfront.
One disadvantage of having a single separate source for wiring maybe that it has frequent changes and always needs merging when checking in.
Saturday, March 9, 2019
Distributing the database
And it would be nice to have the querying and integrity features of an RDBMS.
Assuming that we want to shard data, and not just have a replica,
Some questions arise :
- How easy would it be to add a new node ?Should sharding be automatic, or per some partitioning rules ? If as per rules, what happens when we add/remove nodes, the data will need to be redistributed.
- If a table is distributed across nodes, what happens to primary key ids ? How to prevent duplicates across nodes ? Id ranges ?
- One major use of ids as primary keys is for use in foreign key constraints. But will a distributed table support foreign keys ? Probably not.
- Will ACID transactions be available ?
Found some open-source solutions to scale RDBMS :
- CockroachDB (https://www.cockroachlabs.com/) : A key-value store that supports the wire-protocol of Postgresql, sql, ACID transactions etc. So it behaves as if its a distributed postgresql to the sql drivers, but internally is not.
- Citus : https://www.citusdata.com : A Postgresql extension that allows us to scale Postgresql. The underlying db is indeed postgresql. However, not all postgresql features can be supported in distributed mode.
- Posgres-XL (https://www.postgres-xl.org/overview/)