#!/bin/sh -e init () { [ -n "$1" ] || printArgs mkdir -p "$(dirname $1)" [ -f "$1" ] || cat >"$1" "$tbl".ver cut -f1,3- "$tbl" \ | "$@" \ | join -t$'\t' "$tbl".ver - \ > "$tbl"~ mv "$tbl"~ "$tbl" rm "$tbl".ver } update () { [ -n "$2" -a -n "$3" ] || printArgs oldversion=$(grep "^$2"$'\t' "$1" | cut -f2) tmpfile="$1.update" echo -e "$2\t$(($oldversion + 1 + $RANDOM))\t$3" > "$tmpfile" merge "$1" "$tmpfile" if [ -n "$4" ]; then # broadcast update gzip <"$tmpfile" >"$tmpfile.gz" hbbpc $4 p2ptbl/$(basename "$1") - <"$tmpfile.gz" rm "$tmpfile.gz" fi rm "$tmpfile" } merge () { # we use sort instead of merge here to be robust in case the rows # are not sorted sort "$1" "$2" \ | { oldkey="" oldversion=0 oldval="" while read key version val; do if [ "$key" == "$oldkey" ]; then if [ "$version" -gt "$oldversion" ]; then oldversion="$version" oldval="$val" fi else [ -n "$oldkey" ] && echo -e "$oldkey\t$oldversion\t$oldval" oldkey="$key" oldversion="$version" oldval="$val" fi done [ -n "$oldkey" ] && echo -e "$oldkey\t$oldversion\t$oldval" } > "$1~" mv "$1~" "$1" } gossip() { tgts="$2" if="$3" [ "$tgts" -gt 0 -a -n "$if" ] 2>/dev/null || printArgs # binary search over number of sent lines until size is maximized # and below target size lc=$(wc -l <"$1") [ $lc == 0 ] && return shuf -v seed=$RANDOM <"$1" >"$1.gossip" while [ $lc -ge 1 ]; do head -n$lc "$1.gossip" | gzip >"$1.gossip.gz" if [ $tgts -ge $(wc -c <"$1.gossip.gz") ]; then hbbpc $if p2ptbl/$(basename "$1") - <"$1.gossip.gz" rm "$1.gossip" "$1.gossip.gz" return; fi lc=$(($lc / 2)) done rm "$1.gossip" "$1.gossip.gz" echo "$1 has rows bigger then requested packet size" exit 1 } printArgs () { echo -e >&2 "Usage: $0 init table $0 get table key $0 show table $0 update table key value [interface] $0 filter table program [args] $0 merge table foreign-table $0 gossip table target-size interface" exit 1 } checkTable () { [ -n "$1" ] || printArgs; [ -f "$1" ] || { echo >&2 "$1 is no P2P table"; printArgs; } } lockTable () { checkTable "$2" exec 666<"$2" flock "$1" 666 } case "$1" in init) init "$2" ;; get) lockTable -s "$2" get "$2" "$3" ;; show) lockTable -s "$2" show "$2" ;; filter) tbl="$2" shift 2 lockTable -x "$tbl" filter "$tbl" "$@" ;; update) lockTable -s "$2" update "$2" "$3" "$4" "$5" ;; merge) lockTable -x "$2" checkTable "$3" merge "$2" "$3" ;; gossip) lockTable -s "$2" gossip "$2" "$3" "$4" ;; *) printArgs ;; esac