aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@localhost>2013-02-14 00:00:00 +0000
committerroot <root@localhost>2013-02-14 00:00:00 +0000
commit96b7608966b0e06f757b2a5fc464d53b610ca432 (patch)
tree810aad5dd2d5fbb9ee55b90d62b494815558857e
parent6f0af6d0fff47d2cb1325191d24f8fc1ed56d464 (diff)
downloadgit-remote-gcrypt-96b7608966b0e06f757b2a5fc464d53b610ca432.zip
git-remote-gcrypt-96b7608966b0e06f757b2a5fc464d53b610ca432.tar.gz
git-remote-gcrypt-96b7608966b0e06f757b2a5fc464d53b610ca432.tar.bz2
Repack the encrypted remote regularly
Use a simple but slow method of repacking the remote repository. Download (and verify) all packs not marked 'keep', and repack those into a new packfile. The new packfile is marked 'keep' with generation 1. After PUT is called on the manifest, we remove the redundant old packfiles. The generation number will allow further iterations of repacking to be implemented later.
-rwxr-xr-xgit-remote-gcrypt135
1 files changed, 133 insertions, 2 deletions
diff --git a/git-remote-gcrypt b/git-remote-gcrypt
index 61f8921..c912f99 100755
--- a/git-remote-gcrypt
+++ b/git-remote-gcrypt
@@ -18,10 +18,14 @@ Repoid=
Packkey_bytes=33 # 33 random bytes for passphrase, still compatible if changed
Hashtype=SHA224 # incompatible if changed
Packpfx="pack :${Hashtype}:"
+Keeppfx="keep :${Hashtype}:"
Branchlist=
Packlist=
+Keeplist=
Extension_list=
+Repack_limit=25
+Packlist_delete=
Recipients=
Signers=
@@ -112,6 +116,17 @@ gitception_put()
git update-ref "$Gref" "$commit_id"
}
+# Remove giturl $1, file $2
+# depends on previous GET like put
+gitception_remove()
+{
+ local tree_id= commit_id= tab_=" "
+ # $2 is a filename from the repo format
+ tree_id=$(git ls-tree "$Gref" | xgrep -v -E '\b'"$2"'$' | git mktree) &&
+ commit_id=$(anon_commit "$tree_id") &&
+ git update-ref "$Gref" "$commit_id"
+}
+
gitception_new_repo()
{
local empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
@@ -198,6 +213,32 @@ PUTREPO()
fi
}
+# For repo $1, delete all newline-separated files in $2
+REMOVE()
+{
+ local fn_=
+ if isurl ssh "$1"
+ then
+ splitcolon "${1#ssh://}"
+ (exec 0>&- ; ssh "$prefix_" "cd $suffix_; rm $2")
+ elif isurl sftp "$1"
+ then
+ # FIXME
+ echo_info "sftp: Ignore remove request $1/$2"
+ elif isurl rsync "$1"
+ then
+ xecho "$2" | rsync -I -W -v -r --delete --include-from=- \
+ --exclude='*' "$Localdir"/ "${1#rsync://}/" >&2
+ elif islocalrepo "$1"
+ then
+ (cd "$1"; rm $2)
+ else
+ for fn_ in $2; do
+ gitception_remove "${1#gitception://}" "$fn_"
+ done
+ fi
+}
+
CLEAN_FINAL()
{
if isurl ssh "$1" || isurl sftp "$1" || islocalrepo "$1" || isurl rsync "$1"
@@ -372,11 +413,83 @@ ensure_connected()
Branchlist=$(xecho "$manifest_" | xgrep -E '^[0-9a-f]{40} ')
Packlist=$(xecho "$manifest_" | xgrep "^$Packpfx")
+ Keeplist=$(xecho "$manifest_" | xgrep "^keep")
Extension_list=$(xecho "$manifest_" | xgrep "^extn ")
rcv_repoid=$(xecho "$manifest_" | xgrep "^repo ")
iseq "$(repoidstr)" "$rcv_repoid" || echo_die "Repository id mismatch!"
}
+# $1 is new pack id $2 key
+# set did_repack=yes if repacked
+repack_if_needed()
+{
+ local pack_= rcv_id= packline_= premote_= key_= pkeep_= n_=
+
+ # $TmpPack_Encrypted set in caller
+
+ did_repack=no
+ isnonnull "$Packlist" || return 0
+
+ premote_=$(xecho "$Packlist" | cut -f 1-2 -d ' ')
+ pkeep_=$(xecho "$Keeplist" | cut -f 2 -d ' ')
+
+ if isnull "$pkeep_"; then
+ n_=$(xecho "$Packlist" | wc -l)
+ else
+ n_=$(xecho "$Packlist" | grep -v -F -e "$pkeep_" | wc -l)
+ fi
+ if [ $Repack_limit -gt "$n_" ]; then
+ return
+ fi
+ echo_info "Repacking remote $NAME, ..."
+
+ rm -r -f "$Localdir/pack"
+ mkdir -p "$Localdir/pack"
+ DECRYPT "$2" < "$TmpPack_Encrypted" |
+ git index-pack -v --stdin "$Localdir/pack/${1}.pack" >/dev/null
+
+ xecho "$premote_" | while read packline_
+ do
+ isnonnull "$packline_" || continue
+ if isnonnull "$pkeep_" &&
+ xecho "$packline_" | grep -q -F -e "$pkeep_"
+ then
+ continue
+ fi
+ pack_=${packline_#"$Packpfx"}
+ GET "$URL" "$pack_" "$TmpPack_Encrypted"
+ rcv_id=$(pack_hash < "$TmpPack_Encrypted")
+ if isnoteq "$rcv_id" "$pack_"
+ then
+ echo_die "Packfile $pack_ does not match digest!"
+ fi
+ key_=$(xecho "$Packlist" | grep "$pack_" | cut -f 3 -d ' ')
+ DECRYPT "$key_" < "$TmpPack_Encrypted" |
+ git index-pack -v --stdin "$Localdir/pack/${pack_}.pack" >/dev/null
+ done
+ key_=$(genkey "$Packkey_bytes")
+
+ git verify-pack -v "$Localdir"/pack/*.idx | grep -E '^[0-9a-f]{40}' |
+ cut -f 1 -d ' ' |
+ GIT_ALTERNATE_OBJECT_DIRECTORIES=$Localdir \
+ git pack-objects --stdout | ENCRYPT "$key_" > "$TmpPack_Encrypted"
+
+ # Truncate packlist to only the kept packs
+ if isnull "$pkeep_"; then
+ Packlist_delete=$premote_
+ Packlist=
+ else
+ Packlist_delete=$(xecho "$premote_" | xgrep -v -F -e "$pkeep_")
+ Packlist=$(xecho "$Packlist" | xgrep -F -e "$pkeep_")
+ fi
+
+ pack_id=$(pack_hash < "$TmpPack_Encrypted")
+ Packlist=$(append "$Packlist" "$Packpfx$pack_id $key_")
+ Keeplist=$(append "$Keeplist" "$Keeppfx$pack_id 1")
+ rm -r -f "$Localdir/pack"
+ did_repack=yes
+}
+
do_capabilities()
{
echo_git fetch
@@ -510,7 +623,15 @@ EOF
if [ -s "$TmpObjlist" ]
then
pack_id=$(pack_hash < "$TmpPack_Encrypted")
- Packlist=$(append "$Packlist" "$Packpfx$pack_id $key_")
+ did_repack=
+ repack_if_needed "$pack_id" "$key_"
+
+ if isnoteq "$did_repack" yes
+ then
+ Packlist=$(append "$Packlist" "$Packpfx$pack_id $key_")
+ fi
+ # else, repack rewrote Packlist
+
fi
# Generate manifest
@@ -519,7 +640,7 @@ EOF
TmpManifest_Enc="$Localdir/manifest.$$"
- (xecho "$Branchlist"; xecho "$Packlist";
+ (xecho "$Branchlist"; xecho "$Packlist"; xecho "$Keeplist";
repoidstr; xecho "$Extension_list") |
PRIVENCRYPT "$Recipients" > "$TmpManifest_Enc"
@@ -534,6 +655,16 @@ EOF
# Upload manifest
PUT "$URL" "$Repoid" "$TmpManifest_Enc"
+ # Delete packs
+ if isnonnull "$Packlist_delete"; then
+ REMOVE "$URL" "$(xecho "$Packlist_delete" | while read packline_
+ do
+ isnonnull "$packline_" || continue
+ pack_=${packline_#"$Packpfx"}
+ xecho "$pack_"
+ done)"
+ fi
+
PUT_FINAL "$URL"
rm -f "$TmpManifest_Enc"