Monday, December 14, 2015

Are Files Appends Really Atomic?

Nice post and thanks to the original author !

Ref: http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/
#!/bin/bash

#############################################################################
#
# This script aims to test/prove that you can append to a single file from
# multiple processes with buffers up to a certain size, without causing one
# process' output to corrupt the other's.
#
# The script takes one parameter, the length of the buffer. It then creates
# 20 worker processes which each write 50 lines of the specified buffer
# size to the same file. When all processes are done outputting, it tests
# the output file to ensure it is in the correct format.
#
#############################################################################

NUM_WORKERS=20
LINES_PER_WORKER=50
OUTPUT_FILE=/tmp/out.tmp

# each worker will output $LINES_PER_WORKER lines to the output file
run_worker() {
    worker_num=$1
    buf_len=$2

    # Each line will be a specific character, multiplied by the line length.
    # The character changes based on the worker number.
    filler_len=$((${buf_len}-1)) # -1 -> leave room for \n
    filler_char=$(printf \\$(printf '%03o' $(($worker_num+64))))
    line=`for i in $(seq 1 $filler_len);do echo -n $filler_char;done`
    for i in $(seq 1 $LINES_PER_WORKER)
    do
        echo $line >> $OUTPUT_FILE
    done
}

if [ "$1" = "worker" ]; then
    run_worker $2 $3
    exit
fi

buf_len=$1
if [ "$buf_len" = "" ]; then
    echo "Buffer length not specified, defaulting to 4096"
    buf_len=4096
fi

rm -f $OUTPUT_FILE

echo Launching $NUM_WORKERS worker processes
for i in $(seq 1 $NUM_WORKERS)
do
    $0 worker $i $buf_len &
    pids[$i]=${!}
done

echo Each line will be $buf_len characters long
echo Waiting for processes to exit
for i in $(seq 1 $NUM_WORKERS)
do
    wait ${pids[$i]}
done

# Now we want to test the output file. Each line should be the same letter
# repeated buf_len-1 times (remember the \n takes up one byte). If we had
# workers writing over eachother's lines, then there will be mixed characters
# and/or longer/shorter lines.

echo Testing output file

# Make sure the file is the right size (ensures processes didn't write over
# eachother's lines)
expected_file_size=$(($NUM_WORKERS * $LINES_PER_WORKER * $buf_len))
actual_file_size=`cat $OUTPUT_FILE | wc -c`
if [ "$expected_file_size" -ne "$actual_file_size" ]; then
    echo Expected file size of $expected_file_size, but got $actual_file_size
else
 
    # File size is OK, test the actual content

    # Only use newer versions of grep because older ones are way too slow with
    # backreferences
    [[ $(grep --version) =~ [^[:digit:]]*([[:digit:]]+)\.([[:digit:]]+) ]]
    grep_ver="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
    if [ "$grep_ver" -ge "216" ]; then
        num_lines=$(grep -v "^\(.\)\1\{$((${buf_len}-2))\}$" $OUTPUT_FILE | wc -l)
    else
        # Scan line by line in bash, which isn't that speedy, but is good enough
        # Note: Doesn't work on cygwin for lines < 255
        line_length=$((${buf_len}-1))
        num_lines=0
        for line in `cat $OUTPUT_FILE`
        do
            if ! [[ $line =~ ^${line:0:1}{$line_length}$ ]]; then
                num_lines=$(($num_lines+1))
            fi;
            echo -n .
        done
        echo
    fi

    if [ "$num_lines" -gt "0" ]; then
        echo "Found $num_lines instances of corrupted lines"
        else
        echo "All's good! The output file had no corrupted lines. $size"
    fi
fi

rm -f $OUTPUT_FILE

Friday, November 20, 2015

Linux Kernel Map


Saturday, December 21, 2013

How Browsers Work - I

Nice explanation on basics of browser internals.



Ref: Akamai Blog

Monday, October 28, 2013

Saturday, February 2, 2013

Hardware Ports !!!


Thursday, February 16, 2012

How SCP works !

Interesting article ....

Examples

Now it's time to have some fun. The protocol description might not be that describing like a few simple examples.

single file copy to the remote side

let's have a file test, containing string "hello" and we want to copy it over SCP protocol to /tmp directory.

$ rm -f /tmp/test
$ { echo C0644 6 test; printf "hello\\n"; } | scp -t /tmp
test 100% |\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*| 6 00:00
$ cat /tmp/test
hello

Nice, isn't it? I used printf so that it's clear why we used 6 for the file length. Now something with a directory copy.
recursive directory copy to the remote side

let's have the file test in a directory testdir. Now we want to recursively copy the whole directory to /tmp on the "other side".

$ rm -rf /tmp/testdir
$ { echo D0755 0 testdir; echo C0644 6 test;
printf "hello\\n"; echo E; } | scp -rt /tmp
test 100% |\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*| 6 00:00
$ cat /tmp/testdir/test
hello

Note that we had to use -r option because the directory copy was involved.
copy the directory from the remote side

now the scp program in the pipe will represent the remote side, the producer of the data. As said in the protocol section, the consumer (we) must reply to every protocol message and also to the finished data transfer. Note that this will not create any directory or file since generated protocol messages and data sent are just printed to your terminal - no one reads or interprets them, we just want to see scp's output in the source mode:

$ cd /tmp
$ rm -rf testdir
$ mkdir testdir
$ echo hello > testdir/test
$ printf '\\000\\000\\000\\000\\000\\000' | scp -qprf testdir
T1183832947 0 1183833773 0
D0700 0 testdir
T1183833773 0 1183833762 0
C0600 6 test
hello
E

A little explanation - you don't see data progress bar because of -q option. You see time protocol messages because we asked for them via -p option. And -f means that scp was the producer of the data. Also note that we had to use six '\\0' characters - the first for initializing the transfer, 4 to confirm the messages and 1 for the data transfer. Is that correct? Not exactly because we didn't acknowledged the final E message:

$ echo $?
1

and that's why scp returned failure. If we use 7 binary zeroes everything is fine then:

$ printf '\\000\\000\\000\\000\\000\\000\\000' | scp -qprf testdir
T1183832947 0 1183833956 0
D0700 0 testdir
T1183833773 0 1183833956 0
C0600 6 test
hello
E
$ echo $?
0

sending an error message

The example shows that scp will exit when we reply with binary 2. You can see that even when we send a couple of zeroes after that the scp command doesn't accept them anymore.

$ printf '\\000\\000\\002\\n\\000\\000' | scp -qprf testdir
T1183895689 0 1183899084 0
D0700 0 testdir

Wednesday, February 15, 2012

Host and Subnet Quantities

Class A Host/Subnet Table

Class A
Number of
Bits Borrowed Subnet Effective Number of Number of Subnet
from Host Portion Mask Subnets Hosts/Subnet Mask Bits
------- --------------- --------- ------------- -------------
1 255.128.0.0 2 8388606 /9
2 255.192.0.0 4 4194302 /10
3 255.224.0.0 8 2097150 /11
4 255.240.0.0 16 1048574 /12
5 255.248.0.0 32 524286 /13
6 255.252.0.0 64 262142 /14
7 255.254.0.0 128 131070 /15
8 255.255.0.0 256 65534 /16
9 255.255.128.0 512 32766 /17
10 255.255.192.0 1024 16382 /18
11 255.255.224.0 2048 8190 /19
12 255.255.240.0 4096 4094 /20
13 255.255.248.0 8192 2046 /21
14 255.255.252.0 16384 1022 /22
15 255.255.254.0 32768 510 /23
16 255.255.255.0 65536 254 /24
17 255.255.255.128 131072 126 /25
18 255.255.255.192 262144 62 /26
19 255.255.255.224 524288 30 /27
20 255.255.255.240 1048576 14 /28
21 255.255.255.248 2097152 6 /29
22 255.255.255.252 4194304 2 /30
23 255.255.255.254 8388608 2* /31

Class B Host/Subnet Table

Class B Subnet Effective Effective Number of Subnet
Bits Mask Subnets Hosts Mask Bits
------- --------------- --------- --------- -------------
1 255.255.128.0 2 32766 /17
2 255.255.192.0 4 16382 /18
3 255.255.224.0 8 8190 /19
4 255.255.240.0 16 4094 /20
5 255.255.248.0 32 2046 /21
6 255.255.252.0 64 1022 /22
7 255.255.254.0 128 510 /23
8 255.255.255.0 256 254 /24
9 255.255.255.128 512 126 /25
10 255.255.255.192 1024 62 /26
11 255.255.255.224 2048 30 /27
12 255.255.255.240 4096 14 /28
13 255.255.255.248 8192 6 /29
14 255.255.255.252 16384 2 /30
15 255.255.255.254 32768 2* /31

Class C Host/Subnet Table

Class C Subnet Effective Effective Number of Subnet
Bits Mask Subnets Hosts Mask Bits
------- --------------- --------- --------- --------------
1 255.255.255.128 2 126 /25
2 255.255.255.192 4 62 /26
3 255.255.255.224 8 30 /27
4 255.255.255.240 16 14 /28
5 255.255.255.248 32 6 /29
6 255.255.255.252 64 2 /30
7 255.255.255.254 128 2* /31