queue_;
};
VisitorImpl visitor(nquery, max);
if (!db.scan_parallel(&visitor, THREADNUM)) {
dberrprint(&db, "DB::scan_parallel faileda");
err = true;
}
}
if (!db.close()) {
dberrprint(&db, "DB::close failed");
err = true;
}
return err ? 1 : 0;
}
// END OF FILE
kyotocabinet-1.2.76/lab/kcdict/sample.tsv 0000644 0001750 0001750 00000007261 11606027256 017335 0 ustar mikio mikio one 0 one test the first number
two 0 two test the second number
three 0 three test the third number
four 0 four test the fourth number
five 0 five test the fifth number
six 0 fix test the sixth number
seven 0 seven test the seventh number
eight 0 eight test the eighth number
nine 0 nine test the ninth number
ten 0 ten test the tenth number
eleven 0 eleven test the eleventh number
twelve 0 twelve test the twelfth number
thirteen 0 thirteen test the thirteenth number
fourteen 0 fourteen test the fourteenth number
fifteen 0 fifteen test the fifteenth number
sixteen 0 sixteen test the sixteenth number
seventeen 0 seventeen test the seventeenth number
eighteen 0 eighteen test the eighteenth number
nineteen 0 nineteen test the nineteenth number
twenty 0 twelve test the twentieth number
tokyo 1 Tokyo test the capital city of Japan
japan 1 Japan test a country in the east of Asia
japan 2 japan test lacquer with a durable glossy black finish
japan 3 Japan test a british rock'n roll band
!"#$%&'()*+,-./ 0 ASCII TEST 1 test normalize test
0123456789:;<=>? 0 ASCII TEST 2 test normalize test
@ABCDEFGHIJKLMNO 0 ASCII TEST 3 test normalize test
PQRSTUVWXYZ[\]^_ 0 ASCII TEST 4 test normalize test
`abcdefghijklmno 0 ASCII TEST 5 test normalize test
pqrstuvwxyz{|}~ 0 ASCII TEST 6 test normalize test
ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃ 0 LATIN TEST 1 test normalize test
ÃÑÒÓÔÕÖרÙÚÛÜÃÞß 0 LATIN TEST 2 test normalize test
à áâãäåæçèéêëìÃîï 0 LATIN TEST 3 test normalize test
ðñòóôõö÷øùúûüýþÿ 0 LATIN TEST 4 test normalize test
Ä€ÄĂ㥹ĆćĈĉĊċČÄÄŽÄ 0 LATIN TEST 5 test normalize test
ÄđĒēĔĕĖėĘęĚěĜÄĞğ 0 LATIN TEST 6 test normalize test
Ä Ä¡Ä¢Ä£Ä¤Ä¥Ä¦Ä§Ä¨Ä©ÄªÄ«Ä¬ÄĮį 0 LATIN TEST 7 test normalize test
İıIJijĴĵĶķĸĹĺĻļĽľĿ 0 LATIN TEST 8 test normalize test
Å€ÅłŃńŅņŇňʼnŊŋŌÅÅŽÅ 0 LATIN TEST 9 test normalize test
ÅőŒœŔŕŖŗŘřŚśŜÅŞş 0 LATIN TEST 10 test normalize test
ŠšŢţŤťŦŧŨũŪūŬÅŮů 0 LATIN TEST 11 test normalize test
ŰűŲųŴŵŶŷŸŹźŻżŽžſ 0 LATIN TEST 12 test normalize test
ΑΒΓΔΕΖΗΘΙΚΛΜÎÎžÎŸÎ Î¢Î¡Î£Î¤Î¥Î¦Î§Î¨Î©Ï˜ÏšÏœÏžÏ Ï¢Ï¤Ï¦Ï¨ÏªÏ¬Ï® 0 GREEK TEST 1 test normalize test
αβγδεζηθικλμνξοπÏςστυφχψωϙϛÏϟϡϣϥϧϩϫÏϯ 0 test GREEK TEST 2 normalize test
ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬÐЮЯЀÐЂЃЄЅІЇЈЉЊЋЌÐÐŽÐ 0 CYRILLIC TEST 1 test normalize test
абвгдежзийклмнопрÑтуфхцчшщъыьÑÑŽÑÑёђѓєѕіїјљњћќÑўџ test 0 CYRILLIC TEST 2 normalize test
アイウエオカキクケコサシスセソタï¾ï¾‚テト 0 test HALFWIDTH KANA TEST 1 normalize test
ナニヌネノハヒフï¾ï¾Žï¾ï¾ï¾‘メノヤユヨ 0 HALFWIDTH KANA TEST 2 test normalize test
ラリルレロワヲï¾ï½³ï¾ž 0 HALFWIDTH KANA TEST 3 test normalize test
ガギグゲゴダï¾ï¾žï¾‚゙デド 0 HALFWIDTH KANA TEST 4 test normalize test
バビブï¾ï¾žï¾Žï¾žï¾Šï¾Ÿï¾‹ï¾Ÿï¾Œï¾Ÿï¾ï¾Ÿï¾Žï¾Ÿ 0 HALFWIDTH KANA TEST 5 test normalize test
。「」、・ 0 HALFWIDTH KANA TEST 6 test normalize test
ï¼‘ï¼’ï¼“ï¼”ï¼•ï¼–ï¼—ï¼˜ï¼™ï¼ 0 FULLWIDTH KANA TEST 1 test normalize test
ABCDEFGHIJKLï¼ï¼®ï¼¯ï¼°ï¼±ï¼²ï¼³ï¼´ï¼µï¼¶ï¼·ï¼¸ï¼¹ï¼º 0 FULLWIDTH KANA TEST 2 test normalize test
ï½ï½‚cdefghijklï½ï½Žï½ï½ï½‘rstuvwxyz 0 FULLWIDTH KANA TEST 3 test normalize test
,.:;?ï¼Â´ï½€Â¨ï¼¾ï¿£ï¼¿â€”â€ï¼ï¼¼ã€œï½œ 0 FULLWIDTH MARK TEST 1 test normalize test
‘’“â€ï¼ˆï¼‰ã€”〕[]{ï½ã€ˆã€‰ï¼‹âˆ’ï¼ï¼œï¼žâ€²â€³ 0 FULLWIDTH KANA MARK TEST 2 test normalize test
ï¿¥ï¼„ï¼ƒï¼†ï¼Šï¼ â™¯ 0 FULLWIDTH MARK TEST 3 test normalize test
kyotocabinet-1.2.76/lab/segvtest 0000755 0001750 0001750 00000005330 11560340044 015632 0 ustar mikio mikio #! /bin/sh
#================================================================
# segvtest
# Simulate process crash by Segmentatin Fault
#================================================================
# set variables
testcmd="kchashtest"
testsubcmd="order"
testopts="-th 4"
mgrcmd="kchashmgr"
PATH="$PATH:."
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib:."
DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:/usr/local/lib:."
export PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH
# parse arguments
case "$1" in
kch|hash)
testcmd="kchashtest"
mgrcmd="kchashmgr"
testopts="$testopts -dfunit 8"
;;
kct|tree)
testcmd="kctreetest"
testopts="$testopts -dfunit 8 -pccap 10k"
mgrcmd="kctreemgr"
;;
kcd|dir)
testcmd="kcdirtest"
mgrcmd="kcdirmgr"
;;
kcf|forest)
testcmd="kcforesttest"
testopts="$testopts -pccap 10k"
mgrcmd="kcforestmgr"
;;
esac
if [ "$2" = "-wicked" ]
then
testsubcmd="wicked"
testopts="-th 4 -it 10"
shift
else
testopts="$testopts -rnd"
fi
if [ "$2" = "-oat" ]
then
testopts="$testopts -oat"
shift
fi
if [ "$2" = "-tran" ]
then
testopts="$testopts -tran"
shift
fi
argsleepsec="$2"
loopnum="$3"
# enable libSegFault
unset LD_PRELOAD
if [ -f "/lib/libSegFault.so" ]
then
LD_PRELOAD="/lib/libSegFault.so"
elif [ -f "/lib/x86_64-linux-gnu/libSegFault.so" ]
then
LD_PRELOAD="/lib/x86_64-linux-gnu/libSegFault.so"
fi
if [ -n "$LD_PRELOAD" ]
then
SEGFAULT_SIGNALS="all"
SEGFAULT_OUTPUT_NAME="$testcmd.log"
export LD_PRELOAD SEGFAULT_SIGNALS SEGFAULT_OUTPUT_NAME
fi
# set the cleanup handler
rm -f stop.log
trap "touch stop.log" TERM INT
trap "killall $testcmd >/dev/null 2>&1; rm -f stop.log" EXIT
# infinite loop
cnt=0
while [ ! -f stop.log ]
do
cnt=`expr $cnt + 1`
if [ -n "$argsleepsec" ]
then
sleepsec="$argsleepsec"
else
sleepsec=`date +%S`
sleepinteg=`expr $sleepsec % 6 + 1`
sleepfract=`expr $sleepsec / 6 % 10`
sleepsec="$sleepinteg.$sleepfract"
fi
printf '\n==== iteration: %d (%.1f sec.)\n\n' "$cnt" "$sleepsec"
rm -rf casket* "$testcmd.log"
echo "$testcmd" "$testsubcmd" $testopts casket 10000000
"$testcmd" "$testsubcmd" $testopts casket 10000000 & \
( sleep "$sleepsec" ; killall -SEGV "$testcmd" )
cp -rf casket casket-back 2>/dev/null
cp -rf casket.wal casket-back.wal 2>/dev/null
printf '\n'
ls -ld casket
[ -e casket.wal ] && ls -ld casket.wal
echo "$mgrcmd" check casket
if "$mgrcmd" check casket
then
true
if [ -n "$loopnum" ] && [ "$cnt" -ge "$loopnum" ]
then
break
fi
else
printf '\n==== ERROR\n\n'
printf "cp -rf casket-back casket ; cp -f casket-back.wal casket.wal ; ./$mgrcmd check casket\n"
exit 1
fi
done
printf '\n==== %d tests finished successfully\n\n' "$cnt"
# exit normally
exit 0
# END OF FILE
kyotocabinet-1.2.76/lab/stopwatch 0000755 0001750 0001750 00000005153 11564330513 016011 0 ustar mikio mikio #! /usr/bin/perl
#================================================================
# stopwatch
# Measure elapsed time of some test commands.
#================================================================
use strict;
use warnings;
use Time::HiRes qw(gettimeofday);
use constant {
RECORDNUM => 1000000,
THREADNUM => 4,
TESTCOUNT => 20,
REMOVETOP => 2,
REMOVEBOTTOM => 8,
};
my $file = "casket";
my $rnum = RECORDNUM;
my $bnum = $rnum * 2;
my $tbnum = $rnum / 8;
my $msiz = $rnum * 50;
my $tnum = THREADNUM;
my $rtnum = $rnum / $tnum;
my @commands = (
"./kcstashtest order -bnum $bnum $rnum",
"./kcstashtest order -th $tnum -bnum $tbnum $rtnum",
"./kccachetest order -bnum $bnum $rnum",
"./kccachetest order -th $tnum -bnum $tbnum $rtnum",
"./kchashtest order -set -bnum $bnum -msiz $msiz $file $rnum",
# "./kchashtest order -set -oat -bnum $bnum -msiz $msiz $file $rnum",
"./kchashtest order -get -msiz $msiz $file $rnum",
"./kchashtest order -th $tnum -set -bnum $bnum -msiz $msiz $file $rtnum",
# "./kchashtest order -th $tnum -set -oat -bnum $bnum -msiz $msiz $file $rtnum",
"./kchashtest order -th $tnum -get -msiz $msiz $file $rtnum",
"./kctreetest order -set -bnum $tbnum -msiz $msiz $file $rnum",
# "./kctreetest order -set -oat -bnum $tbnum -msiz $msiz $file $rnum",
"./kctreetest order -get -msiz $msiz $file $rnum",
"./kctreetest order -th $tnum -set -bnum $tbnum -msiz $msiz $file $rtnum",
# "./kctreetest order -th $tnum -set -oat -bnum $tbnum -msiz $msiz $file $rtnum",
"./kctreetest order -th $tnum -get -msiz $msiz $file $rtnum",
);
my @table;
foreach my $command (@commands){
system("sync ; sync");
my @result;
for(my $i = 0; $i < TESTCOUNT; $i++){
my $stime = gettimeofday();
system("$command >/dev/null 2>&1");
$stime = gettimeofday() - $stime;
printf("%s\t%d\t%0.5f\n", $command, $i + 1, $stime);
push(@result, $stime);
}
@result = sort { $a <=> $b } @result;
for(my $i = 0; $i < REMOVETOP; $i++){
shift(@result);
}
for(my $i = 0; $i < REMOVEBOTTOM; $i++){
pop(@result);
}
my $sum = 0;
foreach my $result (@result){
$sum += $result;
}
my $avg = $sum / scalar(@result);
push(@table, [$command, $avg]);
}
printf("\n\nRESULT\n");
foreach my $row (@table){
printf("%s\t%0.5f\n", $$row[0], $$row[1]);
}
printf("\n");
# END OF FILE
kyotocabinet-1.2.76/lab/diffcheck 0000755 0001750 0001750 00000001500 11523256007 015673 0 ustar mikio mikio #! /bin/sh
#================================================================
# diffcheck
# List files different from ones of another version
#================================================================
# set variables
LANG=C
LC_ALL=C
export LANG LC_ALL
regex='\.(h|c|cc|cpp|cxx|java|pl|pm|pod|rb|rd|lua|[1-9]|html|txt)$'
vregex='/api/'
# check arguments
if [ $# != 1 ]
then
printf 'diffcheck: usage: diffcheck directory_of_oldversion\n' 1>&2
exit 1
fi
# diff files
find . -type f | egrep $regex | egrep -v $vregex |
while read file
do
old=`printf '%s\n' "$file" | sed 's/^\.\///'`
printf 'Checking %s and %s ... ' "$file" "$1/$old"
res=`diff -q "$file" "$1/$old"`
if [ -z "$res" ]
then
printf 'same\n'
else
printf '### !!! DIFFERENT !!! ###\n'
fi
done
# exit normally
exit 0
# END OF FILE
kyotocabinet-1.2.76/lab/vcmakecheck.bat 0000644 0001750 0001750 00000000546 11523256007 017004 0 ustar mikio mikio @echo off
rem ================================================================
rem vcmakecheck.bat
rem Perform self-diagnostic test forever
rem ================================================================
:LOOP
nmake -f VCmakefile check
if errorlevel 1 goto :ERROR
echo OK
goto :LOOP
:ERROR
echo Error
exit /b 1
rem END OF FILE
kyotocabinet-1.2.76/lab/stepcount 0000755 0001750 0001750 00000000662 11523256007 016021 0 ustar mikio mikio #! /bin/sh
#================================================================
# stepcount
# Find files including dispensable tab characters
#================================================================
# set variables
LANG=C
LC_ALL=C
export LANG LC_ALL
regex='(\.h|\.c|\.cc|\.java|\.pl|\.pm|\.xs|\.rb|\.js)$'
# count steps
files=`find . -type f | egrep $regex`
wc -l $files | sort -n
# exit normally
exit 0
# END OF FILE
kyotocabinet-1.2.76/lab/primelist 0000755 0001750 0001750 00000001310 11523256007 015774 0 ustar mikio mikio #! /usr/bin/ruby
#================================================================
# primelist
# Print a sparse list of prime numbers
#================================================================
MINNUM = 1
MAXNUM = 2 ** 52
MULNUM = Math.sqrt(Math.sqrt(2))
uniq = {}
base = MINNUM
while base <= MAXNUM
num = base
while num < base * 1.99 - 1
cand = num
while true
cmd = sprintf('factor %d', cand)
res = `#{cmd}`
res = res.gsub(/ *\n/, '')
res = res.gsub(/.*: */, '')
if res !~ / / && !uniq[res]
printf("%s\n", res);
uniq[res] = true
break
end
cand += 1
end
num *= MULNUM
end
base *= 2
end
exit(0)
# END OF FILE
kyotocabinet-1.2.76/lab/numbers.tsv 0000644 0001750 0001750 00000000420 11523256007 016250 0 ustar mikio mikio zero zeroth
one first
two second
- fizz one
three third
four fourth
- buzz one
five fifth
- fizz two
six sixth
seven seventh
eight eighth
- fizz three
nine ninth
- buzz two
ten tenth
eleven eleventh
- fizz four
twelve twelfth
zero
-
kyotocabinet-1.2.76/lab/datechange 0000755 0001750 0001750 00000002407 11523256007 016057 0 ustar mikio mikio #! /bin/sh
#================================================================
# datechange
# Replace date expressions
#================================================================
# set variables
LANG=C
LC_ALL=C
export LANG LC_ALL
year=`date '+%Y'`
date=`date '+%Y-%m-%d'`
fulldate=`date -R`
regexsrc='\.(h|c|cc|cpp|cxx|java|pl|pm|pod|xs|rb|rd|py|lua|idl)$'
regexman='\.[0-9]$'
regexhtml='\.html$'
# edit source files
find . -type f | egrep "$regexsrc" |
while read file
do
echo "$file"
sed "/opyright/ s/\\(20[0-9][0-9]\\)-\\(20[0-9][0-9]\\)/\\1-$year/" "$file" > "$file.tmp"
mv -f "$file.tmp" "$file"
done
# edit manual files
find . -type f | egrep "$regexman" |
while read file
do
echo "$file"
sed "/\\.TH/ s/\\(20[0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)/$date/" "$file" > "$file.tmp"
mv -f "$file.tmp" "$file"
done
# edit HTML files
find . -type f | egrep "$regexhtml" |
while read file
do
echo "$file"
sed -e "/opyright/ s/\\(20[0-9][0-9]\\)-\\(20[0-9][0-9]\\)/\\1-$year/" -e "// s/Last Update: *\\([A-Z][a-z][a-z], [0-9][0-9] [A-Z][a-z][a-z] 20[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] +[0-9][0-9]*\\)/Last Update: $fulldate/" "$file" > "$file.tmp"
mv -f "$file.tmp" "$file"
done
# exit normally
exit 0
# END OF FILE
kyotocabinet-1.2.76/lab/makevcdef 0000755 0001750 0001750 00000001506 11523256007 015720 0 ustar mikio mikio #! /bin/sh
#================================================================
# makevcdef
# Generator of module definition file for Visual C++
#================================================================
# check arguments
file="$1"
if [ -f "$file" ]
then
true
else
printf 'usage: makevcdef library\n' 1>&2
exit 1
fi
# show headers
name=`echo $file | sed -e 's/^lib//' -e 's/\..*//'`
printf 'EXPORTS\r\n'
# show variables
nm -g "$file" | grep ' [BDR] ' | sed 's/.* [BDR] //' | grep -v '^_' | sort | uniq |
while read name
do
num=$((num + 1))
printf ' %s = %s CONSTANT\r\n' "$name" "$name"
done
# show functions
nm -g "$file" | grep ' T ' | sed 's/.* T //' | grep -v '^_' | sort | uniq |
while read name
do
num=$((num + 1))
printf ' %s = %s\r\n' "$name" "$name"
done
# exit normally
exit 0
# END OF FILE
kyotocabinet-1.2.76/lab/codecheck 0000755 0001750 0001750 00000004542 11523256007 015706 0 ustar mikio mikio #! /usr/bin/ruby -w
#================================================================
# codecheck
# Check files about compliance of the coding policy
#================================================================
SUFFIXES = /\.(h|cc)$/
IGNORES = /(kccommon\.h)/
BADOPEN = /[^\w](if|while|for|switch|catch)\(/
BADCLOSE = /\)\{/
BADTYPE = /[^\w](u)*(void|char|int|double|size_t|std::string)[0-9]*(_t)* +\*/
BADFUNCS = [
/[^:.>\w](malloc|calloc|realloc|free|rand|srand|abort|qsort|strtoll|llabs|div|lldiv) *\(/,
/[^:.>\w](memset|memcpy|memmove|memcmp|memchr) *\(/,
/[^:.>\w](strcpy|strncpy|strcat|strncat|strcmp|strchr|strrchr|strstr|strlen) *\(/,
/[^:.>\w](printf|fprintf|sprintf|snprintf|vprintf|vfprintf|vsprintf|vsnprintf) *\(/,
/[^:.>\w](isnan|isinf|pow|fabs|sqrt|floor|ceil|modf|modfl) *\(/,
]
LIMITWIDTH = 97
def checkfile(path)
printf("Checking: %s\n", path)
ok = true
open(path, "r") do |file|
num = 0
file.each do |line|
num += 1
line.chomp!
if line =~ /\s$/
printf("TRAINING SPACE: %s: %d: %s\n", path, num, line)
ok = false
end
if line =~ /\t/
printf("TAB CODE: %s: %d: %s\n", path, num, line)
ok = false
end
if line =~ BADOPEN
printf("BAD OPEN: %s: %d: %s\n", path, num, line)
ok = false
end
if line =~ BADCLOSE
printf("BAD CLOSE: %s: %d: %s\n", path, num, line)
ok = false
end
if line =~ BADTYPE
printf("BAD TYPE: %s: %d: %s\n", path, num, line)
ok = false
end
BADFUNCS.each do |badfunc|
if line =~ badfunc
printf("BAD FUNC: %s: %d: %s\n", path, num, line)
ok = false
end
end
if line.length > LIMITWIDTH && !line.index("/*") && !line.index("*/")
printf("BAD WIDTH: %s: %d: %s\n", path, num, line)
ok = false
end
end
end
return ok
end
ok = true
list = Array::new(ARGV)
list.push(".") if list.empty?
while !list.empty?
path = list.shift
begin
if File::ftype(path) == "directory"
Dir.entries(path).each do |cpath|
if cpath =~ SUFFIXES && cpath !~ /[#~]/ && cpath !~ IGNORES
list.push(path + "/" + cpath)
end
end
else
ok = false if !checkfile(path)
end
rescue
end
end
if ok
printf("ALL OK\n")
exit(0)
else
printf("ERROR\n")
exit(1)
end
# END OF FILE
kyotocabinet-1.2.76/kcprotodb.cc 0000644 0001750 0001750 00000002254 11757460617 015623 0 ustar mikio mikio /*************************************************************************************************
* Prototype database
* Copyright (C) 2009-2012 FAL Labs
* This file is part of Kyoto Cabinet.
* This program is free software: you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation, either version
* 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program.
* If not, see .
*************************************************************************************************/
#include "kcprotodb.h"
#include "myconf.h"
namespace kyotocabinet { // common namespace
// There is no implementation now.
} // common namespace
// END OF FILE
kyotocabinet-1.2.76/kcthread.h 0000644 0001750 0001750 00000070170 11757460617 015265 0 ustar mikio mikio /*************************************************************************************************
* Threading devices
* Copyright (C) 2009-2012 FAL Labs
* This file is part of Kyoto Cabinet.
* This program is free software: you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation, either version
* 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program.
* If not, see .
*************************************************************************************************/
#ifndef _KCTHREAD_H // duplication check
#define _KCTHREAD_H
#include
#include
namespace kyotocabinet { // common namespace
/**
* Threading device.
*/
class Thread {
public:
/**
* Default constructor.
*/
explicit Thread();
/**
* Destructor.
*/
virtual ~Thread();
/**
* Perform the concrete process.
*/
virtual void run() = 0;
/**
* Start the thread.
*/
void start();
/**
* Wait for the thread to finish.
*/
void join();
/**
* Put the thread in the detached state.
*/
void detach();
/**
* Terminate the running thread.
*/
static void exit();
/**
* Yield the processor from the current thread.
*/
static void yield();
/**
* Chill the processor by suspending execution for a quick moment.
*/
static void chill();
/**
* Suspend execution of the current thread.
* @param sec the interval of the suspension in seconds.
* @return true on success, or false on failure.
*/
static bool sleep(double sec);
/**
* Get the hash value of the current thread.
* @return the hash value of the current thread.
*/
static int64_t hash();
private:
/** Dummy constructor to forbid the use. */
Thread(const Thread&);
/** Dummy Operator to forbid the use. */
Thread& operator =(const Thread&);
/** Opaque pointer. */
void* opq_;
};
/**
* Basic mutual exclusion device.
*/
class Mutex {
friend class CondVar;
public:
/**
* Type of the behavior for double locking.
*/
enum Type {
FAST, ///< no operation
ERRORCHECK, ///< check error
RECURSIVE ///< allow recursive locking
};
/**
* Default constructor.
*/
explicit Mutex();
/**
* Constructor.
* @param type the behavior for double locking.
*/
explicit Mutex(Type type);
/**
* Destructor.
*/
~Mutex();
/**
* Get the lock.
*/
void lock();
/**
* Try to get the lock.
* @return true on success, or false on failure.
*/
bool lock_try();
/**
* Try to get the lock.
* @param sec the interval of the suspension in seconds.
* @return true on success, or false on failure.
*/
bool lock_try(double sec);
/**
* Release the lock.
*/
void unlock();
private:
/** Dummy constructor to forbid the use. */
Mutex(const Mutex&);
/** Dummy Operator to forbid the use. */
Mutex& operator =(const Mutex&);
/** Opaque pointer. */
void* opq_;
};
/**
* Scoped mutex device.
*/
class ScopedMutex {
public:
/**
* Constructor.
* @param mutex a mutex to lock the block.
*/
explicit ScopedMutex(Mutex* mutex) : mutex_(mutex) {
_assert_(mutex);
mutex_->lock();
}
/**
* Destructor.
*/
~ScopedMutex() {
_assert_(true);
mutex_->unlock();
}
private:
/** Dummy constructor to forbid the use. */
ScopedMutex(const ScopedMutex&);
/** Dummy Operator to forbid the use. */
ScopedMutex& operator =(const ScopedMutex&);
/** The inner device. */
Mutex* mutex_;
};
/**
* Slotted mutex device.
*/
class SlottedMutex {
public:
/**
* Constructor.
* @param slotnum the number of slots.
*/
explicit SlottedMutex(size_t slotnum);
/**
* Destructor.
*/
~SlottedMutex();
/**
* Get the lock of a slot.
* @param idx the index of a slot.
*/
void lock(size_t idx);
/**
* Release the lock of a slot.
* @param idx the index of a slot.
*/
void unlock(size_t idx);
/**
* Get the locks of all slots.
*/
void lock_all();
/**
* Release the locks of all slots.
*/
void unlock_all();
private:
/** Opaque pointer. */
void* opq_;
};
/**
* Lightweight mutual exclusion device.
*/
class SpinLock {
public:
/**
* Default constructor.
*/
explicit SpinLock();
/**
* Destructor.
*/
~SpinLock();
/**
* Get the lock.
*/
void lock();
/**
* Try to get the lock.
* @return true on success, or false on failure.
*/
bool lock_try();
/**
* Release the lock.
*/
void unlock();
private:
/** Dummy constructor to forbid the use. */
SpinLock(const SpinLock&);
/** Dummy Operator to forbid the use. */
SpinLock& operator =(const SpinLock&);
/** Opaque pointer. */
void* opq_;
};
/**
* Scoped spin lock device.
*/
class ScopedSpinLock {
public:
/**
* Constructor.
* @param spinlock a spin lock to lock the block.
*/
explicit ScopedSpinLock(SpinLock* spinlock) : spinlock_(spinlock) {
_assert_(spinlock);
spinlock_->lock();
}
/**
* Destructor.
*/
~ScopedSpinLock() {
_assert_(true);
spinlock_->unlock();
}
private:
/** Dummy constructor to forbid the use. */
ScopedSpinLock(const ScopedSpinLock&);
/** Dummy Operator to forbid the use. */
ScopedSpinLock& operator =(const ScopedSpinLock&);
/** The inner device. */
SpinLock* spinlock_;
};
/**
* Slotted spin lock devices.
*/
class SlottedSpinLock {
public:
/**
* Constructor.
* @param slotnum the number of slots.
*/
explicit SlottedSpinLock(size_t slotnum);
/**
* Destructor.
*/
~SlottedSpinLock();
/**
* Get the lock of a slot.
* @param idx the index of a slot.
*/
void lock(size_t idx);
/**
* Release the lock of a slot.
* @param idx the index of a slot.
*/
void unlock(size_t idx);
/**
* Get the locks of all slots.
*/
void lock_all();
/**
* Release the locks of all slots.
*/
void unlock_all();
private:
/** Opaque pointer. */
void* opq_;
};
/**
* Reader-writer locking device.
*/
class RWLock {
public:
/**
* Default constructor.
*/
explicit RWLock();
/**
* Destructor.
*/
~RWLock();
/**
* Get the writer lock.
*/
void lock_writer();
/**
* Try to get the writer lock.
* @return true on success, or false on failure.
*/
bool lock_writer_try();
/**
* Get a reader lock.
*/
void lock_reader();
/**
* Try to get a reader lock.
* @return true on success, or false on failure.
*/
bool lock_reader_try();
/**
* Release the lock.
*/
void unlock();
private:
/** Dummy constructor to forbid the use. */
RWLock(const RWLock&);
/** Dummy Operator to forbid the use. */
RWLock& operator =(const RWLock&);
/** Opaque pointer. */
void* opq_;
};
/**
* Scoped reader-writer locking device.
*/
class ScopedRWLock {
public:
/**
* Constructor.
* @param rwlock a rwlock to lock the block.
* @param writer true for writer lock, or false for reader lock.
*/
explicit ScopedRWLock(RWLock* rwlock, bool writer) : rwlock_(rwlock) {
_assert_(rwlock);
if (writer) {
rwlock_->lock_writer();
} else {
rwlock_->lock_reader();
}
}
/**
* Destructor.
*/
~ScopedRWLock() {
_assert_(true);
rwlock_->unlock();
}
private:
/** Dummy constructor to forbid the use. */
ScopedRWLock(const ScopedRWLock&);
/** Dummy Operator to forbid the use. */
ScopedRWLock& operator =(const ScopedRWLock&);
/** The inner device. */
RWLock* rwlock_;
};
/**
* Slotted reader-writer lock devices.
*/
class SlottedRWLock {
public:
/**
* Constructor.
* @param slotnum the number of slots.
*/
explicit SlottedRWLock(size_t slotnum);
/**
* Destructor.
*/
~SlottedRWLock();
/**
* Get the writer lock of a slot.
* @param idx the index of a slot.
*/
void lock_writer(size_t idx);
/**
* Get the reader lock of a slot.
* @param idx the index of a slot.
*/
void lock_reader(size_t idx);
/**
* Release the lock of a slot.
* @param idx the index of a slot.
*/
void unlock(size_t idx);
/**
* Get the writer locks of all slots.
*/
void lock_writer_all();
/**
* Get the reader locks of all slots.
*/
void lock_reader_all();
/**
* Release the locks of all slots.
*/
void unlock_all();
private:
/** Opaque pointer. */
void* opq_;
};
/**
* Lightweight reader-writer locking device.
*/
class SpinRWLock {
public:
/**
* Default constructor.
*/
explicit SpinRWLock();
/**
* Destructor.
*/
~SpinRWLock();
/**
* Get the writer lock.
*/
void lock_writer();
/**
* Try to get the writer lock.
* @return true on success, or false on failure.
*/
bool lock_writer_try();
/**
* Get a reader lock.
*/
void lock_reader();
/**
* Try to get a reader lock.
* @return true on success, or false on failure.
*/
bool lock_reader_try();
/**
* Release the lock.
*/
void unlock();
/**
* Promote a reader lock to the writer lock.
* @return true on success, or false on failure.
*/
bool promote();
/**
* Demote the writer lock to a reader lock.
*/
void demote();
private:
/** Dummy constructor to forbid the use. */
SpinRWLock(const SpinRWLock&);
/** Dummy Operator to forbid the use. */
SpinRWLock& operator =(const SpinRWLock&);
/** Opaque pointer. */
void* opq_;
};
/**
* Scoped reader-writer locking device.
*/
class ScopedSpinRWLock {
public:
/**
* Constructor.
* @param srwlock a spin rwlock to lock the block.
* @param writer true for writer lock, or false for reader lock.
*/
explicit ScopedSpinRWLock(SpinRWLock* srwlock, bool writer) : srwlock_(srwlock) {
_assert_(srwlock);
if (writer) {
srwlock_->lock_writer();
} else {
srwlock_->lock_reader();
}
}
/**
* Destructor.
*/
~ScopedSpinRWLock() {
_assert_(true);
srwlock_->unlock();
}
private:
/** Dummy constructor to forbid the use. */
ScopedSpinRWLock(const ScopedSpinRWLock&);
/** Dummy Operator to forbid the use. */
ScopedSpinRWLock& operator =(const ScopedSpinRWLock&);
/** The inner device. */
SpinRWLock* srwlock_;
};
/**
* Slotted lightweight reader-writer lock devices.
*/
class SlottedSpinRWLock {
public:
/**
* Constructor.
* @param slotnum the number of slots.
*/
explicit SlottedSpinRWLock(size_t slotnum);
/**
* Destructor.
*/
~SlottedSpinRWLock();
/**
* Get the writer lock of a slot.
* @param idx the index of a slot.
*/
void lock_writer(size_t idx);
/**
* Get the reader lock of a slot.
* @param idx the index of a slot.
*/
void lock_reader(size_t idx);
/**
* Release the lock of a slot.
* @param idx the index of a slot.
*/
void unlock(size_t idx);
/**
* Get the writer locks of all slots.
*/
void lock_writer_all();
/**
* Get the reader locks of all slots.
*/
void lock_reader_all();
/**
* Release the locks of all slots.
*/
void unlock_all();
private:
/** Opaque pointer. */
void* opq_;
};
/**
* Condition variable.
*/
class CondVar {
public:
/**
* Default constructor.
*/
explicit CondVar();
/**
* Destructor.
*/
~CondVar();
/**
* Wait for the signal.
* @param mutex a locked mutex.
*/
void wait(Mutex* mutex);
/**
* Wait for the signal.
* @param mutex a locked mutex.
* @param sec the interval of the suspension in seconds.
* @return true on catched signal, or false on timeout.
*/
bool wait(Mutex* mutex, double sec);
/**
* Send the wake-up signal to another waiting thread.
* @note The mutex used for the wait method should be locked by the caller.
*/
void signal();
/**
* Send the wake-up signals to all waiting threads.
* @note The mutex used for the wait method should be locked by the caller.
*/
void broadcast();
private:
/** Dummy constructor to forbid the use. */
CondVar(const CondVar&);
/** Dummy Operator to forbid the use. */
CondVar& operator =(const CondVar&);
/** Opaque pointer. */
void* opq_;
};
/**
* Assosiative condition variable.
*/
class CondMap {
private:
struct Count;
struct Slot;
/** An alias of set of counters. */
typedef std::map CountMap;
/** The number of slots. */
static const size_t SLOTNUM = 64;
public:
/**
* Default constructor.
*/
explicit CondMap() : slots_() {
_assert_(true);
}
/**
* Destructor.
*/
~CondMap() {
_assert_(true);
}
/**
* Wait for a signal.
* @param kbuf the pointer to the key region.
* @param ksiz the size of the key region.
* @param sec the interval of the suspension in seconds. If it is negative, no timeout is
* specified.
* @return true on catched signal, or false on timeout.
*/
bool wait(const char* kbuf, size_t ksiz, double sec = -1) {
_assert_(kbuf && ksiz <= MEMMAXSIZ);
std::string key(kbuf, ksiz);
return wait(key, sec);
}
/**
* Wait for a signal by a key.
* @param key the key.
* @param sec the interval of the suspension in seconds. If it is negative, no timeout is
* specified.
* @return true on catched signal, or false on timeout.
*/
bool wait(const std::string& key, double sec = -1) {
_assert_(true);
double invtime = sec < 0 ? 1.0 : sec;
double curtime = time();
double endtime = curtime + (sec < 0 ? UINT32MAX : sec);
Slot* slot = get_slot(key);
while (curtime < endtime) {
ScopedMutex lock(&slot->mutex);
CountMap::iterator cit = slot->counter.find(key);
if (cit == slot->counter.end()) {
Count cnt = { 1, false };
slot->counter[key] = cnt;
} else {
cit->second.num++;
}
slot->cond.wait(&slot->mutex, invtime);
cit = slot->counter.find(key);
cit->second.num--;
if (cit->second.wake > 0) {
cit->second.wake--;
if (cit->second.num < 1) slot->counter.erase(cit);
return true;
}
if (cit->second.num < 1) slot->counter.erase(cit);
curtime = time();
}
return false;
}
/**
* Send a wake-up signal to another thread waiting by a key.
* @param kbuf the pointer to the key region.
* @param ksiz the size of the key region.
* @return the number of threads waiting for the signal.
*/
size_t signal(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ);
std::string key(kbuf, ksiz);
return signal(key);
}
/**
* Send a wake-up signal to another thread waiting by a key.
* @param key the key.
* @return the number of threads waiting for the signal.
*/
size_t signal(const std::string& key) {
_assert_(true);
Slot* slot = get_slot(key);
ScopedMutex lock(&slot->mutex);
CountMap::iterator cit = slot->counter.find(key);
if (cit == slot->counter.end() || cit->second.num < 1) return 0;
if (cit->second.wake < cit->second.num) cit->second.wake++;
slot->cond.broadcast();
return cit->second.num;
}
/**
* Send wake-up signals to all threads waiting by a key.
* @param kbuf the pointer to the key region.
* @param ksiz the size of the key region.
* @return the number of threads waiting for the signal.
*/
size_t broadcast(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ);
std::string key(kbuf, ksiz);
return broadcast(key);
}
/**
* Send wake-up signals to all threads waiting by a key.
* @param key the key.
* @return the number of threads waiting for the signal.
*/
size_t broadcast(const std::string& key) {
_assert_(true);
Slot* slot = get_slot(key);
ScopedMutex lock(&slot->mutex);
CountMap::iterator cit = slot->counter.find(key);
if (cit == slot->counter.end() || cit->second.num < 1) return 0;
cit->second.wake = cit->second.num;
slot->cond.broadcast();
return cit->second.num;
}
/**
* Send wake-up signals to all threads waiting by each key.
* @return the number of threads waiting for the signal.
*/
size_t broadcast_all() {
_assert_(true);
size_t sum = 0;
for (size_t i = 0; i < SLOTNUM; i++) {
Slot* slot = slots_ + i;
ScopedMutex lock(&slot->mutex);
CountMap::iterator cit = slot->counter.begin();
CountMap::iterator citend = slot->counter.end();
while (cit != citend) {
if (cit->second.num > 0) {
cit->second.wake = cit->second.num;
sum += cit->second.num;
}
slot->cond.broadcast();
++cit;
}
}
return sum;
}
/**
* Get the total number of threads waiting for signals.
* @return the total number of threads waiting for signals.
*/
size_t count() {
_assert_(true);
size_t sum = 0;
for (size_t i = 0; i < SLOTNUM; i++) {
Slot* slot = slots_ + i;
ScopedMutex lock(&slot->mutex);
CountMap::iterator cit = slot->counter.begin();
CountMap::iterator citend = slot->counter.end();
while (cit != citend) {
sum += cit->second.num;
++cit;
}
}
return sum;
}
private:
/**
* Counter for waiting threads.
*/
struct Count {
size_t num; ///< waiting threads
size_t wake; ///< waking threads
};
/**
* Slot of a key space.
*/
struct Slot {
CondVar cond; ///< condition variable
Mutex mutex; ///< mutex
CountMap counter; ///< counter
};
/**
* Get the slot corresponding a key.
* @param key the key.
* @return the slot corresponding the key.
*/
Slot* get_slot(const std::string& key) {
return slots_ + hashmurmur(key.data(), key.size()) % SLOTNUM;
}
/** The slot array. */
Slot slots_[SLOTNUM];
};
/**
* Key of thread specific data.
*/
class TSDKey {
public:
/**
* Default constructor.
*/
explicit TSDKey();
/**
* Constructor.
* @param dstr the destructor for the value.
*/
explicit TSDKey(void (*dstr)(void*));
/**
* Destructor.
*/
~TSDKey();
/**
* Set the value.
* @param ptr an arbitrary pointer.
*/
void set(void* ptr);
/**
* Get the value.
* @return the value.
*/
void* get() const ;
private:
/** Opaque pointer. */
void* opq_;
};
/**
* Smart pointer to thread specific data.
*/
template
class TSD {
public:
/**
* Default constructor.
*/
explicit TSD() : key_(delete_value) {
_assert_(true);
}
/**
* Destructor.
*/
~TSD() {
_assert_(true);
TYPE* obj = (TYPE*)key_.get();
if (obj) {
delete obj;
key_.set(NULL);
}
}
/**
* Dereference operator.
* @return the reference to the inner object.
*/
TYPE& operator *() {
_assert_(true);
TYPE* obj = (TYPE*)key_.get();
if (!obj) {
obj = new TYPE;
key_.set(obj);
}
return *obj;
}
/**
* Member reference operator.
* @return the pointer to the inner object.
*/
TYPE* operator ->() {
_assert_(true);
TYPE* obj = (TYPE*)key_.get();
if (!obj) {
obj = new TYPE;
key_.set(obj);
}
return obj;
}
/**
* Cast operator to the original type.
* @return the copy of the inner object.
*/
operator TYPE() const {
_assert_(true);
TYPE* obj = (TYPE*)key_.get();
if (!obj) return TYPE();
return *obj;
}
private:
/**
* Delete the inner object.
* @param obj the inner object.
*/
static void delete_value(void* obj) {
_assert_(true);
delete (TYPE*)obj;
}
/** Dummy constructor to forbid the use. */
TSD(const TSD&);
/** Dummy Operator to forbid the use. */
TSD& operator =(const TSD&);
/** Key of thread specific data. */
TSDKey key_;
};
/**
* Integer with atomic operations.
*/
class AtomicInt64 {
public:
/**
* Default constructor.
*/
explicit AtomicInt64() : value_(0), lock_() {
_assert_(true);
}
/**
* Copy constructor.
* @param src the source object.
*/
AtomicInt64(const AtomicInt64& src) : value_(src.get()), lock_() {
_assert_(true);
};
/**
* Constructor.
* @param num the initial value.
*/
AtomicInt64(int64_t num) : value_(num), lock_() {
_assert_(true);
}
/**
* Destructor.
*/
~AtomicInt64() {
_assert_(true);
}
/**
* Set the new value.
* @param val the new value.
* @return the old value.
*/
int64_t set(int64_t val);
/**
* Add a value.
* @param val the additional value.
* @return the old value.
*/
int64_t add(int64_t val);
/**
* Perform compare-and-swap.
* @param oval the old value.
* @param nval the new value.
* @return true on success, or false on failure.
*/
bool cas(int64_t oval, int64_t nval);
/**
* Get the current value.
* @return the current value.
*/
int64_t get() const;
/**
* Assignment operator from the self type.
* @param right the right operand.
* @return the reference to itself.
*/
AtomicInt64& operator =(const AtomicInt64& right) {
_assert_(true);
if (&right == this) return *this;
set(right.get());
return *this;
}
/**
* Assignment operator from integer.
* @param right the right operand.
* @return the reference to itself.
*/
AtomicInt64& operator =(const int64_t& right) {
_assert_(true);
set(right);
return *this;
}
/**
* Cast operator to integer.
* @return the current value.
*/
operator int64_t() const {
_assert_(true);
return get();
}
/**
* Summation assignment operator by integer.
* @param right the right operand.
* @return the reference to itself.
*/
AtomicInt64& operator +=(int64_t right) {
_assert_(true);
add(right);
return *this;
}
/**
* Subtraction assignment operator by integer.
* @param right the right operand.
* @return the reference to itself.
*/
AtomicInt64& operator -=(int64_t right) {
_assert_(true);
add(-right);
return *this;
}
/**
* Secure the least value
* @param val the least value
* @return the current value.
*/
int64_t secure_least(int64_t val) {
_assert_(true);
while (true) {
int64_t cur = get();
if (cur >= val) return cur;
if (cas(cur, val)) break;
}
return val;
}
private:
/** The value. */
volatile int64_t value_;
/** The alternative lock. */
mutable SpinLock lock_;
};
/**
* Task queue device.
*/
class TaskQueue {
public:
class Task;
private:
class WorkerThread;
/** An alias of list of tasks. */
typedef std::list TaskList;
public:
/**
* Interface of a task.
*/
class Task {
friend class TaskQueue;
public:
/**
* Default constructor.
*/
explicit Task() : id_(0), thid_(0), aborted_(false) {
_assert_(true);
}
/**
* Destructor.
*/
virtual ~Task() {
_assert_(true);
}
/**
* Get the ID number of the task.
* @return the ID number of the task, which is incremented from 1.
*/
uint64_t id() const {
_assert_(true);
return id_;
}
/**
* Get the ID number of the worker thread.
* @return the ID number of the worker thread. It is from 0 to less than the number of
* worker threads.
*/
uint32_t thread_id() const {
_assert_(true);
return thid_;
}
/**
* Check whether the thread is to be aborted.
* @return true if the thread is to be aborted, or false if not.
*/
bool aborted() const {
_assert_(true);
return aborted_;
}
private:
/** The task ID number. */
uint64_t id_;
/** The thread ID number. */
uint64_t thid_;
/** The flag to be aborted. */
bool aborted_;
};
/**
* Default Constructor.
*/
TaskQueue() : thary_(NULL), thnum_(0), tasks_(), count_(0), mutex_(), cond_(), seed_(0) {
_assert_(true);
}
/**
* Destructor.
*/
virtual ~TaskQueue() {
_assert_(true);
}
/**
* Process a task.
* @param task a task object.
*/
virtual void do_task(Task* task) = 0;
/**
* Process the starting event.
* @param task a task object.
* @note This is called for each thread on starting.
*/
virtual void do_start(const Task* task) {
_assert_(true);
}
/**
* Process the finishing event.
* @param task a task object.
* @note This is called for each thread on finishing.
*/
virtual void do_finish(const Task* task) {
_assert_(true);
}
/**
* Start the task queue.
* @param thnum the number of worker threads.
*/
void start(size_t thnum) {
_assert_(thnum > 0 && thnum <= MEMMAXSIZ);
thary_ = new WorkerThread[thnum];
for (size_t i = 0; i < thnum; i++) {
thary_[i].id_ = i;
thary_[i].queue_ = this;
thary_[i].start();
}
thnum_ = thnum;
}
/**
* Finish the task queue.
* @note This function blocks until all tasks in the queue are popped.
*/
void finish() {
_assert_(true);
mutex_.lock();
TaskList::iterator it = tasks_.begin();
TaskList::iterator itend = tasks_.end();
while (it != itend) {
Task* task = *it;
task->aborted_ = true;
++it;
}
cond_.broadcast();
mutex_.unlock();
Thread::yield();
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) {
mutex_.lock();
if (tasks_.empty()) {
mutex_.unlock();
break;
}
mutex_.unlock();
if (wsec > 1.0) wsec = 1.0;
Thread::sleep(wsec);
}
mutex_.lock();
for (size_t i = 0; i < thnum_; i++) {
thary_[i].aborted_ = true;
}
cond_.broadcast();
mutex_.unlock();
for (size_t i = 0; i < thnum_; i++) {
thary_[i].join();
}
delete[] thary_;
}
/**
* Add a task.
* @param task a task object.
* @return the number of tasks in the queue.
*/
int64_t add_task(Task* task) {
_assert_(task);
mutex_.lock();
task->id_ = ++seed_;
tasks_.push_back(task);
int64_t count = ++count_;
cond_.signal();
mutex_.unlock();
return count;
}
/**
* Get the number of tasks in the queue.
* @return the number of tasks in the queue.
*/
int64_t count() {
_assert_(true);
mutex_.lock();
int64_t count = count_;
mutex_.unlock();
return count;
}
private:
/**
* Implementation of the worker thread.
*/
class WorkerThread : public Thread {
friend class TaskQueue;
public:
explicit WorkerThread() : id_(0), queue_(NULL), aborted_(false) {
_assert_(true);
}
private:
void run() {
_assert_(true);
Task* stask = new Task;
stask->thid_ = id_;
queue_->do_start(stask);
delete stask;
bool empty = false;
while (true) {
queue_->mutex_.lock();
if (aborted_) {
queue_->mutex_.unlock();
break;
}
if (empty) queue_->cond_.wait(&queue_->mutex_, 1.0);
Task * task = NULL;
if (queue_->tasks_.empty()) {
empty = true;
} else {
task = queue_->tasks_.front();
task->thid_ = id_;
queue_->tasks_.pop_front();
queue_->count_--;
empty = false;
}
queue_->mutex_.unlock();
if (task) queue_->do_task(task);
}
Task* ftask = new Task;
ftask->thid_ = id_;
ftask->aborted_ = true;
queue_->do_finish(ftask);
delete ftask;
}
uint32_t id_;
TaskQueue* queue_;
Task* task_;
bool aborted_;
};
/** Dummy constructor to forbid the use. */
TaskQueue(const TaskQueue&);
/** Dummy Operator to forbid the use. */
TaskQueue& operator =(const TaskQueue&);
/** The array of worker threads. */
WorkerThread* thary_;
/** The number of worker threads. */
size_t thnum_;
/** The list of tasks. */
TaskList tasks_;
/** The number of the tasks. */
int64_t count_;
/** The mutex for the task list. */
Mutex mutex_;
/** The condition variable for the task list. */
CondVar cond_;
/** The seed of ID numbers. */
uint64_t seed_;
};
} // common namespace
#endif // duplication check
// END OF FILE
kyotocabinet-1.2.76/kclangc.cc 0000644 0001750 0001750 00000106151 11757460617 015237 0 ustar mikio mikio /*************************************************************************************************
* C language binding
* Copyright (C) 2009-2012 FAL Labs
* This file is part of Kyoto Cabinet.
* This program is free software: you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation, either version
* 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program.
* If not, see .
*************************************************************************************************/
#include "kcpolydb.h"
#include "kcdbext.h"
#include "kclangc.h"
#include "myconf.h"
using namespace kyotocabinet;
extern "C" {
/** The package version. */
const char* const KCVERSION = VERSION;
/** Special pointer for no operation by the visiting function. */
const char* const KCVISNOP = DB::Visitor::NOP;
/** Special pointer to remove the record by the visiting function. */
const char* const KCVISREMOVE = DB::Visitor::REMOVE;
/**
* Allocate a region on memory.
*/
void* kcmalloc(size_t size) {
_assert_(size > 0 && size <= MEMMAXSIZ);
return new char[size];
}
/**
* Release a region allocated in the library.
*/
void kcfree(void* ptr) {
_assert_(true);
delete[] (char*)ptr;
}
/**
* Get the time of day in seconds.
*/
double kctime(void) {
_assert_(true);
return kyotocabinet::time();
}
/**
* Convert a string to an integer.
*/
int64_t kcatoi(const char* str) {
_assert_(str);
return kyotocabinet::atoi(str);
}
/**
* Convert a string with a metric prefix to an integer.
*/
int64_t kcatoix(const char* str) {
_assert_(str);
return kyotocabinet::atoix(str);
}
/**
* Convert a string to a real number.
*/
double kcatof(const char* str) {
_assert_(str);
return kyotocabinet::atof(str);
}
/**
* Get the hash value by MurMur hashing.
*/
uint64_t kchashmurmur(const void* buf, size_t size) {
_assert_(buf && size <= MEMMAXSIZ);
return kyotocabinet::hashmurmur(buf, size);
}
/**
* Get the hash value by FNV hashing.
*/
uint64_t kchashfnv(const void* buf, size_t size) {
_assert_(buf && size <= MEMMAXSIZ);
return kyotocabinet::hashfnv(buf, size);
}
/**
* Calculate the levenshtein distance of two regions.
*/
size_t kclevdist(const void* abuf, size_t asiz, const void* bbuf, size_t bsiz, int32_t utf) {
_assert_(abuf && asiz <= MEMMAXSIZ && bbuf && bsiz <= MEMMAXSIZ);
size_t dist;
if (utf) {
uint32_t astack[128];
uint32_t* aary = asiz > sizeof(astack) / sizeof(*astack) ? new uint32_t[asiz] : astack;
size_t anum;
strutftoucs((const char*)abuf, asiz, aary, &anum);
uint32_t bstack[128];
uint32_t* bary = bsiz > sizeof(bstack) / sizeof(*bstack) ? new uint32_t[bsiz] : bstack;
size_t bnum;
strutftoucs((const char*)bbuf, bsiz, bary, &bnum);
dist = strucsdist(aary, anum, bary, bnum);
if (bary != bstack) delete[] bary;
if (aary != astack) delete[] aary;
} else {
dist = memdist(abuf, asiz, bbuf, bsiz);
}
return dist;
}
/**
* Get the quiet Not-a-Number value.
*/
double kcnan() {
_assert_(true);
return kyotocabinet::nan();
}
/**
* Get the positive infinity value.
*/
double kcinf() {
_assert_(true);
return kyotocabinet::inf();
}
/**
* Check a number is a Not-a-Number value.
*/
int32_t kcchknan(double num) {
_assert_(true);
return kyotocabinet::chknan(num);
}
/**
* Check a number is an infinity value.
*/
int32_t kcchkinf(double num) {
_assert_(true);
return kyotocabinet::chkinf(num);
}
/**
* Get the readable string of an error code.
*/
const char* kcecodename(int32_t code) {
_assert_(true);
return BasicDB::Error::codename((BasicDB::Error::Code)code);
}
/**
* Create a database object.
*/
KCDB* kcdbnew(void) {
_assert_(true);
return (KCDB*)new PolyDB;
}
/**
* Destroy a database object.
*/
void kcdbdel(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
delete pdb;
}
/**
* Open a database file.
*/
int32_t kcdbopen(KCDB* db, const char* path, uint32_t mode) {
_assert_(db && path);
PolyDB* pdb = (PolyDB*)db;
return pdb->open(path, mode);
}
/**
* Close the database file.
*/
int32_t kcdbclose(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->close();
}
/**
* Get the code of the last happened error.
*/
int32_t kcdbecode(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->error().code();
}
/**
* Get the supplement message of the last happened error.
*/
const char* kcdbemsg(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->error().message();
}
/**
* Accept a visitor to a record.
*/
int32_t kcdbaccept(KCDB* db, const char* kbuf, size_t ksiz,
KCVISITFULL fullproc, KCVISITEMPTY emptyproc, void* opq, int32_t writable) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
class VisitorImpl : public DB::Visitor {
public:
explicit VisitorImpl(KCVISITFULL fullproc, KCVISITEMPTY emptyproc, void* opq) :
fullproc_(fullproc), emptyproc_(emptyproc), opq_(opq) {}
const char* visit_full(const char* kbuf, size_t ksiz,
const char* vbuf, size_t vsiz, size_t* sp) {
if (!fullproc_) return NOP;
return fullproc_(kbuf, ksiz, vbuf, vsiz, sp, opq_);
}
const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
if (!emptyproc_) return NOP;
return emptyproc_(kbuf, ksiz, sp, opq_);
}
private:
KCVISITFULL fullproc_;
KCVISITEMPTY emptyproc_;
void* opq_;
};
VisitorImpl visitor(fullproc, emptyproc, opq);
return pdb->accept(kbuf, ksiz, &visitor, writable);
}
/**
* Accept a visitor to multiple records at once.
*/
int32_t kcdbacceptbulk(KCDB* db, const KCSTR* keys, size_t knum,
KCVISITFULL fullproc, KCVISITEMPTY emptyproc,
void* opq, int32_t writable) {
_assert_(db && keys && knum <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
std::vector xkeys;
xkeys.reserve(knum);
for (size_t i = 0; i < knum; i++) {
xkeys.push_back(std::string(keys[i].buf, keys[i].size));
}
class VisitorImpl : public DB::Visitor {
public:
explicit VisitorImpl(KCVISITFULL fullproc, KCVISITEMPTY emptyproc, void* opq) :
fullproc_(fullproc), emptyproc_(emptyproc), opq_(opq) {}
const char* visit_full(const char* kbuf, size_t ksiz,
const char* vbuf, size_t vsiz, size_t* sp) {
if (!fullproc_) return NOP;
return fullproc_(kbuf, ksiz, vbuf, vsiz, sp, opq_);
}
const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
if (!emptyproc_) return NOP;
return emptyproc_(kbuf, ksiz, sp, opq_);
}
private:
KCVISITFULL fullproc_;
KCVISITEMPTY emptyproc_;
void* opq_;
};
VisitorImpl visitor(fullproc, emptyproc, opq);
return pdb->accept_bulk(xkeys, &visitor, writable);
}
/**
* Iterate to accept a visitor for each record.
*/
int32_t kcdbiterate(KCDB* db, KCVISITFULL fullproc, void* opq, int32_t writable) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
class VisitorImpl : public DB::Visitor {
public:
explicit VisitorImpl(KCVISITFULL fullproc, void* opq) : fullproc_(fullproc), opq_(opq) {}
const char* visit_full(const char* kbuf, size_t ksiz,
const char* vbuf, size_t vsiz, size_t* sp) {
if (!fullproc_) return NOP;
return fullproc_(kbuf, ksiz, vbuf, vsiz, sp, opq_);
}
private:
KCVISITFULL fullproc_;
void* opq_;
};
VisitorImpl visitor(fullproc, opq);
return pdb->iterate(&visitor, writable);
}
/**
* Scan each record in parallel.
*/
int32_t kcdbscanpara(KCDB* db, KCVISITFULL fullproc, void* opq, size_t thnum) {
_assert_(db && thnum <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
class VisitorImpl : public DB::Visitor {
public:
explicit VisitorImpl(KCVISITFULL fullproc, void* opq) : fullproc_(fullproc), opq_(opq) {}
const char* visit_full(const char* kbuf, size_t ksiz,
const char* vbuf, size_t vsiz, size_t* sp) {
if (!fullproc_) return NOP;
return fullproc_(kbuf, ksiz, vbuf, vsiz, sp, opq_);
}
private:
KCVISITFULL fullproc_;
void* opq_;
};
VisitorImpl visitor(fullproc, opq);
return pdb->scan_parallel(&visitor, thnum);
}
/**
* Set the value of a record.
*/
int32_t kcdbset(KCDB* db, const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->set(kbuf, ksiz, vbuf, vsiz);
}
/**
* Add a record.
*/
int32_t kcdbadd(KCDB* db, const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->add(kbuf, ksiz, vbuf, vsiz);
}
/**
* Replace the value of a record.
*/
int32_t kcdbreplace(KCDB* db, const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->replace(kbuf, ksiz, vbuf, vsiz);
}
/**
* Append the value of a record.
*/
int32_t kcdbappend(KCDB* db, const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->append(kbuf, ksiz, vbuf, vsiz);
}
/**
* Add a number to the numeric value of a record.
*/
int64_t kcdbincrint(KCDB* db, const char* kbuf, size_t ksiz, int64_t num, int64_t orig) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->increment(kbuf, ksiz, num, orig);
}
/**
* Add a number to the numeric value of a record.
*/
double kcdbincrdouble(KCDB* db, const char* kbuf, size_t ksiz, double num, double orig) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->increment_double(kbuf, ksiz, num, orig);
}
/**
* Perform compare-and-swap.
*/
int32_t kcdbcas(KCDB* db, const char* kbuf, size_t ksiz,
const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->cas(kbuf, ksiz, ovbuf, ovsiz, nvbuf, nvsiz);
}
/**
* Remove a record.
*/
int32_t kcdbremove(KCDB* db, const char* kbuf, size_t ksiz) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->remove(kbuf, ksiz);
}
/**
* Retrieve the value of a record.
*/
char* kcdbget(KCDB* db, const char* kbuf, size_t ksiz, size_t* sp) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ && sp);
PolyDB* pdb = (PolyDB*)db;
return pdb->get(kbuf, ksiz, sp);
}
/**
* Check the existence of a record.
*/
int32_t kcdbcheck(KCDB* db, const char* kbuf, size_t ksiz) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
return pdb->check(kbuf, ksiz);
}
/**
* Retrieve the value of a record.
*/
int32_t kcdbgetbuf(KCDB* db, const char* kbuf, size_t ksiz, char* vbuf, size_t max) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ && vbuf);
PolyDB* pdb = (PolyDB*)db;
return pdb->get(kbuf, ksiz, vbuf, max);
}
/**
* Retrieve the value of a record and remove it atomically.
*/
char* kcdbseize(KCDB* db, const char* kbuf, size_t ksiz, size_t* sp) {
_assert_(db && kbuf && ksiz <= MEMMAXSIZ && sp);
PolyDB* pdb = (PolyDB*)db;
return pdb->seize(kbuf, ksiz, sp);
}
/**
* Store records at once.
*/
int64_t kcdbsetbulk(KCDB* db, const KCREC* recs, size_t rnum, int32_t atomic) {
_assert_(db && recs && rnum <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
std::map xrecs;
for (size_t i = 0; i < rnum; i++) {
const KCREC* rec = recs + i;
xrecs[std::string(rec->key.buf, rec->key.size)] =
std::string(rec->value.buf, rec->value.size);
}
return pdb->set_bulk(xrecs, atomic);
}
/**
* Remove records at once.
*/
int64_t kcdbremovebulk(KCDB* db, const KCSTR* keys, size_t knum, int32_t atomic) {
_assert_(db && keys && knum <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
std::vector xkeys;
xkeys.reserve(knum);
for (size_t i = 0; i < knum; i++) {
const KCSTR* key = keys + i;
xkeys.push_back(std::string(key->buf, key->size));
}
return pdb->remove_bulk(xkeys, atomic);
}
/**
* Retrieve records at once.
*/
int64_t kcdbgetbulk(KCDB* db, const KCSTR* keys, size_t knum, KCREC* recs, int32_t atomic) {
_assert_(db && keys && knum <= MEMMAXSIZ && recs);
PolyDB* pdb = (PolyDB*)db;
std::vector xkeys;
xkeys.reserve(knum);
for (size_t i = 0; i < knum; i++) {
const KCSTR* key = keys + i;
xkeys.push_back(std::string(key->buf, key->size));
}
std::map xrecs;
if (pdb->get_bulk(xkeys, &xrecs, atomic) < 0) return -1;
std::map::iterator it = xrecs.begin();
std::map::iterator itend = xrecs.end();
size_t ridx = 0;
while (ridx < knum && it != itend) {
size_t ksiz = it->first.size();
char* kbuf = new char[ksiz+1];
std::memcpy(kbuf, it->first.data(), ksiz);
kbuf[ksiz] = '\0';
size_t vsiz = it->second.size();
char* vbuf = new char[vsiz+1];
std::memcpy(vbuf, it->second.data(), vsiz);
vbuf[vsiz] = '\0';
KCREC* rec = recs + (ridx++);
rec->key.buf = kbuf;
rec->key.size = ksiz;
rec->value.buf = vbuf;
rec->value.size = vsiz;
++it;
}
return ridx;
}
/**
* Synchronize updated contents with the file and the device.
*/
int32_t kcdbsync(KCDB* db, int32_t hard, KCFILEPROC proc, void* opq) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
class FileProcessorImpl : public BasicDB::FileProcessor {
public:
explicit FileProcessorImpl(KCFILEPROC proc, void* opq) : proc_(proc), opq_(opq) {}
bool process(const std::string& path, int64_t count, int64_t size) {
if (!proc_) return true;
return proc_(path.c_str(), count, size, opq_);
}
private:
KCFILEPROC proc_;
void* opq_;
};
FileProcessorImpl myproc(proc, opq);
return pdb->synchronize(hard, &myproc);
}
/**
* Occupy database by locking and do something meanwhile.
*/
int32_t kcdboccupy(KCDB* db, int32_t writable, KCFILEPROC proc, void* opq) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
class FileProcessorImpl : public BasicDB::FileProcessor {
public:
explicit FileProcessorImpl(KCFILEPROC proc, void* opq) : proc_(proc), opq_(opq) {}
bool process(const std::string& path, int64_t count, int64_t size) {
if (!proc_) return true;
return proc_(path.c_str(), count, size, opq_);
}
private:
KCFILEPROC proc_;
void* opq_;
};
FileProcessorImpl myproc(proc, opq);
return pdb->occupy(writable, &myproc);
}
/**
* Create a copy of the database file.
*/
int32_t kcdbcopy(KCDB* db, const char* dest) {
_assert_(db && dest);
PolyDB* pdb = (PolyDB*)db;
return pdb->copy(dest);
}
/**
* Begin transaction.
*/
int32_t kcdbbegintran(KCDB* db, int32_t hard) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->begin_transaction(hard);
}
/**
* Try to begin transaction.
*/
int32_t kcdbbegintrantry(KCDB* db, int32_t hard) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->begin_transaction_try(hard);
}
/**
* End transaction.
*/
int32_t kcdbendtran(KCDB* db, int32_t commit) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->end_transaction(commit);
}
/**
* Remove all records.
*/
int32_t kcdbclear(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->clear();
}
/**
* Dump records into a file.
*/
int32_t kcdbdumpsnap(KCDB* db, const char* dest) {
_assert_(db && dest);
PolyDB* pdb = (PolyDB*)db;
return pdb->dump_snapshot(dest);
}
/**
* Load records from a file.
*/
int32_t kcdbloadsnap(KCDB* db, const char* src) {
_assert_(db && src);
PolyDB* pdb = (PolyDB*)db;
return pdb->load_snapshot(src);
}
/**
* Get the number of records.
*/
int64_t kcdbcount(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->count();
}
/**
* Get the size of the database file.
*/
int64_t kcdbsize(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
return pdb->size();
}
/**
* Get the path of the database file.
*/
char* kcdbpath(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
std::string path = pdb->path();
size_t psiz = path.size();
char* pbuf = new char[psiz+1];
std::memcpy(pbuf, path.c_str(), psiz + 1);
return pbuf;
}
/**
* Get the miscellaneous status information.
*/
char* kcdbstatus(KCDB* db) {
_assert_(db);
PolyDB* pdb = (PolyDB*)db;
std::map status;
if (!pdb->status(&status)) return NULL;
std::ostringstream obuf;
std::map::iterator it = status.begin();
std::map::iterator itend = status.end();
while (it != itend) {
obuf << it->first << "\t" << it->second << "\n";
++it;
}
std::string sstr = obuf.str();
size_t ssiz = sstr.size();
char* sbuf = new char[ssiz+1];
std::memcpy(sbuf, sstr.c_str(), ssiz + 1);
return sbuf;
}
/**
* Get keys matching a prefix string.
*/
int64_t kcdbmatchprefix(KCDB* db, const char* prefix, char** strary, size_t max) {
_assert_(db && prefix && strary && max <= MEMMAXSIZ);
PolyDB* pdb = (PolyDB*)db;
std::vector strvec;
if (pdb->match_prefix(prefix, &strvec, max) == -1) return -1;
int64_t cnt = 0;
std::vector::iterator it = strvec.begin();
std::vector