* Re: [PATCH] close clobbers mmap's errno in read_cache
From: Sven Verdoolaege @ 2005-10-07 21:48 UTC (permalink / raw)
To: Alex Riesen; +Cc: Junio C Hamano, git
In-Reply-To: <20051007214551.GA8893@steel.home>
On Fri, Oct 07, 2005 at 11:45:51PM +0200, Alex Riesen wrote:
> }
> + i = errno;
> close(fd);
> if (map == MAP_FAILED)
> - die("index file mmap failed (%s)", strerror(errno));
> + die("index file mmap failed (%s)", strerror(i));
>
Why don't you just move the close after the test ?
There's no point in closing if you're going to die.
skimo
^ permalink raw reply
* [PATCH] close clobbers mmap's errno in read_cache
From: Alex Riesen @ 2005-10-07 21:45 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Save errno before close(fd) for strerror in die().
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
--- a/read-cache.c 2005-10-03 09:16:31.000000000 +0200
+++ b/read-cache.c 2005-10-07 23:23:40.000000000 +0200
@@ -482,9 +482,10 @@ int read_cache(void)
if (size >= sizeof(struct cache_header) + 20)
map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
}
+ i = errno;
close(fd);
if (map == MAP_FAILED)
- die("index file mmap failed (%s)", strerror(errno));
+ die("index file mmap failed (%s)", strerror(i));
hdr = map;
if (verify_hdr(hdr, size) < 0)
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Alex Riesen @ 2005-10-07 21:39 UTC (permalink / raw)
To: Chuck Lever
Cc: Git Mailing List, Junio C Hamano, Linus Torvalds,
Christopher Faylor, H. Peter Anvin
In-Reply-To: <4346E8AC.5030503@citi.umich.edu>
Chuck Lever, Fri, Oct 07, 2005 23:29:16 +0200:
> s/malloc/xmalloc/
It's not that funny after second repost...
---
Make read_cache copy the index into memory, to improve portability on
other OS's which have mmap too, tend to use it less commonly.
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -497,9 +497,12 @@ int read_cache(void)
offset = sizeof(*hdr);
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = map + offset;
- offset = offset + ce_size(ce);
- active_cache[i] = ce;
+ size_t size = ce_size(ce);
+ struct cache_entry *newce = xmalloc(size);
+ offset = offset + size;
+ active_cache[i] = memcpy(newce, ce, size);
}
+ munmap(map, size);
return active_nr;
unmap:
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Chuck Lever @ 2005-10-07 21:29 UTC (permalink / raw)
To: Alex Riesen
Cc: Git Mailing List, Junio C Hamano, Linus Torvalds,
Christopher Faylor, H. Peter Anvin
In-Reply-To: <20051007212250.GA1423@steel.home>
[-- Attachment #1: Type: text/plain, Size: 752 bytes --]
Alex Riesen wrote:
> Make read_cache copy the index into memory, to improve portability on
> other OS's which have mmap too, tend to use it less commonly.
>
> Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
>
> diff --git a/read-cache.c b/read-cache.c
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -497,9 +497,12 @@ int read_cache(void)
> offset = sizeof(*hdr);
> for (i = 0; i < active_nr; i++) {
> struct cache_entry *ce = map + offset;
> - offset = offset + ce_size(ce);
> - active_cache[i] = ce;
> + size_t size = ce_size(ce);
> + struct cache_entry *newce = malloc(size);
> + offset = offset + size;
> + active_cache[i] = memcpy(newce, ce, size);
> }
> + munmap(map, size);
> return active_nr;
>
> unmap:
s/malloc/xmalloc/
[-- Attachment #2: cel.vcf --]
[-- Type: text/x-vcard, Size: 439 bytes --]
begin:vcard
fn:Chuck Lever
n:Lever;Charles
org:Network Appliance, Incorporated;Linux NFS Client Development
adr:535 West William Street, Suite 3100;;Center for Information Technology Integration;Ann Arbor;MI;48103-4943;USA
email;internet:cel@citi.umich.edu
title:Member of Technical Staff
tel;work:+1 734 763 4415
tel;fax:+1 734 763 4434
tel;home:+1 734 668 1089
x-mozilla-html:FALSE
url:http://www.monkey.org/~cel/
version:2.1
end:vcard
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Alex Riesen @ 2005-10-07 21:22 UTC (permalink / raw)
To: Git Mailing List
Cc: Junio C Hamano, Linus Torvalds, Christopher Faylor,
H. Peter Anvin
In-Reply-To: <20051007205450.GA14827@steel.home>
Alex Riesen, Fri, Oct 07, 2005 22:54:50 +0200:
> Linus Torvalds, Fri, Oct 07, 2005 17:34:19 +0200:
> > > it suddenly get worse: now I'm stuck on git-pull.
> > >
> > > git-merge-index (called at some point by git-pull) maps the index
> > > in, and starts git-merge-one-file for each (or the given) entry in
> > > the index. git-merge-one-file calls git-update-index, which wants
> > > to update the index. Which doesn't work, because it's locked by
> > > that piece of s$%^.
> >
> > NOTE! git doesn't use mmap() because it _needs_ to use mmap(), but because
> > it was simple to do that way, and it's a total idiosyncracy of mine that I
> > often try to mmap the data. I often also tend to do my own allocators
> > instead of using malloc() (see my "sparse" project in case you're
> > interested in other idiosyncracies of mine - macros to do list traversal
> > etc).
> >
> > The fact is, "mmap()" isn't really any better than "read()": it has some
> > advantages wrt memory management for the kernel, which is probably one big
> > reason why I do it, but quite frankly, if you were to change every single
> > mmap() to be a "map_file()" instead, and made it optional whether it used
> > mmap() or "malloc + read()", I personally don't think it would be
> > horrible.
> >
> > And it might make things much simpler for portability. The "use mmap"
> > approach is very much a unixism, particularly the way unix people do it
> > (mmap followed by close, making the file descriptor "go away"). Sure,
> > other OS's have mmap too, but I think on them it tends to be less commonly
> > used.
>
> "Sounds like a thinly veiled threat or a very effective prodding" 8)
>
Junio C Hamano, Fri, Oct 07, 2005 23:00:02 +0200:
> Huh? where is your memcpy?
Unbelievable... I actually tested the change! But not _the_ patch.
Thanks. Next time, hit me :)
---
Make read_cache copy the index into memory, to improve portability on
other OS's which have mmap too, tend to use it less commonly.
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -497,9 +497,12 @@ int read_cache(void)
offset = sizeof(*hdr);
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = map + offset;
- offset = offset + ce_size(ce);
- active_cache[i] = ce;
+ size_t size = ce_size(ce);
+ struct cache_entry *newce = malloc(size);
+ offset = offset + size;
+ active_cache[i] = memcpy(newce, ce, size);
}
+ munmap(map, size);
return active_nr;
unmap:
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Alex Riesen @ 2005-10-07 20:54 UTC (permalink / raw)
To: Git Mailing List
Cc: Linus Torvalds, Christopher Faylor, Junio C Hamano,
H. Peter Anvin
In-Reply-To: <Pine.LNX.4.64.0510070828270.31407@g5.osdl.org>
Linus Torvalds, Fri, Oct 07, 2005 17:34:19 +0200:
> > it suddenly get worse: now I'm stuck on git-pull.
> >
> > git-merge-index (called at some point by git-pull) maps the index
> > in, and starts git-merge-one-file for each (or the given) entry in
> > the index. git-merge-one-file calls git-update-index, which wants
> > to update the index. Which doesn't work, because it's locked by
> > that piece of s$%^.
>
> NOTE! git doesn't use mmap() because it _needs_ to use mmap(), but because
> it was simple to do that way, and it's a total idiosyncracy of mine that I
> often try to mmap the data. I often also tend to do my own allocators
> instead of using malloc() (see my "sparse" project in case you're
> interested in other idiosyncracies of mine - macros to do list traversal
> etc).
>
> The fact is, "mmap()" isn't really any better than "read()": it has some
> advantages wrt memory management for the kernel, which is probably one big
> reason why I do it, but quite frankly, if you were to change every single
> mmap() to be a "map_file()" instead, and made it optional whether it used
> mmap() or "malloc + read()", I personally don't think it would be
> horrible.
>
> And it might make things much simpler for portability. The "use mmap"
> approach is very much a unixism, particularly the way unix people do it
> (mmap followed by close, making the file descriptor "go away"). Sure,
> other OS's have mmap too, but I think on them it tends to be less commonly
> used.
"Sounds like a thinly veiled threat or a very effective prodding" 8)
---
Make read_cache copy the index into memory, to improve portability on
other OS's which have mmap too, tend to use it less commonly.
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -497,9 +497,11 @@ int read_cache(void)
offset = sizeof(*hdr);
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = map + offset;
- offset = offset + ce_size(ce);
- active_cache[i] = ce;
+ size_t size = ce_size(ce);
+ offset = offset + size;
+ active_cache[i] = malloc(ce, size);
}
+ munmap(map, size);
return active_nr;
unmap:
^ permalink raw reply
* Re: Some ASCII Art
From: Junio C Hamano @ 2005-10-07 19:42 UTC (permalink / raw)
To: Jon Loeliger; +Cc: Git List
In-Reply-To: <1128713749.29904.84.camel@cashmere.sps.mot.com>
Jon Loeliger <jdl@freescale.com> writes:
> Would it be a useful option to git-show-branch
> that would state the commit SHA1s as well?
>
> % git show-branch --show-revs
>
> * [master] Merge paul's branch
> ! [origin] Fix drm 'debug' sysfs permissions
> ! [paul] powerpc: Fix idle.c compile warning
> ---
> + [06a41091c93e529e6cef68ba60deeb1b9ceabc7f] Merge paul's branch
> + + [05f62a5c049845eab8dfb3aeda55c18a2d4396e3] powerpc: Fix idle.c compile warning
> + + [c16ff7e44883afc05cbf6fde0e6913bb10c66885] powerpc: Define a _sdata symbol
> + + [8dad3f9257414f151cd821bfe01f54d7f52d2507] powerpc: Merge traps.c a bit more
> + + [b3491269f5604e4265ee2f27b47a76ce1e3678b6] powerpc: Use the merged of_device.c with ARCH=powerpc
In practice, probably 30 or so bits prefix would identify an
object uniquely within a repository, so one possibility is to
use the first 7 or so letters from 40-byte SHA1, after making
sure 7 is enough for that particular prefix -- otherwise use
more for that particular object.
The current "relative to the head" notation is descriptive and
easier to see when you do not have too many branches and complex
merge structure but one major drawback is that it is not stable;
you add a commit then what was used to be master~5 now suddenly
become master~6.
^ permalink raw reply
* Re: Some ASCII Art
From: Jon Loeliger @ 2005-10-07 19:35 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git List
In-Reply-To: <7v8xx67559.fsf@assigned-by-dhcp.cox.net>
On Thu, 2005-10-06 at 15:38, Junio C Hamano wrote:
> Jon Loeliger <jdl@freescale.com> writes:
>
> > Fundamental Git Index Operations
> > Git Index Operations
>
> These two look almost the same.
Yeah, the first one was intended to capture the
operations discussed the first four points of the
"The Workflow" section of the main Git doc page.
The second is "more of same", but the one picture with
every ASCII arc on it was getting confusing and crowded.
> I find the label "commit-tree" on index -> odb in the second
> picture a bit misleading. "commit-tree" takes a tree and zero
> or more commit objects to create a new commit object, so it
> works solely inside odb.
Ah! Of course. Thanks!
> It is good that you mention that "read-tree -u" form updates
> working tree in the second picture.
Discovering how this related was a key insight for me. :-)
> In the same spirit, you
> might also want to mention that "checkout-index -u" updates the
> index (i.e. matches the stat information) in the same picture.
Ooh. Yes! Good idea.
> > Commit DAG Revision Naming
> > ==========================
> >
> > Both node B and C are a commit parents of node A.
>
> I assume that parents are left to right in this picture, that
> is, B's first parent is D, second E, and third F.
Yeah, I even meant to add that sentence before
sending the mail.
> > Is there a way to name node C, E, F, H, I or J?
>
> C = A^2
> E = B^2 = A^^2
> F = B^3 = A^^3
> H = D^2 = B^^2 = A^^^2 = A~2^2
> I = F^ = B^3^ = A^^3^
> J = F^2 = B^3^2 = A^^3^2
Ah!
> They look like line noise ;-)
Indeed. :-)
Would it be a useful option to git-show-branch
that would state the commit SHA1s as well?
% git show-branch --show-revs
* [master] Merge paul's branch
! [origin] Fix drm 'debug' sysfs permissions
! [paul] powerpc: Fix idle.c compile warning
---
+ [06a41091c93e529e6cef68ba60deeb1b9ceabc7f] Merge paul's branch
+ + [05f62a5c049845eab8dfb3aeda55c18a2d4396e3] powerpc: Fix idle.c compile warning
+ + [c16ff7e44883afc05cbf6fde0e6913bb10c66885] powerpc: Define a _sdata symbol
+ + [8dad3f9257414f151cd821bfe01f54d7f52d2507] powerpc: Merge traps.c a bit more
+ + [b3491269f5604e4265ee2f27b47a76ce1e3678b6] powerpc: Use the merged of_device.c with ARCH=powerpc
Thanks for your feedback!
jdl
^ permalink raw reply
* [RFC] embedded TAB and LF in pathnames
From: Junio C Hamano @ 2005-10-07 19:35 UTC (permalink / raw)
To: git; +Cc: Kai Ruemmler
While I was reviewing git-status fix by Kai Ruemmler, it struck
me that our barebone Porcelain-ish layer got a bit sloppier over
time. The core layer does not care about any metacharacters in
the pathname, and it has provisions, primarily in the form of
'-z' flag, for carefully written Porcelain layers to handle
pathnames with embedded metacharacters correctly.
One exception, however, is the interaction between the git-diff
family output and git-apply. We needed to be compatible with
other people's diff, which meant that we should not have to
worry too much about pathnames with embedded TABs and LFs
because GNU diff would not produce usable diff for such things
anyway. But 'git-diff --names' barfing if a pathname contained
these characters when run without '-z' flag was too much. This
still breaks 'git-status'.
So I am considering the following changes:
- 'raw' output format without '-z', upon finding a TAB or LF,
would not die, but just issue a warning. However, the paths
are "munged" in a way described later.
- '--name-only' and '--name-status' format issue the same
warning when finding these characters and run without '-z'.
And the paths are "munged" as well.
- 'patch' output format also issues a warning. The paths are
"munged" but in a slightly different manner from the above.
- 'git-apply' is taught about the path munging in the diff
input for git diffs (i.e. 'diff --git') and do sensible
things.
One possible way for path munging goes like this. We could take
advantage of the fact that we do not ever output '//' ourselves,
and '//' never appears in valid diffs by other people's tools,
unless done deliberately by hand ("diff -u a//foo. b//foo.c"
from the command line). So we could use '//' as if it is a
backslash. Examples.
"foo/bar.c" --> "foo/bar.c" (no funny letters - as before)
"foo\nbar" --> "foo//0Abar" (double slash followed by 2 hex)
"foo\tbar" --> "foo//09bar" (double slash followed by 2 hex)
So a diff output to rename "foo/bar.c" to "foo\nbar.c" would
become:
diff --git a/foo/bar.c b/foo//0Abar.c
similarity index 100%
rename from foo
rename to foo//0Abar.c
The byte-values subject to this munging is LF for patch output
(because git-apply seems to grok TABs in pathnames just fine),
and TAB and LF for 'raw', '--name-only', '--name-status' without
'-z'.
I have not made up my mind on the exact choice of the quoting
convention. We could say '///' instead of '//', for example, or
even '//{LF}//' instead of '//0A' proposed above. One thing I
am trying to avoid is "foo\nbar", which I suspect would be
unfriendly to the Cygwin folks.
^ permalink raw reply
* Re: [PATCH] Add support for parallel HTTP transfers
From: Junio C Hamano @ 2005-10-07 18:08 UTC (permalink / raw)
To: Nick Hengeveld; +Cc: Daniel Barkalow, git
In-Reply-To: <20051007172206.GK15593@reactrix.com>
Nick Hengeveld <nickh@reactrix.com> writes:
> I think the only downside to leaving that check in place is that when
> pull() finishes there may be completed requests left behind in the
> queue, possibly with unreported transfer errors. Would it make sense
> to just release any requests left in the queue after pull(), and report
> if any of them had transfer errors?
Pull finishing and reporting success while some requests have
still been outstanding with transfer errors sounds to me that
decision to finish and declare success is made prematurely.
What do these leftover requests you are worried about ask for?
Are you making redundant requests, which can turn out to be
unneeded?
^ permalink raw reply
* Re: [PATCH] Add support for parallel HTTP transfers
From: Junio C Hamano @ 2005-10-07 18:08 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0510071323070.23242@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
>> The check was added in 029f6de377c7e0484f5c4cf070934599580f1784
>> because back then calling fetch() on an object that we already
>> had had a funny interaction with what http-fetch.c did. I
>> suspect that Nick's curl-multi changes made it unnecessary, but
>> you should double check for other transports.
>
> Hmm; my intended convention was that fetch() would always be called if
> prefetch() was called, even if something had happened to make it appear in
> between (e.g., prefetch() causing it to be fetched or a different call to
> fetch() speculatively also getting it).
When I re-read the code, I think that check was probably a wrong
fix to begin with.
The original problem sequence, when the http-fetch was still
synchronous, was this:
(1) we ask for an object, fetch_object() did not find one and
fetch_pack() got a pack that contained the object and
installed it; the pack is removed from the "yet to be
downloaded from this repository" list.
(2) we ask for another object, fetch_object() did not find one
and fetch_pack() was asked to see if there is a pack we
have not downloaded that contained the object -- the pack
downloaded in step (1) did not count, and this request
failed. Overall fetch() said "Nope, I cannot get it", when
it already had one.
We should remove that check as you suggested, and fix fetch()
implementation in http-fetch.c to notice the above situation,
perhaps?
^ permalink raw reply
* Re: [PATCH] Add support for parallel HTTP transfers
From: Daniel Barkalow @ 2005-10-07 17:41 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Nick Hengeveld
In-Reply-To: <7v8xx55kia.fsf@assigned-by-dhcp.cox.net>
On Fri, 7 Oct 2005, Junio C Hamano wrote:
> Daniel Barkalow <barkalow@iabervon.org> writes:
>
> >> > It should be fine to download objects and a pack that contains them at the
> >> > same time, although there's currently a check in fetch.c which should be
> >> > removed, so that it will call fetch() for an object if the object appears
> >> > between the prefetch() and the fetch().
> >>
> >> Can you provide a patch, or point me toward the right place to make that
> >> change?
> >
> > It's line 168 of fetch.c; the "!has_sha1_file(obj->sha1)" part should go
> > away.
>
> The check was added in 029f6de377c7e0484f5c4cf070934599580f1784
> because back then calling fetch() on an object that we already
> had had a funny interaction with what http-fetch.c did. I
> suspect that Nick's curl-multi changes made it unnecessary, but
> you should double check for other transports.
Hmm; my intended convention was that fetch() would always be called if
prefetch() was called, even if something had happened to make it appear in
between (e.g., prefetch() causing it to be fetched or a different call to
fetch() speculatively also getting it).
The ssh transport actually wants to not have the check (if the object
appears out of nowhere after we request it, we still want to read it out
of the connection).
The local transport probably ought to have the check added on line 169 of
local-fetch.c
In general, transports need to deal with this case themselves, because the
core code doesn't know if they started something in prefetch() than needs
to get finished in fetch().
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH] Add support for parallel HTTP transfers
From: Nick Hengeveld @ 2005-10-07 17:22 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Daniel Barkalow, git
In-Reply-To: <7v8xx55kia.fsf@assigned-by-dhcp.cox.net>
On Fri, Oct 07, 2005 at 10:01:33AM -0700, Junio C Hamano wrote:
> The check was added in 029f6de377c7e0484f5c4cf070934599580f1784
> because back then calling fetch() on an object that we already
> had had a funny interaction with what http-fetch.c did. I
> suspect that Nick's curl-multi changes made it unnecessary, but
> you should double check for other transports.
I think the only downside to leaving that check in place is that when
pull() finishes there may be completed requests left behind in the
queue, possibly with unreported transfer errors. Would it make sense
to just release any requests left in the queue after pull(), and report
if any of them had transfer errors?
--
For a successful technology, reality must take precedence over public
relations, for nature cannot be fooled.
^ permalink raw reply
* Re: [PATCH] Add support for parallel HTTP transfers
From: Junio C Hamano @ 2005-10-07 17:01 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git, Nick Hengeveld
In-Reply-To: <Pine.LNX.4.63.0510071149550.23242@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
>> > It should be fine to download objects and a pack that contains them at the
>> > same time, although there's currently a check in fetch.c which should be
>> > removed, so that it will call fetch() for an object if the object appears
>> > between the prefetch() and the fetch().
>>
>> Can you provide a patch, or point me toward the right place to make that
>> change?
>
> It's line 168 of fetch.c; the "!has_sha1_file(obj->sha1)" part should go
> away.
The check was added in 029f6de377c7e0484f5c4cf070934599580f1784
because back then calling fetch() on an object that we already
had had a funny interaction with what http-fetch.c did. I
suspect that Nick's curl-multi changes made it unnecessary, but
you should double check for other transports.
^ permalink raw reply
* [PATCH] Create object subdirectories on demand (phase II)
From: Junio C Hamano @ 2005-10-07 16:30 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <7vfyrd7jll.fsf@assigned-by-dhcp.cox.net>
This removes the unoptimization. The previous round does not mind
missing fan-out directories, but still makes sure they exist, lest
older versions choke on a repository created/packed by it.
This round does not play that nicely anymore -- empty fan-out
directories are not created by init-db, and will stay removed by
prune-packed. The prune command also removes empty fan-out directories.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
Here is what I did. I unoptimized your original and that
sits near the tip of "pu" branch. This patch is to revert
the unoptimization. In addition, git-prune is told about
the empty fan-out removal, although it may not matter that
much. Hopefully, the phase I can be included in the next
official release, and after everybody updates, this patch
can go in.
git-prune.sh | 1 +
init-db.c | 4 ----
prune-packed.c | 3 +--
t/t0000-basic.sh | 8 ++++----
4 files changed, 6 insertions(+), 10 deletions(-)
applies-to: d672cb30d513553ea3ca92a933563a25df1d7865
93638ce0a569543d0b41eedfac6873a541f5c753
diff --git a/git-prune.sh b/git-prune.sh
index 9657dbf..b28630c 100755
--- a/git-prune.sh
+++ b/git-prune.sh
@@ -22,6 +22,7 @@ sed -ne '/unreachable /{
}' | {
cd "$GIT_OBJECT_DIRECTORY" || exit
xargs $echo rm -f
+ rmdir 2>/dev/null [0-9a-f][0-9a-f]
}
git-prune-packed $dryrun
diff --git a/init-db.c b/init-db.c
index aabc09f..921df9b 100644
--- a/init-db.c
+++ b/init-db.c
@@ -244,10 +244,6 @@ int main(int argc, char **argv)
memcpy(path, sha1_dir, len);
safe_create_dir(sha1_dir);
- for (i = 0; i < 256; i++) {
- sprintf(path+len, "/%02x", i);
- safe_create_dir(path);
- }
strcpy(path+len, "/pack");
safe_create_dir(path);
strcpy(path+len, "/info");
diff --git a/prune-packed.c b/prune-packed.c
index 73f0f3a..16685d1 100644
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -27,8 +27,7 @@ static void prune_dir(int i, DIR *dir, c
error("unable to unlink %s", pathname);
}
pathname[len] = 0;
- if (rmdir(pathname))
- mkdir(pathname, 0777);
+ rmdir(pathname);
}
static void prune_packed_objects(void)
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 5c5f854..dff7d69 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -28,12 +28,12 @@ test_expect_success \
'.git/objects should be empty after git-init-db in an empty repo.' \
'cmp -s /dev/null should-be-empty'
-# also it should have 258 subdirectories; 256 fan-out anymore, pack, and info.
-# 259 is counting "objects" itself
+# also it should have 2 subdirectories; no fan-out anymore, pack, and info.
+# 3 is counting "objects" itself
find .git/objects -type d -print >full-of-directories
test_expect_success \
- '.git/objects should have 258 subdirectories.' \
- 'test $(wc -l < full-of-directories) = 259'
+ '.git/objects should have 3 subdirectories.' \
+ 'test $(wc -l < full-of-directories) = 3'
################################################################
# Basics of the basics
---
0.99.8.GIT
^ permalink raw reply related
* Re: [PATCH] Add support for parallel HTTP transfers
From: Daniel Barkalow @ 2005-10-07 16:23 UTC (permalink / raw)
To: Nick Hengeveld; +Cc: git
In-Reply-To: <20051007000041.GH15593@reactrix.com>
On Thu, 6 Oct 2005, Nick Hengeveld wrote:
> On Thu, Oct 06, 2005 at 04:07:07PM -0400, Daniel Barkalow wrote:
>
> > Somewhat weirdly, the version of curl on my desktop doesn't actually have
> > an implementation of curl_multi_info_read, although it's in the header
> > file and documentation. So you'll want a version check somewhere, I think,
> > which should probably just disable parallel transfers.
>
> I was afraid that was going to happen... From the archived versions on the
> CURL download site, it looks as though multi support was added in 7.9.8 -
> which version do you have installed on your desktop?
I'll have to check, but I think it's 7.9.8 or close to that; it seems like
they added multi support without a critical function, so you might need to
bump the check from what the history would suggest.
> > It should be fine to download objects and a pack that contains them at the
> > same time, although there's currently a check in fetch.c which should be
> > removed, so that it will call fetch() for an object if the object appears
> > between the prefetch() and the fetch().
>
> Can you provide a patch, or point me toward the right place to make that
> change?
It's line 168 of fetch.c; the "!has_sha1_file(obj->sha1)" part should go
away.
> > I should be able to review this over the weekend. What sort of performance
> > are you getting at this point (in terms of bandwidth utilization)?
>
> I've done limited testing by using the time command to track real/user/sys
> taken to run 'git fetch http://kernel.org/pub/scm/git/git.git master',
> and have seen performance improve by a factor of ~2-10:
That looks good. I think it might be good to set the default connection
limit higher; I don't think we can generate enough parallelism that we'd
cause problems for a server with a single client, and, with a constant
stream of clients, this will just shuffle around when the connections
happen; to the extent that a single client does more simultaneous
connections, it'll overlap less with other clients.
> About that "-r" arg - seems like it should be something else as -r is
> used elsewhere in git to enable recursion. "-c" was my first thought,
> but that's used to fetch commit objects.
The other things that affect the behaviour of the HTTP fetch in particular
are done as environment variables, which seems like a good idea to me.
Alternatively, you could use a long option. I don't expect there will be
much variation in what someone uses.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* [PATCH] Set the parallel HTTP request limit via an environment variable
From: Nick Hengeveld @ 2005-10-07 15:59 UTC (permalink / raw)
To: git
Use an environment variable rather than a command-line argument to set the
parallel HTTP request limit. This allows the setting to work whether
git-http-fetch is run directly or via git-fetch.
Signed-off-by: Nick Hengeveld <nickh@reactrix.com>
---
http-fetch.c | 17 ++++++-----------
1 files changed, 6 insertions(+), 11 deletions(-)
a508fd4ba7300476e6ad029fca10371ca869af1e
diff --git a/http-fetch.c b/http-fetch.c
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -1034,22 +1034,11 @@ int main(int argc, char **argv)
arg++;
} else if (!strcmp(argv[arg], "--recover")) {
get_recover = 1;
-#ifdef USE_CURL_MULTI
- } else if (argv[arg][1] == 'r') {
- max_requests = atoi(argv[arg + 1]);
- if (max_requests < 1)
- max_requests = DEFAULT_MAX_REQUESTS;
- arg++;
-#endif
}
arg++;
}
if (argc < arg + 2) {
-#ifdef USE_CURL_MULTI
- usage("git-http-fetch [-c] [-t] [-a] [-d] [-v] [-r concurrent-request-limit] [--recover] [-w ref] commit-id url");
-#else
usage("git-http-fetch [-c] [-t] [-a] [-d] [-v] [--recover] [-w ref] commit-id url");
-#endif
return 1;
}
commit_id = argv[arg];
@@ -1058,6 +1047,12 @@ int main(int argc, char **argv)
curl_global_init(CURL_GLOBAL_ALL);
#ifdef USE_CURL_MULTI
+ char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
+ if (http_max_requests != NULL)
+ max_requests = atoi(http_max_requests);
+ if (max_requests < 1)
+ max_requests = DEFAULT_MAX_REQUESTS;
+
curlm = curl_multi_init();
if (curlm == NULL) {
fprintf(stderr, "Error creating curl multi handle.\n");
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Linus Torvalds @ 2005-10-07 15:34 UTC (permalink / raw)
To: Alex Riesen
Cc: Git Mailing List, Christopher Faylor, Junio C Hamano,
H. Peter Anvin
In-Reply-To: <81b0412b0510070544v3e7cf0b4n521db8ff7e4e335a@mail.gmail.com>
On Fri, 7 Oct 2005, Alex Riesen wrote:
>
> it suddenly get worse: now I'm stuck on git-pull.
>
> git-merge-index (called at some point by git-pull) maps the index in, and starts
> git-merge-one-file for each (or the given) entry in the index.
> git-merge-one-file
> calls git-update-index, which wants to update the index. Which doesn't work,
> because it's locked by that piece of s$%^.
NOTE! git doesn't use mmap() because it _needs_ to use mmap(), but because
it was simple to do that way, and it's a total idiosyncracy of mine that I
often try to mmap the data. I often also tend to do my own allocators
instead of using malloc() (see my "sparse" project in case you're
interested in other idiosyncracies of mine - macros to do list traversal
etc).
The fact is, "mmap()" isn't really any better than "read()": it has some
advantages wrt memory management for the kernel, which is probably one big
reason why I do it, but quite frankly, if you were to change every single
mmap() to be a "map_file()" instead, and made it optional whether it used
mmap() or "malloc + read()", I personally don't think it would be
horrible.
And it might make things much simpler for portability. The "use mmap"
approach is very much a unixism, particularly the way unix people do it
(mmap followed by close, making the file descriptor "go away"). Sure,
other OS's have mmap too, but I think on them it tends to be less commonly
used.
Linus
^ permalink raw reply
* Re: Create object subdirectories on demand
From: Linus Torvalds @ 2005-10-07 14:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vfyrd7jll.fsf@assigned-by-dhcp.cox.net>
On Fri, 7 Oct 2005, Junio C Hamano wrote:
>
> But then once everybody else updates, the repository their git
> creates cannot be read by my git -- an interesting chicken and
> egg problem.
Well, you can do it in two (or three) phases:
(a) remove the tests for "GIT_DIR/objects/00" from the "is this a
git dir" tests and allow git-fsck-objects to skip missing
directories.
This makes read-only operations work fine in sparse directories
(b) apply my sha1_file.c part of the patch that knows how to do the mkdir
and also fixes (untested!) the write_sha1_from_fd() problem.
This makes all operations work fine in sparse object directories
(c) remove the "for(i = 0; i < 256; i++) mkdir(i)" thing from git-init-db
and add the "rmdir()" to git-prune-packed.
This is the part that actually generates the sparse object directories.
So if you apply (a+b) to mainline, and wait with (c) until a later date,
at least we can then do (c) at any point. No hurry.
Appended is a suggested split, if you want it explicitly. I haven't
actually tested this split and did it by hand, but it looks correct.
Linus
---- stage (a) ----
Phase 1: don't require the object subdirectories to be there if empty
diff --git a/daemon.c b/daemon.c
--- a/daemon.c
+++ b/daemon.c
@@ -142,7 +142,7 @@ static int upload(char *dir, int dirlen)
* is ok with us doing this.
*/
if ((!export_all_trees && access("git-daemon-export-ok", F_OK)) ||
- access("objects/00", X_OK) ||
+ access("objects/", X_OK) ||
access("HEAD", R_OK)) {
logerror("Not a valid git-daemon-enabled repository: '%s'", dir);
return -1;
diff --git a/fsck-objects.c b/fsck-objects.c
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -329,9 +329,8 @@ static int fsck_dir(int i, char *path)
DIR *dir = opendir(path);
struct dirent *de;
- if (!dir) {
- return error("missing sha1 directory '%s'", path);
- }
+ if (!dir)
+ return 0;
while ((de = readdir(dir)) != NULL) {
char name[100];
diff --git a/git-rename.perl b/git-rename.perl
--- a/git-rename.perl
+++ b/git-rename.perl
@@ -15,7 +15,7 @@ sub usage($);
my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" &&
- -d $GIT_DIR . "/objects/00" && -d $GIT_DIR . "/refs") {
+ -d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
usage("Git repository not found.");
}
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -22,4 +22,4 @@ refs/*) : ;;
*) false ;;
esac &&
[ -d "$GIT_DIR/refs" ] &&
-[ -d "$GIT_OBJECT_DIRECTORY/00" ]
+[ -d "$GIT_OBJECT_DIRECTORY/" ]
diff --git a/prune-packed.c b/prune-packed.c
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -46,7 +48,7 @@ static void prune_packed_objects(void)
sprintf(pathname + len, "%02x/", i);
d = opendir(pathname);
if (!d)
- die("unable to open %s", pathname);
+ continue;
prune_dir(i, d, pathname, len + 3);
closedir(d);
}
---- stage (b) ----
Phase 2: create object subdirectories on demand
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1248,6 +1248,73 @@ char *write_sha1_file_prepare(void *buf,
return sha1_file_name(sha1);
}
+/*
+ * Link the tempfile to the final place, possibly creating the
+ * last directory level as you do so.
+ *
+ * Returns the errno on failure, 0 on success.
+ */
+static int link_temp_to_file(const char *tmpfile, char *filename)
+{
+ int ret;
+
+ if (!link(tmpfile, filename))
+ return 0;
+
+ /*
+ * Try to mkdir the last path component if that failed
+ * with an ENOENT.
+ *
+ * Re-try the "link()" regardless of whether the mkdir
+ * succeeds, since a race might mean that somebody
+ * else succeeded.
+ */
+ ret = errno;
+ if (ret == ENOENT) {
+ char *dir = strrchr(filename, '/');
+ if (dir) {
+ *dir = 0;
+ mkdir(filename, 0777);
+ *dir = '/';
+ if (!link(tmpfile, filename))
+ return 0;
+ ret = errno;
+ }
+ }
+ return ret;
+}
+
+/*
+ * Move the just written object into its final resting place
+ */
+static int move_temp_to_file(const char *tmpfile, char *filename)
+{
+ int ret = link_temp_to_file(tmpfile, filename);
+ if (ret) {
+ /*
+ * Coda hack - coda doesn't like cross-directory links,
+ * so we fall back to a rename, which will mean that it
+ * won't be able to check collisions, but that's not a
+ * big deal.
+ *
+ * When this succeeds, we just return 0. We have nothing
+ * left to unlink.
+ */
+ if (ret == EXDEV && !rename(tmpfile, filename))
+ return 0;
+ }
+ unlink(tmpfile);
+ if (ret) {
+ if (ret != EEXIST) {
+ fprintf(stderr, "unable to write sha1 filename %s: %s", filename, strerror(ret));
+ return -1;
+ }
+ /* FIXME!!! Collision check here ? */
+ }
+
+ return 0;
+}
+
int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
{
int size;
@@ -1257,7 +1324,7 @@ int write_sha1_file(void *buf, unsigned
char *filename;
static char tmpfile[PATH_MAX];
unsigned char hdr[50];
- int fd, hdrlen, ret;
+ int fd, hdrlen;
/* Normally if we have it in the pack then we do not bother writing
* it out into .git/objects/??/?{38} file.
@@ -1320,32 +1387,7 @@ int write_sha1_file(void *buf, unsigned
close(fd);
free(compressed);
- ret = link(tmpfile, filename);
- if (ret < 0) {
- ret = errno;
-
- /*
- * Coda hack - coda doesn't like cross-directory links,
- * so we fall back to a rename, which will mean that it
- * won't be able to check collisions, but that's not a
- * big deal.
- *
- * When this succeeds, we just return 0. We have nothing
- * left to unlink.
- */
- if (ret == EXDEV && !rename(tmpfile, filename))
- return 0;
- }
- unlink(tmpfile);
- if (ret) {
- if (ret != EEXIST) {
- fprintf(stderr, "unable to write sha1 filename %s: %s", filename, strerror(ret));
- return -1;
- }
- /* FIXME!!! Collision check here ? */
- }
-
- return 0;
+ return move_temp_to_file(tmpfile, filename);
}
int write_sha1_to_fd(int fd, const unsigned char *sha1)
@@ -1420,8 +1462,7 @@ int write_sha1_to_fd(int fd, const unsig
int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
size_t bufsize, size_t *bufposn)
{
- char *filename = sha1_file_name(sha1);
-
+ char tmpfile[PATH_MAX];
int local;
z_stream stream;
unsigned char real_sha1[20];
@@ -1429,10 +1470,11 @@ int write_sha1_from_fd(const unsigned ch
int ret;
SHA_CTX c;
- local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX", get_object_directory());
+ local = mkstemp(tmpfile);
if (local < 0)
- return error("Couldn't open %s\n", filename);
+ return error("Couldn't open %s for %s\n", tmpfile, sha1_to_hex(sha1));
memset(&stream, 0, sizeof(stream));
@@ -1462,7 +1504,7 @@ int write_sha1_from_fd(const unsigned ch
size = read(fd, buffer + *bufposn, bufsize - *bufposn);
if (size <= 0) {
close(local);
- unlink(filename);
+ unlink(tmpfile);
if (!size)
return error("Connection closed?");
perror("Reading from connection");
@@ -1475,15 +1517,15 @@ int write_sha1_from_fd(const unsigned ch
close(local);
SHA1_Final(real_sha1, &c);
if (ret != Z_STREAM_END) {
- unlink(filename);
+ unlink(tmpfile);
return error("File %s corrupted", sha1_to_hex(sha1));
}
if (memcmp(sha1, real_sha1, 20)) {
- unlink(filename);
+ unlink(tmpfile);
return error("File %s has bad hash\n", sha1_to_hex(sha1));
}
-
- return 0;
+
+ return move_temp_to_file(tmpfile, sha1_file_name(sha1));
}
int has_pack_index(const unsigned char *sha1)
---- stage (c) ----
Phase 3: actually remove object subdirectories
diff --git a/init-db.c b/init-db.c
--- a/init-db.c
+++ b/init-db.c
@@ -244,10 +244,6 @@ int main(int argc, char **argv)
memcpy(path, sha1_dir, len);
safe_create_dir(sha1_dir);
- for (i = 0; i < 256; i++) {
- sprintf(path+len, "/%02x", i);
- safe_create_dir(path);
- }
strcpy(path+len, "/pack");
safe_create_dir(path);
strcpy(path+len, "/info");
diff --git a/prune-packed.c b/prune-packed.c
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -26,6 +26,8 @@ static void prune_dir(int i, DIR *dir, c
else if (unlink(pathname) < 0)
error("unable to unlink %s", pathname);
}
+ pathname[len] = 0;
+ rmdir(pathname);
}
static void prune_packed_objects(void)
^ permalink raw reply
* cg-mv
From: Zack Brown @ 2005-10-07 14:33 UTC (permalink / raw)
To: Git Mailing List
Hi,
IIRC, file renaming is something we only care about at read time, we don't
actually need to track it while making the change, because git allows us to
track data from file to file without having to tell it that the data is moving.
So, just to keep certain people happy, why not have the cg-mv command defined to
something like this:
#!/bin/bash
cp $1 $2
cg-rm $1
cg-add $2
Be well,
Zack
--
Zack Brown
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Alex Riesen @ 2005-10-07 12:44 UTC (permalink / raw)
To: Git Mailing List; +Cc: Christopher Faylor, Junio C Hamano, H. Peter Anvin
In-Reply-To: <81b0412b0510060307q431b64edt4196553bce28346c@mail.gmail.com>
On 10/6/05, Alex Riesen <raa.lkml@gmail.com> wrote:
> > (a bit too intrusive). The patch fixes only update-index.c (the one I had
> > problems with), there probably are other places were the situation is alike.
>
> of course there are "other places". Please, try the attached patch instead.
>
> For the record: the patch is supposed to help people with
> "Unable to write new cachefile" kind of errors.
Just as I thought the situation improved (by closing index.lock and
unmapping index),
it suddenly get worse: now I'm stuck on git-pull.
git-merge-index (called at some point by git-pull) maps the index in, and starts
git-merge-one-file for each (or the given) entry in the index.
git-merge-one-file
calls git-update-index, which wants to update the index. Which doesn't work,
because it's locked by that piece of s$%^.
The only working walkaround for me atm is unlinking indexfile before rename in
commit_index_file :(
^ permalink raw reply
* Re: Create object subdirectories on demand
From: Junio C Hamano @ 2005-10-07 9:38 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0510061612080.31407@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> This has _not_ gotten a lot of testing, but I verified that basic things
> seem to work, and that packing an archive properly removes the unnecessary
> subdirectories.
>
> I'd suggest it sit in "pu" for a while.
I typically use the tip of "pu" myself, which resulted in an
interesting case (nothing grave). After running 'git prune', I
switched to another topic branch that did not include this
patch, built it, and tried it out -- and got complaint because
the earlier 'git prune' happened to remove ".git/objects/00".
Now I was not in a valid git repository anymore ;-).
This needs to wait until everybody's git get this update,
especially, I cannot use this version in my $HOME/bin/ on
kernel.org right now.
But then once everybody else updates, the repository their git
creates cannot be read by my git -- an interesting chicken and
egg problem.
Maybe successful rmdir() immediately followed by mkdir(), if we
are willing to waste 4KB or so per empty directory, trading
space for safety and ease of transition? That is, phase I tools
do not complain if objects/00 is missing, lazily creates
object/??/ is missing, and makes sure empty directories are
pruned but still recreates them for safety. Then phase II tools
then stops the recreating part.
> However, somebody should really check my code carefully before merging
> this. In particular, I didn't test "git-ssh-pull" at all, so I'm not sure
> I actually fixed the "write temp-file" thing properly.
Well, the thing is, I do not use commit walkers over ssh myself
and honestly consider them having outlived their usefulness.
But you are right -- I should look at this one again before
placing in the master.
^ permalink raw reply
* Re: [PATCH] Show original and resulting blob object info in diff output.
From: Junio C Hamano @ 2005-10-07 5:16 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0510062139560.31407@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> IOW, why not make it shorter ans prettier and just make it be
>
> index 7be50413538868412a87..83660822fcbb9edac523
>
> which is basically the first 20 hex digits of each SHA1.
Makes sense.
> If you want the "applies-to" etc,...
applies-to: is for the whole tree, and I think it can go if we
do this per-blob signature thing.
The first SHA1 after applies-to: is coming from diff-tree,
noting the commit object _after_ the change. I could filter it
while running format-patch, because it is useless from patch
application point of view.
> .... In fact, I bet 20 bits would be plenty).
So the updated proposal would be:
diff --git a/apply.c b/apply.c
index 7be5041..8366082 100644
--- a/apply.c
+++ b/apply.c
@@ -14,6 +14,7 @@
...
diff --git a/foo.sh b/bar.sh
old mode 100644
new mode 100755
index 7be5041..8366082
similarity index 86%
rename from foo.sh
rename to bar.sh
--- a/foo.sh
+++ b/bar.sh
@@ -14,6 +14,7 @@
...
where the "index" line shows abbreviated SHA1 for pre- and post-
image blob, with an optional mode bit string only if there is no
mode change; otherwise we would have old/new mode line anyway.
^ permalink raw reply
* Re: [PATCH] Add support for parallel HTTP transfers
From: Junio C Hamano @ 2005-10-07 5:15 UTC (permalink / raw)
To: Nick Hengeveld; +Cc: git
In-Reply-To: <20051007045639.GA18998@reactrix.com>
Nick Hengeveld <nickh@reactrix.com> writes:
> Not that I'm a huge fan of using environment variables, but it might make
> sense to use one here. That would allow the setting to work whether
> git-http-fetch is run directly or via git-fetch. GIT_HTTP_MAX_REQUESTS?
Good point.
^ permalink raw reply
* Re: [PATCH] Add support for parallel HTTP transfers
From: Nick Hengeveld @ 2005-10-07 4:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7virwa5ety.fsf@assigned-by-dhcp.cox.net>
On Thu, Oct 06, 2005 at 05:51:53PM -0700, Junio C Hamano wrote:
> Well, I'd suggest just to hardcode a reasonable value to be a
> good net citizen, and not make it configurable. Four, perhaps?
>
> OTOH, we may want to have an option to disable parallel from the
> command line (I think -r 1 would mean that with yours).
I'd prefer to keep it configurable - for our purposes we'll be hitting
a single server from several clients and will probably want to limit
concurrent connections to something like two per client, but when doing
a fetch from a big server farm more connections would make sense.
> If we really want to have the number of parallel configurable,
> and -r implies recursive as you say, maybe '-j' to mimic
> parallel make?
Not that I'm a huge fan of using environment variables, but it might make
sense to use one here. That would allow the setting to work whether
git-http-fetch is run directly or via git-fetch. GIT_HTTP_MAX_REQUESTS?
--
For a successful technology, reality must take precedence over public
relations, for nature cannot be fooled.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox