Fossil SCM
Abandon the HNAME table idea. Instead, continue to use the BLOB.UUID as the primary artifact name and add the ALIAS table for aliased artifact names after a hash algorithm change. Add the optional alias argument to the M-card.
Commit
2e42c9cb89ac25e6ee503705070e9022a7e49c7d
Parent
80f9b68e6f0547b…
5 files changed
+1
-1
+17
-8
+9
-22
+11
-9
+33
-21
+1
-1
| --- src/content.c | ||
| +++ src/content.c | ||
| @@ -1128,11 +1128,11 @@ | ||
| 1128 | 1128 | "cherry-pick target of", 0); |
| 1129 | 1129 | nErr += check_exists(p->aCherrypick[i].zCPBase, flags, p, |
| 1130 | 1130 | "cherry-pick baseline of", 0); |
| 1131 | 1131 | } |
| 1132 | 1132 | for(i=0; i<p->nCChild; i++){ |
| 1133 | - nErr += check_exists(p->azCChild[i], flags, p, "in", 0); | |
| 1133 | + nErr += check_exists(p->aCChild[i].zUuid, flags, p, "in", 0); | |
| 1134 | 1134 | } |
| 1135 | 1135 | for(i=0; i<p->nTag; i++){ |
| 1136 | 1136 | nErr += check_exists(p->aTag[i].zUuid, flags, p, "target of", 0); |
| 1137 | 1137 | } |
| 1138 | 1138 | manifest_destroy(p); |
| 1139 | 1139 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -1128,11 +1128,11 @@ | |
| 1128 | "cherry-pick target of", 0); |
| 1129 | nErr += check_exists(p->aCherrypick[i].zCPBase, flags, p, |
| 1130 | "cherry-pick baseline of", 0); |
| 1131 | } |
| 1132 | for(i=0; i<p->nCChild; i++){ |
| 1133 | nErr += check_exists(p->azCChild[i], flags, p, "in", 0); |
| 1134 | } |
| 1135 | for(i=0; i<p->nTag; i++){ |
| 1136 | nErr += check_exists(p->aTag[i].zUuid, flags, p, "target of", 0); |
| 1137 | } |
| 1138 | manifest_destroy(p); |
| 1139 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -1128,11 +1128,11 @@ | |
| 1128 | "cherry-pick target of", 0); |
| 1129 | nErr += check_exists(p->aCherrypick[i].zCPBase, flags, p, |
| 1130 | "cherry-pick baseline of", 0); |
| 1131 | } |
| 1132 | for(i=0; i<p->nCChild; i++){ |
| 1133 | nErr += check_exists(p->aCChild[i].zUuid, flags, p, "in", 0); |
| 1134 | } |
| 1135 | for(i=0; i<p->nTag; i++){ |
| 1136 | nErr += check_exists(p->aTag[i].zUuid, flags, p, "target of", 0); |
| 1137 | } |
| 1138 | manifest_destroy(p); |
| 1139 |
+17
-8
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -95,12 +95,15 @@ | ||
| 95 | 95 | struct { |
| 96 | 96 | char *zCPTarget; /* Hash for cherry-picked version w/ +|- prefix */ |
| 97 | 97 | char *zCPBase; /* Hash for cherry-pick baseline. NULL for singletons */ |
| 98 | 98 | } *aCherrypick; |
| 99 | 99 | int nCChild; /* Number of cluster children */ |
| 100 | - int nCChildAlloc; /* Number of closts allocated in azCChild[] */ | |
| 101 | - char **azCChild; /* Hashes of referenced objects in a cluster. M cards */ | |
| 100 | + int nCChildAlloc; /* Number of cluster allocated in aCChild[] */ | |
| 101 | + struct { | |
| 102 | + char *zUuid; /* Hashes of referenced objects in cluster. M cards */ | |
| 103 | + char *zAlias; /* Alias arguments on a cluster */ | |
| 104 | + } *aCChild; | |
| 102 | 105 | int nTag; /* Number of T Cards */ |
| 103 | 106 | int nTagAlloc; /* Slots allocated in aTag[] */ |
| 104 | 107 | struct TagType { |
| 105 | 108 | char *zName; /* Name of the tag */ |
| 106 | 109 | char *zUuid; /* Hash of artifact that the tag is applied to */ |
| @@ -138,11 +141,11 @@ | ||
| 138 | 141 | void manifest_destroy(Manifest *p){ |
| 139 | 142 | if( p ){ |
| 140 | 143 | blob_reset(&p->content); |
| 141 | 144 | fossil_free(p->aFile); |
| 142 | 145 | fossil_free(p->azParent); |
| 143 | - fossil_free(p->azCChild); | |
| 146 | + fossil_free(p->aCChild); | |
| 144 | 147 | fossil_free(p->aTag); |
| 145 | 148 | fossil_free(p->aField); |
| 146 | 149 | fossil_free(p->aCherrypick); |
| 147 | 150 | if( p->pBaseline ) manifest_destroy(p->pBaseline); |
| 148 | 151 | memset(p, 0, sizeof(*p)); |
| @@ -643,23 +646,29 @@ | ||
| 643 | 646 | ** |
| 644 | 647 | ** An M-line identifies another artifact by its hash. M-lines |
| 645 | 648 | ** occur in clusters only. |
| 646 | 649 | */ |
| 647 | 650 | case 'M': { |
| 651 | + char *zAlias; | |
| 648 | 652 | zUuid = next_token(&x, &sz); |
| 649 | 653 | if( zUuid==0 ) SYNTAX("missing hash on M-card"); |
| 650 | 654 | if( hname_validate(zUuid,sz)==HNAME_NONE ){ |
| 651 | 655 | SYNTAX("Invalid hash on M-card"); |
| 652 | 656 | } |
| 657 | + zAlias = next_token(&x, &sz); | |
| 658 | + if( zAlias && hname_validate(zAlias,sz)==HNAME_NONE ){ | |
| 659 | + SYNTAX("Invalid alias hash on M-card"); | |
| 660 | + } | |
| 653 | 661 | if( p->nCChild>=p->nCChildAlloc ){ |
| 654 | 662 | p->nCChildAlloc = p->nCChildAlloc*2 + 10; |
| 655 | - p->azCChild = fossil_realloc(p->azCChild | |
| 656 | - , p->nCChildAlloc*sizeof(p->azCChild[0]) ); | |
| 663 | + p->aCChild = fossil_realloc(p->aCChild | |
| 664 | + , p->nCChildAlloc*sizeof(p->aCChild[0]) ); | |
| 657 | 665 | } |
| 658 | 666 | i = p->nCChild++; |
| 659 | - p->azCChild[i] = zUuid; | |
| 660 | - if( i>0 && fossil_strcmp(p->azCChild[i-1], zUuid)>=0 ){ | |
| 667 | + p->aCChild[i].zUuid = zUuid; | |
| 668 | + p->aCChild[i].zAlias = zAlias; | |
| 669 | + if( i>0 && fossil_strcmp(p->aCChild[i-1].zUuid, zUuid)>=0 ){ | |
| 661 | 670 | SYNTAX("M-card in the wrong order"); |
| 662 | 671 | } |
| 663 | 672 | break; |
| 664 | 673 | } |
| 665 | 674 | |
| @@ -2006,11 +2015,11 @@ | ||
| 2006 | 2015 | static Stmt del1; |
| 2007 | 2016 | tag_insert("cluster", 1, 0, rid, p->rDate, rid); |
| 2008 | 2017 | db_static_prepare(&del1, "DELETE FROM unclustered WHERE rid=:rid"); |
| 2009 | 2018 | for(i=0; i<p->nCChild; i++){ |
| 2010 | 2019 | int mid; |
| 2011 | - mid = uuid_to_rid(p->azCChild[i], 1); | |
| 2020 | + mid = uuid_to_rid(p->aCChild[i].zUuid, 1); | |
| 2012 | 2021 | if( mid>0 ){ |
| 2013 | 2022 | db_bind_int(&del1, ":rid", mid); |
| 2014 | 2023 | db_step(&del1); |
| 2015 | 2024 | db_reset(&del1); |
| 2016 | 2025 | } |
| 2017 | 2026 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -95,12 +95,15 @@ | |
| 95 | struct { |
| 96 | char *zCPTarget; /* Hash for cherry-picked version w/ +|- prefix */ |
| 97 | char *zCPBase; /* Hash for cherry-pick baseline. NULL for singletons */ |
| 98 | } *aCherrypick; |
| 99 | int nCChild; /* Number of cluster children */ |
| 100 | int nCChildAlloc; /* Number of closts allocated in azCChild[] */ |
| 101 | char **azCChild; /* Hashes of referenced objects in a cluster. M cards */ |
| 102 | int nTag; /* Number of T Cards */ |
| 103 | int nTagAlloc; /* Slots allocated in aTag[] */ |
| 104 | struct TagType { |
| 105 | char *zName; /* Name of the tag */ |
| 106 | char *zUuid; /* Hash of artifact that the tag is applied to */ |
| @@ -138,11 +141,11 @@ | |
| 138 | void manifest_destroy(Manifest *p){ |
| 139 | if( p ){ |
| 140 | blob_reset(&p->content); |
| 141 | fossil_free(p->aFile); |
| 142 | fossil_free(p->azParent); |
| 143 | fossil_free(p->azCChild); |
| 144 | fossil_free(p->aTag); |
| 145 | fossil_free(p->aField); |
| 146 | fossil_free(p->aCherrypick); |
| 147 | if( p->pBaseline ) manifest_destroy(p->pBaseline); |
| 148 | memset(p, 0, sizeof(*p)); |
| @@ -643,23 +646,29 @@ | |
| 643 | ** |
| 644 | ** An M-line identifies another artifact by its hash. M-lines |
| 645 | ** occur in clusters only. |
| 646 | */ |
| 647 | case 'M': { |
| 648 | zUuid = next_token(&x, &sz); |
| 649 | if( zUuid==0 ) SYNTAX("missing hash on M-card"); |
| 650 | if( hname_validate(zUuid,sz)==HNAME_NONE ){ |
| 651 | SYNTAX("Invalid hash on M-card"); |
| 652 | } |
| 653 | if( p->nCChild>=p->nCChildAlloc ){ |
| 654 | p->nCChildAlloc = p->nCChildAlloc*2 + 10; |
| 655 | p->azCChild = fossil_realloc(p->azCChild |
| 656 | , p->nCChildAlloc*sizeof(p->azCChild[0]) ); |
| 657 | } |
| 658 | i = p->nCChild++; |
| 659 | p->azCChild[i] = zUuid; |
| 660 | if( i>0 && fossil_strcmp(p->azCChild[i-1], zUuid)>=0 ){ |
| 661 | SYNTAX("M-card in the wrong order"); |
| 662 | } |
| 663 | break; |
| 664 | } |
| 665 | |
| @@ -2006,11 +2015,11 @@ | |
| 2006 | static Stmt del1; |
| 2007 | tag_insert("cluster", 1, 0, rid, p->rDate, rid); |
| 2008 | db_static_prepare(&del1, "DELETE FROM unclustered WHERE rid=:rid"); |
| 2009 | for(i=0; i<p->nCChild; i++){ |
| 2010 | int mid; |
| 2011 | mid = uuid_to_rid(p->azCChild[i], 1); |
| 2012 | if( mid>0 ){ |
| 2013 | db_bind_int(&del1, ":rid", mid); |
| 2014 | db_step(&del1); |
| 2015 | db_reset(&del1); |
| 2016 | } |
| 2017 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -95,12 +95,15 @@ | |
| 95 | struct { |
| 96 | char *zCPTarget; /* Hash for cherry-picked version w/ +|- prefix */ |
| 97 | char *zCPBase; /* Hash for cherry-pick baseline. NULL for singletons */ |
| 98 | } *aCherrypick; |
| 99 | int nCChild; /* Number of cluster children */ |
| 100 | int nCChildAlloc; /* Number of cluster allocated in aCChild[] */ |
| 101 | struct { |
| 102 | char *zUuid; /* Hashes of referenced objects in cluster. M cards */ |
| 103 | char *zAlias; /* Alias arguments on a cluster */ |
| 104 | } *aCChild; |
| 105 | int nTag; /* Number of T Cards */ |
| 106 | int nTagAlloc; /* Slots allocated in aTag[] */ |
| 107 | struct TagType { |
| 108 | char *zName; /* Name of the tag */ |
| 109 | char *zUuid; /* Hash of artifact that the tag is applied to */ |
| @@ -138,11 +141,11 @@ | |
| 141 | void manifest_destroy(Manifest *p){ |
| 142 | if( p ){ |
| 143 | blob_reset(&p->content); |
| 144 | fossil_free(p->aFile); |
| 145 | fossil_free(p->azParent); |
| 146 | fossil_free(p->aCChild); |
| 147 | fossil_free(p->aTag); |
| 148 | fossil_free(p->aField); |
| 149 | fossil_free(p->aCherrypick); |
| 150 | if( p->pBaseline ) manifest_destroy(p->pBaseline); |
| 151 | memset(p, 0, sizeof(*p)); |
| @@ -643,23 +646,29 @@ | |
| 646 | ** |
| 647 | ** An M-line identifies another artifact by its hash. M-lines |
| 648 | ** occur in clusters only. |
| 649 | */ |
| 650 | case 'M': { |
| 651 | char *zAlias; |
| 652 | zUuid = next_token(&x, &sz); |
| 653 | if( zUuid==0 ) SYNTAX("missing hash on M-card"); |
| 654 | if( hname_validate(zUuid,sz)==HNAME_NONE ){ |
| 655 | SYNTAX("Invalid hash on M-card"); |
| 656 | } |
| 657 | zAlias = next_token(&x, &sz); |
| 658 | if( zAlias && hname_validate(zAlias,sz)==HNAME_NONE ){ |
| 659 | SYNTAX("Invalid alias hash on M-card"); |
| 660 | } |
| 661 | if( p->nCChild>=p->nCChildAlloc ){ |
| 662 | p->nCChildAlloc = p->nCChildAlloc*2 + 10; |
| 663 | p->aCChild = fossil_realloc(p->aCChild |
| 664 | , p->nCChildAlloc*sizeof(p->aCChild[0]) ); |
| 665 | } |
| 666 | i = p->nCChild++; |
| 667 | p->aCChild[i].zUuid = zUuid; |
| 668 | p->aCChild[i].zAlias = zAlias; |
| 669 | if( i>0 && fossil_strcmp(p->aCChild[i-1].zUuid, zUuid)>=0 ){ |
| 670 | SYNTAX("M-card in the wrong order"); |
| 671 | } |
| 672 | break; |
| 673 | } |
| 674 | |
| @@ -2006,11 +2015,11 @@ | |
| 2015 | static Stmt del1; |
| 2016 | tag_insert("cluster", 1, 0, rid, p->rDate, rid); |
| 2017 | db_static_prepare(&del1, "DELETE FROM unclustered WHERE rid=:rid"); |
| 2018 | for(i=0; i<p->nCChild; i++){ |
| 2019 | int mid; |
| 2020 | mid = uuid_to_rid(p->aCChild[i].zUuid, 1); |
| 2021 | if( mid>0 ){ |
| 2022 | db_bind_int(&del1, ":rid", mid); |
| 2023 | db_step(&del1); |
| 2024 | db_reset(&del1); |
| 2025 | } |
| 2026 |
+9
-22
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -78,26 +78,20 @@ | ||
| 78 | 78 | @ mtime INTEGER, -- Time last modified. Seconds since 1970 |
| 79 | 79 | @ cols TEXT, -- A color-key specification |
| 80 | 80 | @ sqlcode TEXT -- An SQL SELECT statement for this report |
| 81 | 81 | @ ); |
| 82 | 82 | ; |
| 83 | -static const char zCreateHnameTable[] = | |
| 84 | -@ -- The hname table provides mappings from artifact hashes (hval) to the | |
| 85 | -@ -- artifact id (rid). This table was added in Fossil-2.0. Prior to | |
| 86 | -@ -- Fossil-2.0, there was only a single SHA1 hash value for each artifact | |
| 87 | -@ -- which was stored in the BLOB.UUID field. With the introduction of | |
| 88 | -@ -- multiple hash algorithms, the hval to rid mapping went from one-to-one to | |
| 89 | -@ -- many-to-one and a new table became necessary. | |
| 83 | +static const char zSchemaUpdate3[] = | |
| 84 | +@ -- Make sure the alias table exists. | |
| 90 | 85 | @ -- |
| 91 | -@ CREATE TABLE hname( | |
| 86 | +@ CREATE TABLE alias( | |
| 92 | 87 | @ hval TEXT, -- Hex-encoded hash value |
| 93 | -@ htype ANY, -- Type of hash. Preferred hash: 0 | |
| 88 | +@ htype ANY, -- Type of hash. | |
| 94 | 89 | @ rid INTEGER REFERENCES blob, -- Blob that this hash names |
| 95 | 90 | @ PRIMARY KEY(hval,htype) |
| 96 | 91 | @ ) WITHOUT ROWID; |
| 97 | -@ INSERT INTO hname(hval,htype,rid) SELECT uuid,0,rid FROM blob; | |
| 98 | -@ CREATE INDEX hname_rid ON hname(rid,htype); | |
| 92 | +@ CREATE INDEX alias_rid ON alias(rid,htype) | |
| 99 | 93 | ; |
| 100 | 94 | |
| 101 | 95 | /* |
| 102 | 96 | ** Update the schema as necessary |
| 103 | 97 | */ |
| @@ -174,20 +168,13 @@ | ||
| 174 | 168 | "ALTER TABLE concealed ADD COLUMN mtime INTEGER;" |
| 175 | 169 | "UPDATE concealed SET mtime=now();" |
| 176 | 170 | ); |
| 177 | 171 | } |
| 178 | 172 | |
| 179 | - /* If the hname table is missing, that means we are dealing with an | |
| 180 | - ** older Fossil 1.x database. Create the hname table an populate it | |
| 181 | - ** with the SHA1 hash values in the blob.uuid field. | |
| 182 | - ** | |
| 183 | - ** TODO: After all the rest of the code is updated to use the hname | |
| 184 | - ** table instead of the blob.uuid column, also delete the blob.uuid | |
| 185 | - ** column. | |
| 186 | - */ | |
| 187 | - if( !db_table_exists("repository", "hname") ){ | |
| 188 | - db_multi_exec("%s", zCreateHnameTable/*safe-for-%s*/); | |
| 173 | + /* If the alias table is missing, create it. */ | |
| 174 | + if( !db_table_exists("repository", "alias") ){ | |
| 175 | + db_multi_exec("%s", zSchemaUpdate3/*safe-for-%s*/); | |
| 189 | 176 | } |
| 190 | 177 | } |
| 191 | 178 | |
| 192 | 179 | /* |
| 193 | 180 | ** Variables used to store state information about an on-going "rebuild" |
| @@ -800,11 +787,11 @@ | ||
| 800 | 787 | p = manifest_get(rid, CFTYPE_CLUSTER, 0); |
| 801 | 788 | if( p==0 ){ |
| 802 | 789 | fossil_fatal("bad cluster: rid=%d", rid); |
| 803 | 790 | } |
| 804 | 791 | for(i=0; i<p->nCChild; i++){ |
| 805 | - const char *zUuid = p->azCChild[i]; | |
| 792 | + const char *zUuid = p->aCChild[i].zUuid; | |
| 806 | 793 | int crid = name_to_rid(zUuid); |
| 807 | 794 | if( crid==0 ){ |
| 808 | 795 | fossil_warning("cluster (rid=%d) references unknown artifact %s", |
| 809 | 796 | rid, zUuid); |
| 810 | 797 | continue; |
| 811 | 798 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -78,26 +78,20 @@ | |
| 78 | @ mtime INTEGER, -- Time last modified. Seconds since 1970 |
| 79 | @ cols TEXT, -- A color-key specification |
| 80 | @ sqlcode TEXT -- An SQL SELECT statement for this report |
| 81 | @ ); |
| 82 | ; |
| 83 | static const char zCreateHnameTable[] = |
| 84 | @ -- The hname table provides mappings from artifact hashes (hval) to the |
| 85 | @ -- artifact id (rid). This table was added in Fossil-2.0. Prior to |
| 86 | @ -- Fossil-2.0, there was only a single SHA1 hash value for each artifact |
| 87 | @ -- which was stored in the BLOB.UUID field. With the introduction of |
| 88 | @ -- multiple hash algorithms, the hval to rid mapping went from one-to-one to |
| 89 | @ -- many-to-one and a new table became necessary. |
| 90 | @ -- |
| 91 | @ CREATE TABLE hname( |
| 92 | @ hval TEXT, -- Hex-encoded hash value |
| 93 | @ htype ANY, -- Type of hash. Preferred hash: 0 |
| 94 | @ rid INTEGER REFERENCES blob, -- Blob that this hash names |
| 95 | @ PRIMARY KEY(hval,htype) |
| 96 | @ ) WITHOUT ROWID; |
| 97 | @ INSERT INTO hname(hval,htype,rid) SELECT uuid,0,rid FROM blob; |
| 98 | @ CREATE INDEX hname_rid ON hname(rid,htype); |
| 99 | ; |
| 100 | |
| 101 | /* |
| 102 | ** Update the schema as necessary |
| 103 | */ |
| @@ -174,20 +168,13 @@ | |
| 174 | "ALTER TABLE concealed ADD COLUMN mtime INTEGER;" |
| 175 | "UPDATE concealed SET mtime=now();" |
| 176 | ); |
| 177 | } |
| 178 | |
| 179 | /* If the hname table is missing, that means we are dealing with an |
| 180 | ** older Fossil 1.x database. Create the hname table an populate it |
| 181 | ** with the SHA1 hash values in the blob.uuid field. |
| 182 | ** |
| 183 | ** TODO: After all the rest of the code is updated to use the hname |
| 184 | ** table instead of the blob.uuid column, also delete the blob.uuid |
| 185 | ** column. |
| 186 | */ |
| 187 | if( !db_table_exists("repository", "hname") ){ |
| 188 | db_multi_exec("%s", zCreateHnameTable/*safe-for-%s*/); |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | /* |
| 193 | ** Variables used to store state information about an on-going "rebuild" |
| @@ -800,11 +787,11 @@ | |
| 800 | p = manifest_get(rid, CFTYPE_CLUSTER, 0); |
| 801 | if( p==0 ){ |
| 802 | fossil_fatal("bad cluster: rid=%d", rid); |
| 803 | } |
| 804 | for(i=0; i<p->nCChild; i++){ |
| 805 | const char *zUuid = p->azCChild[i]; |
| 806 | int crid = name_to_rid(zUuid); |
| 807 | if( crid==0 ){ |
| 808 | fossil_warning("cluster (rid=%d) references unknown artifact %s", |
| 809 | rid, zUuid); |
| 810 | continue; |
| 811 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -78,26 +78,20 @@ | |
| 78 | @ mtime INTEGER, -- Time last modified. Seconds since 1970 |
| 79 | @ cols TEXT, -- A color-key specification |
| 80 | @ sqlcode TEXT -- An SQL SELECT statement for this report |
| 81 | @ ); |
| 82 | ; |
| 83 | static const char zSchemaUpdate3[] = |
| 84 | @ -- Make sure the alias table exists. |
| 85 | @ -- |
| 86 | @ CREATE TABLE alias( |
| 87 | @ hval TEXT, -- Hex-encoded hash value |
| 88 | @ htype ANY, -- Type of hash. |
| 89 | @ rid INTEGER REFERENCES blob, -- Blob that this hash names |
| 90 | @ PRIMARY KEY(hval,htype) |
| 91 | @ ) WITHOUT ROWID; |
| 92 | @ CREATE INDEX alias_rid ON alias(rid,htype) |
| 93 | ; |
| 94 | |
| 95 | /* |
| 96 | ** Update the schema as necessary |
| 97 | */ |
| @@ -174,20 +168,13 @@ | |
| 168 | "ALTER TABLE concealed ADD COLUMN mtime INTEGER;" |
| 169 | "UPDATE concealed SET mtime=now();" |
| 170 | ); |
| 171 | } |
| 172 | |
| 173 | /* If the alias table is missing, create it. */ |
| 174 | if( !db_table_exists("repository", "alias") ){ |
| 175 | db_multi_exec("%s", zSchemaUpdate3/*safe-for-%s*/); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | /* |
| 180 | ** Variables used to store state information about an on-going "rebuild" |
| @@ -800,11 +787,11 @@ | |
| 787 | p = manifest_get(rid, CFTYPE_CLUSTER, 0); |
| 788 | if( p==0 ){ |
| 789 | fossil_fatal("bad cluster: rid=%d", rid); |
| 790 | } |
| 791 | for(i=0; i<p->nCChild; i++){ |
| 792 | const char *zUuid = p->aCChild[i].zUuid; |
| 793 | int crid = name_to_rid(zUuid); |
| 794 | if( crid==0 ){ |
| 795 | fossil_warning("cluster (rid=%d) references unknown artifact %s", |
| 796 | rid, zUuid); |
| 797 | continue; |
| 798 |
+11
-9
| --- src/schema.c | ||
| +++ src/schema.c | ||
| @@ -79,11 +79,11 @@ | ||
| 79 | 79 | @ -- |
| 80 | 80 | @ CREATE TABLE blob( |
| 81 | 81 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 82 | 82 | @ rcvid INTEGER, -- Origin of this record |
| 83 | 83 | @ size INTEGER, -- Size of content. -1 for a phantom. |
| 84 | -@ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content | |
| 84 | +@ uuid TEXT UNIQUE NOT NULL, -- hash of the content | |
| 85 | 85 | @ content BLOB, -- Compressed content of this record |
| 86 | 86 | @ CHECK( length(uuid)==40 AND rid>0 ) |
| 87 | 87 | @ ); |
| 88 | 88 | @ CREATE TABLE delta( |
| 89 | 89 | @ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed |
| @@ -107,23 +107,25 @@ | ||
| 107 | 107 | @ mtime DATETIME, -- Time of receipt. Julian day. |
| 108 | 108 | @ nonce TEXT UNIQUE, -- Nonce used for login |
| 109 | 109 | @ ipaddr TEXT -- Remote IP address. NULL for direct. |
| 110 | 110 | @ ); |
| 111 | 111 | @ |
| 112 | -@ -- The hname table maps hash values (hval) into artifact IDs (rid). | |
| 113 | -@ -- Prior to Fossil 2.0 (early 2017) there was only a single SHA1 hash | |
| 114 | -@ -- value, and so the one-to-one mapping was accomplished using the | |
| 115 | -@ -- BLOB.UUID column. Beginning with 2.0, the mapping is many-to-one | |
| 116 | -@ -- and so a separate table became necessary. | |
| 112 | +@ -- The canonical name of each artifact is given by the BLOB.UUID field. | |
| 113 | +@ -- But artifacts can also have aliases. Aliases arise, for example, when | |
| 114 | +@ -- the naming hash algorithm changes, or as a result of trying to provide | |
| 115 | +@ -- compatibility with a different VCS. | |
| 116 | +@ -- | |
| 117 | +@ -- Each entry in the ALIAS table provides an alternative name by which an | |
| 118 | +@ -- artifact can be called. | |
| 117 | 119 | @ -- |
| 118 | -@ CREATE TABLE hname( | |
| 120 | +@ CREATE TABLE alias( | |
| 119 | 121 | @ hval TEXT, -- Hex-encoded hash value |
| 120 | -@ htype ANY, -- Type of hash. Preferred hash: 0 | |
| 122 | +@ htype ANY, -- Type of hash. | |
| 121 | 123 | @ rid INTEGER REFERENCES blob, -- Blob that this hash names |
| 122 | 124 | @ PRIMARY KEY(hval,htype) |
| 123 | 125 | @ ) WITHOUT ROWID; |
| 124 | -@ CREATE INDEX hname_rid ON hname(rid,htype) | |
| 126 | +@ CREATE INDEX alias_rid ON alias(rid,htype) | |
| 125 | 127 | @ |
| 126 | 128 | @ -- Information about users |
| 127 | 129 | @ -- |
| 128 | 130 | @ -- The user.pw field can be either cleartext of the password, or |
| 129 | 131 | @ -- a SHA1 hash of the password. If the user.pw field is exactly 40 |
| 130 | 132 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -79,11 +79,11 @@ | |
| 79 | @ -- |
| 80 | @ CREATE TABLE blob( |
| 81 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 82 | @ rcvid INTEGER, -- Origin of this record |
| 83 | @ size INTEGER, -- Size of content. -1 for a phantom. |
| 84 | @ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content |
| 85 | @ content BLOB, -- Compressed content of this record |
| 86 | @ CHECK( length(uuid)==40 AND rid>0 ) |
| 87 | @ ); |
| 88 | @ CREATE TABLE delta( |
| 89 | @ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed |
| @@ -107,23 +107,25 @@ | |
| 107 | @ mtime DATETIME, -- Time of receipt. Julian day. |
| 108 | @ nonce TEXT UNIQUE, -- Nonce used for login |
| 109 | @ ipaddr TEXT -- Remote IP address. NULL for direct. |
| 110 | @ ); |
| 111 | @ |
| 112 | @ -- The hname table maps hash values (hval) into artifact IDs (rid). |
| 113 | @ -- Prior to Fossil 2.0 (early 2017) there was only a single SHA1 hash |
| 114 | @ -- value, and so the one-to-one mapping was accomplished using the |
| 115 | @ -- BLOB.UUID column. Beginning with 2.0, the mapping is many-to-one |
| 116 | @ -- and so a separate table became necessary. |
| 117 | @ -- |
| 118 | @ CREATE TABLE hname( |
| 119 | @ hval TEXT, -- Hex-encoded hash value |
| 120 | @ htype ANY, -- Type of hash. Preferred hash: 0 |
| 121 | @ rid INTEGER REFERENCES blob, -- Blob that this hash names |
| 122 | @ PRIMARY KEY(hval,htype) |
| 123 | @ ) WITHOUT ROWID; |
| 124 | @ CREATE INDEX hname_rid ON hname(rid,htype) |
| 125 | @ |
| 126 | @ -- Information about users |
| 127 | @ -- |
| 128 | @ -- The user.pw field can be either cleartext of the password, or |
| 129 | @ -- a SHA1 hash of the password. If the user.pw field is exactly 40 |
| 130 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -79,11 +79,11 @@ | |
| 79 | @ -- |
| 80 | @ CREATE TABLE blob( |
| 81 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 82 | @ rcvid INTEGER, -- Origin of this record |
| 83 | @ size INTEGER, -- Size of content. -1 for a phantom. |
| 84 | @ uuid TEXT UNIQUE NOT NULL, -- hash of the content |
| 85 | @ content BLOB, -- Compressed content of this record |
| 86 | @ CHECK( length(uuid)==40 AND rid>0 ) |
| 87 | @ ); |
| 88 | @ CREATE TABLE delta( |
| 89 | @ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed |
| @@ -107,23 +107,25 @@ | |
| 107 | @ mtime DATETIME, -- Time of receipt. Julian day. |
| 108 | @ nonce TEXT UNIQUE, -- Nonce used for login |
| 109 | @ ipaddr TEXT -- Remote IP address. NULL for direct. |
| 110 | @ ); |
| 111 | @ |
| 112 | @ -- The canonical name of each artifact is given by the BLOB.UUID field. |
| 113 | @ -- But artifacts can also have aliases. Aliases arise, for example, when |
| 114 | @ -- the naming hash algorithm changes, or as a result of trying to provide |
| 115 | @ -- compatibility with a different VCS. |
| 116 | @ -- |
| 117 | @ -- Each entry in the ALIAS table provides an alternative name by which an |
| 118 | @ -- artifact can be called. |
| 119 | @ -- |
| 120 | @ CREATE TABLE alias( |
| 121 | @ hval TEXT, -- Hex-encoded hash value |
| 122 | @ htype ANY, -- Type of hash. |
| 123 | @ rid INTEGER REFERENCES blob, -- Blob that this hash names |
| 124 | @ PRIMARY KEY(hval,htype) |
| 125 | @ ) WITHOUT ROWID; |
| 126 | @ CREATE INDEX alias_rid ON alias(rid,htype) |
| 127 | @ |
| 128 | @ -- Information about users |
| 129 | @ -- |
| 130 | @ -- The user.pw field can be either cleartext of the password, or |
| 131 | @ -- a SHA1 hash of the password. If the user.pw field is exactly 40 |
| 132 |
+33
-21
| --- www/fileformat.wiki | ||
| +++ www/fileformat.wiki | ||
| @@ -27,18 +27,28 @@ | ||
| 27 | 27 | with the global state. |
| 28 | 28 | The local state is not composed of artifacts and is not intended to be enduring. |
| 29 | 29 | This document is concerned with global state only. Local state is only |
| 30 | 30 | mentioned here in order to distinguish it from global state. |
| 31 | 31 | |
| 32 | -Each artifact in the repository is named by its SHA1 hash. | |
| 32 | +Each artifact in the repository is named by a hash of the artifact | |
| 33 | +content. | |
| 33 | 34 | No prefixes or meta information is added to an artifact before |
| 34 | -its hash is computed. The name of an artifact in the repository | |
| 35 | -is exactly the same SHA1 hash that is computed by sha1sum | |
| 36 | -on the file as it exists in your source tree.</p> | |
| 35 | +its hash is computed. | |
| 36 | + | |
| 37 | +Each repository uses a single hash algorithm to compute artifact names. | |
| 38 | +The default algorithm is currently SHA3-256, though this might change | |
| 39 | +in future releases of Fossil. Historical versions of Fossil used | |
| 40 | +SHA1. The hash algorithm for a repository can be changed. When a hash | |
| 41 | +algorithm change occurs, a set of aliases are set up (using the | |
| 42 | +two-argument version of the M-card on cluster artifacts) so that the | |
| 43 | +older hash values can be mapped into the new hash values for artifacts | |
| 44 | +that were added to the repository before the hash algorithm change. | |
| 37 | 45 | |
| 38 | 46 | Some artifacts have a particular format which gives them special |
| 39 | -meaning to fossil. Fossil recognizes: | |
| 47 | +meaning to Fossil. The special artifacts are calls "structural | |
| 48 | +artifacts". Fossil recognizes the following kinds of structural | |
| 49 | +artifacts: | |
| 40 | 50 | |
| 41 | 51 | <ul> |
| 42 | 52 | <li> [#manifest | Manifests] </li> |
| 43 | 53 | <li> [#cluster | Clusters] </li> |
| 44 | 54 | <li> [#ctrl | Control Artifacts] </li> |
| @@ -46,13 +56,13 @@ | ||
| 46 | 56 | <li> [#tktchng | Ticket Changes] </li> |
| 47 | 57 | <li> [#attachment | Attachments] </li> |
| 48 | 58 | <li> [#event | TechNotes] </li> |
| 49 | 59 | </ul> |
| 50 | 60 | |
| 51 | -These seven artifact types are described in the following sections. | |
| 61 | +These seven structural artifact types are described in the following sections. | |
| 52 | 62 | |
| 53 | -In the current implementation (as of 2009-01-25) the artifacts that | |
| 63 | +In the current implementation (as of 2017-02-27) the artifacts that | |
| 54 | 64 | make up a fossil repository are stored as delta- and zlib-compressed |
| 55 | 65 | blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This |
| 56 | 66 | is an implementation detail and might change in a future release. For |
| 57 | 67 | the purpose of this article "file format" means the format of the artifacts, |
| 58 | 68 | not how the artifacts are stored on disk. It is the artifact format that |
| @@ -98,14 +108,14 @@ | ||
| 98 | 108 | |
| 99 | 109 | <blockquote> |
| 100 | 110 | <b>B</b> <i>baseline-manifest</i><br> |
| 101 | 111 | <b>C</b> <i>checkin-comment</i><br> |
| 102 | 112 | <b>D</b> <i>time-and-date-stamp</i><br> |
| 103 | -<b>F</b> <i>filename</i> ?<i>SHA1-hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br> | |
| 113 | +<b>F</b> <i>filename</i> ?<i>hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br> | |
| 104 | 114 | <b>N</b> <i>mimetype</i><br> |
| 105 | -<b>P</b> <i>SHA1-hash</i>+<br> | |
| 106 | -<b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash</i> ?<i>SHA1-hash</i>?<br> | |
| 115 | +<b>P</b> <i>artifact-hash</i>+<br> | |
| 116 | +<b>Q</b> (<b>+</b>|<b>-</b>)<i>artifact-hash</i> ?<i>artifact-hash</i>?<br> | |
| 107 | 117 | <b>R</b> <i>repository-checksum</i><br> |
| 108 | 118 | <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br> |
| 109 | 119 | <b>U</b> <i>user-login</i><br> |
| 110 | 120 | <b>Z</b> <i>manifest-checksum</i> |
| 111 | 121 | </blockquote> |
| @@ -145,11 +155,11 @@ | ||
| 145 | 155 | check-in relative to the root of the project file hierarchy. No ".." |
| 146 | 156 | or "." directories are allowed within the filename. Space characters |
| 147 | 157 | are escaped as in C-card comment text. Backslash characters and |
| 148 | 158 | newlines are not allowed within filenames. The directory separator |
| 149 | 159 | character is a forward slash (ASCII 0x2F). The second argument to the |
| 150 | -F-card is the full 40-character lower-case hexadecimal SHA1 hash of | |
| 160 | +F-card is the lower-case hexadecimal artifact hash of | |
| 151 | 161 | the content artifact. The second argument is required for baseline |
| 152 | 162 | manifests but is optional for delta manifests. When the second |
| 153 | 163 | argument to the F-card is omitted, it means that the file has been |
| 154 | 164 | deleted relative to the baseline (files removed in baseline manifests |
| 155 | 165 | versions are <em>not</em> added as F-cards). The optional 3rd argument |
| @@ -167,14 +177,14 @@ | ||
| 167 | 177 | is used. |
| 168 | 178 | |
| 169 | 179 | A manifest has zero or one P-cards. Most manifests have one P-card. |
| 170 | 180 | The P-card has a varying number of arguments that |
| 171 | 181 | define other manifests from which the current manifest |
| 172 | -is derived. Each argument is a 40-character lowercase | |
| 173 | -hexadecimal SHA1 of a predecessor manifest. All arguments | |
| 182 | +is derived. Each argument is a lowercase | |
| 183 | +hexadecimal artifact hash of a predecessor manifest. All arguments | |
| 174 | 184 | to the P-card must be unique within that card. |
| 175 | -The first argument is the SHA1 of the direct ancestor of the manifest. | |
| 185 | +The first argument is the artifact hash of the direct ancestor of the manifest. | |
| 176 | 186 | Other arguments define manifests with which the first was |
| 177 | 187 | merged to yield the current manifest. Most manifests have |
| 178 | 188 | a P-card with a single argument. The first manifest in the |
| 179 | 189 | project has no ancestors and thus has no P-card or (depending |
| 180 | 190 | on the Fossil version) an empty P-card (no arguments). |
| @@ -241,13 +251,13 @@ | ||
| 241 | 251 | <a name="cluster"></a> |
| 242 | 252 | <h2>2.0 Clusters</h2> |
| 243 | 253 | |
| 244 | 254 | A cluster is an artifact that declares the existence of other artifacts. |
| 245 | 255 | Clusters are used during repository synchronization to help |
| 246 | -reduce network traffic. As such, clusters are an optimization and | |
| 247 | -may be removed from a repository without loss or damage to the | |
| 248 | -underlying project code. | |
| 256 | +reduce network traffic. Clusters are also used to record aliases | |
| 257 | +for artifact names, so that if the artifact hash algorithm changes, | |
| 258 | +artifacts can still be looked up using the older hash algorithm. | |
| 249 | 259 | |
| 250 | 260 | Clusters follow a syntax that is very similar to manifests. |
| 251 | 261 | A cluster is a line-oriented text file. Newline characters |
| 252 | 262 | (ASCII 0x0a) separate the artifact into cards. Each card begins with a single |
| 253 | 263 | character "card type". Zero or more arguments may follow |
| @@ -263,17 +273,19 @@ | ||
| 263 | 273 | Unlike manifests, clusters are never PGP signed. |
| 264 | 274 | |
| 265 | 275 | Allowed cards in the cluster are as follows: |
| 266 | 276 | |
| 267 | 277 | <blockquote> |
| 268 | -<b>M</b> <i>artifact-id</i><br /> | |
| 278 | +<b>M</b> <i>artifact-id</i> ?<i>alias</i><br /> | |
| 269 | 279 | <b>Z</b> <i>checksum</i> |
| 270 | 280 | </blockquote> |
| 271 | 281 | |
| 272 | 282 | A cluster contains one or more "M" cards followed by a single "Z" |
| 273 | -card. Each M card has a single argument which is the artifact ID of | |
| 274 | -another artifact in the repository. The Z card works exactly like | |
| 283 | +card. Each M card has at least on argument which is the artifact ID of | |
| 284 | +another artifact in the repository. If the M card has a second argument, | |
| 285 | +the second argument is an alias for the artifact name. | |
| 286 | +The Z card works exactly like | |
| 275 | 287 | the Z card of a manifest. The argument to the Z card is the |
| 276 | 288 | lower-case hexadecimal representation of the MD5 checksum of all |
| 277 | 289 | prior cards in the cluster. The Z-card is required. |
| 278 | 290 | |
| 279 | 291 | An example cluster from Fossil can be seen |
| @@ -647,11 +659,11 @@ | ||
| 647 | 659 | <td> </td> |
| 648 | 660 | <td> </td> |
| 649 | 661 | <td> </td> |
| 650 | 662 | </tr> |
| 651 | 663 | <tr> |
| 652 | -<td><b>M</b> <i>uuid</i></td> | |
| 664 | +<td><b>M</b> <i>uuid</i> ?<i>alias</i>?</td> | |
| 653 | 665 | <td> </td> |
| 654 | 666 | <td align=center><b>1+</b></td> |
| 655 | 667 | <td> </td> |
| 656 | 668 | <td> </td> |
| 657 | 669 | <td> </td> |
| 658 | 670 |
| --- www/fileformat.wiki | |
| +++ www/fileformat.wiki | |
| @@ -27,18 +27,28 @@ | |
| 27 | with the global state. |
| 28 | The local state is not composed of artifacts and is not intended to be enduring. |
| 29 | This document is concerned with global state only. Local state is only |
| 30 | mentioned here in order to distinguish it from global state. |
| 31 | |
| 32 | Each artifact in the repository is named by its SHA1 hash. |
| 33 | No prefixes or meta information is added to an artifact before |
| 34 | its hash is computed. The name of an artifact in the repository |
| 35 | is exactly the same SHA1 hash that is computed by sha1sum |
| 36 | on the file as it exists in your source tree.</p> |
| 37 | |
| 38 | Some artifacts have a particular format which gives them special |
| 39 | meaning to fossil. Fossil recognizes: |
| 40 | |
| 41 | <ul> |
| 42 | <li> [#manifest | Manifests] </li> |
| 43 | <li> [#cluster | Clusters] </li> |
| 44 | <li> [#ctrl | Control Artifacts] </li> |
| @@ -46,13 +56,13 @@ | |
| 46 | <li> [#tktchng | Ticket Changes] </li> |
| 47 | <li> [#attachment | Attachments] </li> |
| 48 | <li> [#event | TechNotes] </li> |
| 49 | </ul> |
| 50 | |
| 51 | These seven artifact types are described in the following sections. |
| 52 | |
| 53 | In the current implementation (as of 2009-01-25) the artifacts that |
| 54 | make up a fossil repository are stored as delta- and zlib-compressed |
| 55 | blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This |
| 56 | is an implementation detail and might change in a future release. For |
| 57 | the purpose of this article "file format" means the format of the artifacts, |
| 58 | not how the artifacts are stored on disk. It is the artifact format that |
| @@ -98,14 +108,14 @@ | |
| 98 | |
| 99 | <blockquote> |
| 100 | <b>B</b> <i>baseline-manifest</i><br> |
| 101 | <b>C</b> <i>checkin-comment</i><br> |
| 102 | <b>D</b> <i>time-and-date-stamp</i><br> |
| 103 | <b>F</b> <i>filename</i> ?<i>SHA1-hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br> |
| 104 | <b>N</b> <i>mimetype</i><br> |
| 105 | <b>P</b> <i>SHA1-hash</i>+<br> |
| 106 | <b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash</i> ?<i>SHA1-hash</i>?<br> |
| 107 | <b>R</b> <i>repository-checksum</i><br> |
| 108 | <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br> |
| 109 | <b>U</b> <i>user-login</i><br> |
| 110 | <b>Z</b> <i>manifest-checksum</i> |
| 111 | </blockquote> |
| @@ -145,11 +155,11 @@ | |
| 145 | check-in relative to the root of the project file hierarchy. No ".." |
| 146 | or "." directories are allowed within the filename. Space characters |
| 147 | are escaped as in C-card comment text. Backslash characters and |
| 148 | newlines are not allowed within filenames. The directory separator |
| 149 | character is a forward slash (ASCII 0x2F). The second argument to the |
| 150 | F-card is the full 40-character lower-case hexadecimal SHA1 hash of |
| 151 | the content artifact. The second argument is required for baseline |
| 152 | manifests but is optional for delta manifests. When the second |
| 153 | argument to the F-card is omitted, it means that the file has been |
| 154 | deleted relative to the baseline (files removed in baseline manifests |
| 155 | versions are <em>not</em> added as F-cards). The optional 3rd argument |
| @@ -167,14 +177,14 @@ | |
| 167 | is used. |
| 168 | |
| 169 | A manifest has zero or one P-cards. Most manifests have one P-card. |
| 170 | The P-card has a varying number of arguments that |
| 171 | define other manifests from which the current manifest |
| 172 | is derived. Each argument is a 40-character lowercase |
| 173 | hexadecimal SHA1 of a predecessor manifest. All arguments |
| 174 | to the P-card must be unique within that card. |
| 175 | The first argument is the SHA1 of the direct ancestor of the manifest. |
| 176 | Other arguments define manifests with which the first was |
| 177 | merged to yield the current manifest. Most manifests have |
| 178 | a P-card with a single argument. The first manifest in the |
| 179 | project has no ancestors and thus has no P-card or (depending |
| 180 | on the Fossil version) an empty P-card (no arguments). |
| @@ -241,13 +251,13 @@ | |
| 241 | <a name="cluster"></a> |
| 242 | <h2>2.0 Clusters</h2> |
| 243 | |
| 244 | A cluster is an artifact that declares the existence of other artifacts. |
| 245 | Clusters are used during repository synchronization to help |
| 246 | reduce network traffic. As such, clusters are an optimization and |
| 247 | may be removed from a repository without loss or damage to the |
| 248 | underlying project code. |
| 249 | |
| 250 | Clusters follow a syntax that is very similar to manifests. |
| 251 | A cluster is a line-oriented text file. Newline characters |
| 252 | (ASCII 0x0a) separate the artifact into cards. Each card begins with a single |
| 253 | character "card type". Zero or more arguments may follow |
| @@ -263,17 +273,19 @@ | |
| 263 | Unlike manifests, clusters are never PGP signed. |
| 264 | |
| 265 | Allowed cards in the cluster are as follows: |
| 266 | |
| 267 | <blockquote> |
| 268 | <b>M</b> <i>artifact-id</i><br /> |
| 269 | <b>Z</b> <i>checksum</i> |
| 270 | </blockquote> |
| 271 | |
| 272 | A cluster contains one or more "M" cards followed by a single "Z" |
| 273 | card. Each M card has a single argument which is the artifact ID of |
| 274 | another artifact in the repository. The Z card works exactly like |
| 275 | the Z card of a manifest. The argument to the Z card is the |
| 276 | lower-case hexadecimal representation of the MD5 checksum of all |
| 277 | prior cards in the cluster. The Z-card is required. |
| 278 | |
| 279 | An example cluster from Fossil can be seen |
| @@ -647,11 +659,11 @@ | |
| 647 | <td> </td> |
| 648 | <td> </td> |
| 649 | <td> </td> |
| 650 | </tr> |
| 651 | <tr> |
| 652 | <td><b>M</b> <i>uuid</i></td> |
| 653 | <td> </td> |
| 654 | <td align=center><b>1+</b></td> |
| 655 | <td> </td> |
| 656 | <td> </td> |
| 657 | <td> </td> |
| 658 |
| --- www/fileformat.wiki | |
| +++ www/fileformat.wiki | |
| @@ -27,18 +27,28 @@ | |
| 27 | with the global state. |
| 28 | The local state is not composed of artifacts and is not intended to be enduring. |
| 29 | This document is concerned with global state only. Local state is only |
| 30 | mentioned here in order to distinguish it from global state. |
| 31 | |
| 32 | Each artifact in the repository is named by a hash of the artifact |
| 33 | content. |
| 34 | No prefixes or meta information is added to an artifact before |
| 35 | its hash is computed. |
| 36 | |
| 37 | Each repository uses a single hash algorithm to compute artifact names. |
| 38 | The default algorithm is currently SHA3-256, though this might change |
| 39 | in future releases of Fossil. Historical versions of Fossil used |
| 40 | SHA1. The hash algorithm for a repository can be changed. When a hash |
| 41 | algorithm change occurs, a set of aliases are set up (using the |
| 42 | two-argument version of the M-card on cluster artifacts) so that the |
| 43 | older hash values can be mapped into the new hash values for artifacts |
| 44 | that were added to the repository before the hash algorithm change. |
| 45 | |
| 46 | Some artifacts have a particular format which gives them special |
| 47 | meaning to Fossil. The special artifacts are calls "structural |
| 48 | artifacts". Fossil recognizes the following kinds of structural |
| 49 | artifacts: |
| 50 | |
| 51 | <ul> |
| 52 | <li> [#manifest | Manifests] </li> |
| 53 | <li> [#cluster | Clusters] </li> |
| 54 | <li> [#ctrl | Control Artifacts] </li> |
| @@ -46,13 +56,13 @@ | |
| 56 | <li> [#tktchng | Ticket Changes] </li> |
| 57 | <li> [#attachment | Attachments] </li> |
| 58 | <li> [#event | TechNotes] </li> |
| 59 | </ul> |
| 60 | |
| 61 | These seven structural artifact types are described in the following sections. |
| 62 | |
| 63 | In the current implementation (as of 2017-02-27) the artifacts that |
| 64 | make up a fossil repository are stored as delta- and zlib-compressed |
| 65 | blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This |
| 66 | is an implementation detail and might change in a future release. For |
| 67 | the purpose of this article "file format" means the format of the artifacts, |
| 68 | not how the artifacts are stored on disk. It is the artifact format that |
| @@ -98,14 +108,14 @@ | |
| 108 | |
| 109 | <blockquote> |
| 110 | <b>B</b> <i>baseline-manifest</i><br> |
| 111 | <b>C</b> <i>checkin-comment</i><br> |
| 112 | <b>D</b> <i>time-and-date-stamp</i><br> |
| 113 | <b>F</b> <i>filename</i> ?<i>hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br> |
| 114 | <b>N</b> <i>mimetype</i><br> |
| 115 | <b>P</b> <i>artifact-hash</i>+<br> |
| 116 | <b>Q</b> (<b>+</b>|<b>-</b>)<i>artifact-hash</i> ?<i>artifact-hash</i>?<br> |
| 117 | <b>R</b> <i>repository-checksum</i><br> |
| 118 | <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br> |
| 119 | <b>U</b> <i>user-login</i><br> |
| 120 | <b>Z</b> <i>manifest-checksum</i> |
| 121 | </blockquote> |
| @@ -145,11 +155,11 @@ | |
| 155 | check-in relative to the root of the project file hierarchy. No ".." |
| 156 | or "." directories are allowed within the filename. Space characters |
| 157 | are escaped as in C-card comment text. Backslash characters and |
| 158 | newlines are not allowed within filenames. The directory separator |
| 159 | character is a forward slash (ASCII 0x2F). The second argument to the |
| 160 | F-card is the lower-case hexadecimal artifact hash of |
| 161 | the content artifact. The second argument is required for baseline |
| 162 | manifests but is optional for delta manifests. When the second |
| 163 | argument to the F-card is omitted, it means that the file has been |
| 164 | deleted relative to the baseline (files removed in baseline manifests |
| 165 | versions are <em>not</em> added as F-cards). The optional 3rd argument |
| @@ -167,14 +177,14 @@ | |
| 177 | is used. |
| 178 | |
| 179 | A manifest has zero or one P-cards. Most manifests have one P-card. |
| 180 | The P-card has a varying number of arguments that |
| 181 | define other manifests from which the current manifest |
| 182 | is derived. Each argument is a lowercase |
| 183 | hexadecimal artifact hash of a predecessor manifest. All arguments |
| 184 | to the P-card must be unique within that card. |
| 185 | The first argument is the artifact hash of the direct ancestor of the manifest. |
| 186 | Other arguments define manifests with which the first was |
| 187 | merged to yield the current manifest. Most manifests have |
| 188 | a P-card with a single argument. The first manifest in the |
| 189 | project has no ancestors and thus has no P-card or (depending |
| 190 | on the Fossil version) an empty P-card (no arguments). |
| @@ -241,13 +251,13 @@ | |
| 251 | <a name="cluster"></a> |
| 252 | <h2>2.0 Clusters</h2> |
| 253 | |
| 254 | A cluster is an artifact that declares the existence of other artifacts. |
| 255 | Clusters are used during repository synchronization to help |
| 256 | reduce network traffic. Clusters are also used to record aliases |
| 257 | for artifact names, so that if the artifact hash algorithm changes, |
| 258 | artifacts can still be looked up using the older hash algorithm. |
| 259 | |
| 260 | Clusters follow a syntax that is very similar to manifests. |
| 261 | A cluster is a line-oriented text file. Newline characters |
| 262 | (ASCII 0x0a) separate the artifact into cards. Each card begins with a single |
| 263 | character "card type". Zero or more arguments may follow |
| @@ -263,17 +273,19 @@ | |
| 273 | Unlike manifests, clusters are never PGP signed. |
| 274 | |
| 275 | Allowed cards in the cluster are as follows: |
| 276 | |
| 277 | <blockquote> |
| 278 | <b>M</b> <i>artifact-id</i> ?<i>alias</i><br /> |
| 279 | <b>Z</b> <i>checksum</i> |
| 280 | </blockquote> |
| 281 | |
| 282 | A cluster contains one or more "M" cards followed by a single "Z" |
| 283 | card. Each M card has at least on argument which is the artifact ID of |
| 284 | another artifact in the repository. If the M card has a second argument, |
| 285 | the second argument is an alias for the artifact name. |
| 286 | The Z card works exactly like |
| 287 | the Z card of a manifest. The argument to the Z card is the |
| 288 | lower-case hexadecimal representation of the MD5 checksum of all |
| 289 | prior cards in the cluster. The Z-card is required. |
| 290 | |
| 291 | An example cluster from Fossil can be seen |
| @@ -647,11 +659,11 @@ | |
| 659 | <td> </td> |
| 660 | <td> </td> |
| 661 | <td> </td> |
| 662 | </tr> |
| 663 | <tr> |
| 664 | <td><b>M</b> <i>uuid</i> ?<i>alias</i>?</td> |
| 665 | <td> </td> |
| 666 | <td align=center><b>1+</b></td> |
| 667 | <td> </td> |
| 668 | <td> </td> |
| 669 | <td> </td> |
| 670 |