{"id":9713,"date":"2011-09-07T07:00:00","date_gmt":"2011-09-07T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/09\/07\/why-is-the-registry-a-hierarchical-database-instead-of-a-relational-one\/"},"modified":"2011-09-07T07:00:00","modified_gmt":"2011-09-07T07:00:00","slug":"why-is-the-registry-a-hierarchical-database-instead-of-a-relational-one","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110907-00\/?p=9713","title":{"rendered":"Why is the registry a hierarchical database instead of a relational one?"},"content":{"rendered":"<p>\nCommenter ton asks\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2009\/02\/05\/9397154.aspx#9399358\">\nwhy the registry was defined as a hierarchical database instead of\na relational database<\/a>.\n<\/p>\n<p>\nHeck, it&#8217;s not even a hierarchical database!\n<\/p>\n<p>\nThe original registry was just a dictionary;\ni.e., a list of name\/value pairs, accessed by name.\nIn other words, it was a <i>flat<\/i> database.\n<\/p>\n<table BORDER=\"1\" STYLE=\"border-collapse: collapse\">\n<tr>\n<td><tt>.txt<\/tt><\/td>\n<td><tt>txtfile<\/tt><\/td>\n<\/tr>\n<tr>\n<td><tt>txtfile<\/tt><\/td>\n<td><tt>Text Document<\/tt><\/td>\n<\/tr>\n<tr>\n<td><tt>txtfile\\DefaultIcon<\/tt><\/td>\n<td><tt>notepad.exe,1<\/tt><\/td>\n<\/tr>\n<tr>\n<td><tt>txtfile\\shell<\/tt><\/td>\n<td><tt>open<\/tt><\/td>\n<\/tr>\n<tr>\n<td><tt>txtfile\\shell\\open\\command<\/tt><\/td>\n<td><tt>notepad %1<\/tt><\/td>\n<\/tr>\n<\/table>\n<p>\nIf you turned your head sideways and treated the backslashes as\nnode separators, you could sort of trick yourself into believing\nthat this resulted in something vaguely approximating\na hierarchical database,\nand a really lame one at that (since each node held only one piece\nof data).\n<\/p>\n<p>\nWhen you choose your data structures, you necessarily are guided\nby the intended use pattern and the engineering constraints.\nOne important engineering constraint was that you have to minimize\nmemory consumption.\nAll of the registry code fit in 16KB of memory.\n(Recall that Windows 3.1 had to run on machines with only 1MB of memory.)\n<\/p>\n<p>\nOkay, what is the usage pattern of the registry?\nAs originally designed, the registry was for recording information\nabout file types.\nWe have the file types themselves (<code>txtfile<\/code>),\nproperties about those file types (<code>DefaultIcon<\/code>),\nverbs associated with those file types (<code>open<\/code>),\nand verb implementations (<code>command<\/code> or <code>ddeexec<\/code>).\nSome verb implementations are simple (<code>command<\/code> involves\njust a single string describing the command line);\nothers are complex (<code>ddeexec<\/code> requires the execute string,\nthe application, and the topic, plus an optional alternate execute string).\n<\/p>\n<ul>\n<li>Given a file type and a property, retrieve the value of that\n    property.<\/p>\n<li>Given a file type and a verb, retrieve information about how to\n    perform that verb.<\/p>\n<li>The set of properties can be extended.\n<li>The set of property schemata can be extended.\n<li>The set of verbs can be extended.\n<li>The set of verb implementations can be extended.\n<\/ul>\n<\/p>\n<p>Since the properties and verb implementations can be extended,\nyou can&#8217;t come up with a single schema that covers everything.\nFor example, over the years, new file type properties have been\nadded such as <code>ContentType<\/code>,\n<code>OpenWithList<\/code>,\nand <code>ShellNew<\/code>.\nThe first one is a simple string;\nthe second is\n<a HREF=\"http:\/\/msdn.microsoft.com\/bb166549.aspx\">\na list of strings<\/a>,\nand the third\nis\n<a HREF=\"http:\/\/msdn.microsoft.com\/cc144101.aspx#new\">\na complex key with multiple variants<\/a>.\nMeanwhile, additional verb implementations have been added,\nsuch as\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/05\/03\/10006065.aspx\">\n<code>DropTarget<\/code><\/a>.\n<\/p>\n<p>\nGiven the heterogeneity of the data the registry needs to keep track of,\nimposing some sort of uniform schema is doomed to failure.\n<\/p>\n<p>\n&#8220;But you can just update the schemata each time the registration is\nextended.&#8221;\n<\/p>\n<p>\nThat creates its own problems.\nFor example, to support\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/06\/30\/434209.aspx\">\nroaming user profiles<\/a>,\nyou need a single registry hive to work on multiple versions of the\noperating system.\nIf version N+1 adds a new schema, but then the profile roams to a\nmachine running version&nbsp;N,\nthen that registry hive will be interpreted as corrupted since it\ncontains data that matches no valid schema.\n<\/p>\n<p>\n&#8220;Well, then include the schemata with the roaming profile so that\nwhen the older operating system sees the hive, it also sees the\nupdated schemata.&#8221;\n<\/p>\n<p>\nThis is trickier than it sounds, because when the profile roams to\nthe newer operating system, you presumably want the schemata to be\nupgraded and written back into the user profile.\nIt also assumes that the versioning of the schemata is strictly linear.\n(What if you roam a user profile from a Windows&nbsp;XP machine\nto a Server&nbsp;2003 machine? Neither is a descendant of the other.)\n<\/p>\n<p>\nBut what kills this proposal is that it makes it impossible for a program\nto &#8220;pre-register&#8221; properties for a future version of the operating system.\nSuppose a new schema is added in version&nbsp;N+1,\nlike, say, the IDropTarget verb implementation.\nYou write a program that you want to run on version&nbsp;N as well as\non version&nbsp;N+1.\nIf your installer tries to register the version&nbsp;N+1 information,\nit will fail since there is no schema for it.\nBut that means that when the user upgrades to version&nbsp;N+1,\nthey don&#8217;t get the benefit of the version&nbsp;N+1 feature.\nIn order to get the version&nbsp;N+1 feature to work, they have to\nreinstall the program so the installer says,\n&#8220;Oh, now I can register the version&nbsp;+1 information.&#8221;\n<\/p>\n<p>\n&#8220;Well, then allow applications to install a new schema whenever\nthey need to.&#8221;\n<\/p>\n<p>\nIn other words, make it a total free-for-all.\nIn which case, why do you need a schema at all?\nJust leave it as an unregulated collection of name\/value pairs\ngoverned by convention rather than rigid rules,\nas long as\nthe code which writes the information and the code which reads it\nagree on the format of the information and where to look for it.\n<\/p>\n<p>\nHey, wow, that&#8217;s what the registry already is!\n<\/p>\n<p>\nAnd besides, if you told somebody,\n&#8220;Hi, yeah, in order to support looking up four pieces of\ninformation about file types,\nWindows 3.1 comes with a copy of\nSQL Server,&#8221;\nthey would think you were insane.\nThat&#8217;s like using a bazooka to kill a mosquito.\n<\/p>\n<p>\nWhat are you planning on doing with this relational database anyway?\nAre you thinking of doing an INNER JOIN on the registry?\n(Besides, the registry is already being abused enough already.\nImagine if it were a SQL server: Everybody would store\n<i>all their data<\/i> in it!)\n<\/p>\n<p>\nton explains one way applications could use this advanced functionality:\n<\/p>\n<blockquote CLASS=\"q\"><p>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2009\/02\/05\/9397154.aspx#9400103\">\nAn application would have a table or group of tables<\/a>\nin relational style registry.\nA group of settings would be a row.\nA single setting would be a column.\nIs it starting to become clearer now how SQL like statements\ncould now be used to constrain what gets deleted and added?\nHow good is your understanding of SQL and DBMS?\n<\/p><\/blockquote>\n<p>\nYou know what most application authors would say?\nThey would say &#8220;Are you mad?\nYou&#8217;re saying that I need to create a table with one column for each\nsetting?\nAnd this table would have a single row (since I have only one application)?\nAll this just so\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/09\/12\/54896.aspx\">\nI can save my window position<\/a>?\nScrew it, I&#8217;m going back to INI files.&#8221;\nWhat&#8217;ll happen in practice is that everybody will create a table with\ntwo columns,\na string called <code>name<\/code> and a blob called\n<code>value<\/code>.\nNow we&#8217;ve come full circle:\nWe have our flat database again.\n<\/p>\n<p>\nAnd how would they make sure the name of their table doesn&#8217;t\ncollide with the name of a table created by another application?\nProbably by encoding the company name and application name into\nthe name of the table, according to some agreed-upon convention.\nLike say, the Settings table used by the LitSoft program\nwritten by LitWare would be called\n<code>LitWare_LitSoft_Settings<\/code>.\nSo querying a value from this table would go something like\n<\/p>\n<pre>\nSELECT value FROM PerUser.LitWare_LitSoft_Settings\n    WHERE name = \"WindowPosition\"\n<\/pre>\n<p>\nHey, this looks an awful lot like\n<\/p>\n<pre>\nRegistry.CurrentUser.OpenSubKey(@\"LitWare\\LitSoft\\Settings\")\n        .GetValue(\"WindowPosition\");\n<\/pre>\n<p>\nOne of ton&#8217;s arguments for using a relational database is that\nit permits enforcement of referential integrity.\nBut I would argue that in the general case, you\n<i>don&#8217;t want<\/i>\nstrict enforcement of referential integrity.\nSuppose you uninstall a program.\nThe uninstaller tries to delete the program registration,\nbut that registration is being referenced by foreign keys in other tables.\nThese references were not created by the application itself;\nperhaps the shell common dialog created them as part of its\ninternal bookkeeping.\nIf the registry blocked the deletion, then the uninstall would fail.\n&#8220;Cannot uninstall application\nbecause there&#8217;s still a reference to it somewhere.&#8221;\nAnd that reference might be\nin Bob&#8217;s user profile,\nfrom that time Bob said, &#8220;Hey can I log onto your machine quickly?\nI need to look up something.&#8221;\nBob is unlikely to come back to your machine any time soon,\nso his user profile is just going to sit there holding a reference\nto that application you want to uninstall for an awfully long time.\n&#8220;Hi, Bob, can you come by my office?\nI need you to log on so I can uninstall an app.&#8221;\n<\/p>\n<p>\nSo let&#8217;s assume it goes the other way:\nThe registry automatically deletes orphaned foreign key rows.\n(And for hives that are not currently available, it just remembers\nthat those foreign key rows should be deleted the next time they are loaded.\nNevermind that that list of &#8220;foreign key rows that should be deleted\nthe next time Bob logs on&#8221; is going to get pretty long.)\n<\/p>\n<p>\nNow suppose you&#8217;re uninstalling a program not because you want to\nget rid of it, but because you&#8217;re doing an uninstall\/reinstall\ntroubleshooting step.\nYou uninstall the program, all the orphaned foreign key rows are\nautomatically deleted, then you reinstall the program.\nThose orphaned foreign key rows are not undeleted; they remain deleted.\nResult: You lost some settings.\nThis is the reason why\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2007\/09\/17\/4948130.aspx\">\nyou don&#8217;t clean up per-user data when uninstalling programs<\/a>.\n<\/p>\n<p>\nEnforcing referential integrity also means that you can&#8217;t create\nanticipatory references.\nOne example of this was given earlier, where you register something\non version&nbsp;N even though the feature doesn&#8217;t get activated\nuntil the user upgrades to version&nbsp;N+1.\nMore generally, Program&nbsp;X may want to create a reference to\nProgram&nbsp;Y at installation,\neven if program&nbsp;Y isn&#8217;t installed yet.\n(For example, X is a Web browser and Y is a popular plug-in.)\nThe Program&nbsp;Y features remain dormant, because the attempt by\nProgram&nbsp;X to access Program&nbsp;Y will fail,\nbut once the user installs Program&nbsp;Y,\nthen the Program&nbsp;Y features are magically &#8220;turned on&#8221;\nin Program&nbsp;X.\n<\/p>\n<p>\nConsider, as an even more specific example, the &#8220;kill bit&#8221; database.\nThere, the goal isn&#8217;t to &#8220;turn on&#8221; features of Program&nbsp;Y but\nto turn them off.\nImagine if referential integrity were enforced:\nYou couldn&#8217;t kill an ActiveX control until after it was installed!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Commenter ton asks why the registry was defined as a hierarchical database instead of a relational database. Heck, it&#8217;s not even a hierarchical database! The original registry was just a dictionary; i.e., a list of name\/value pairs, accessed by name. In other words, it was a flat database. .txt txtfile txtfile Text Document txtfile\\DefaultIcon notepad.exe,1 [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-9713","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Commenter ton asks why the registry was defined as a hierarchical database instead of a relational database. Heck, it&#8217;s not even a hierarchical database! The original registry was just a dictionary; i.e., a list of name\/value pairs, accessed by name. In other words, it was a flat database. .txt txtfile txtfile Text Document txtfile\\DefaultIcon notepad.exe,1 [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9713","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=9713"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9713\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=9713"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=9713"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=9713"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}