1#------------------------------------------------------------------------------------------------- 2# Perl binding of Kyoto Cabinet 3# Copyright (C) 2009-2010 FAL Labs 4# This file is part of Kyoto Cabinet. 5# This program is free software: you can redistribute it and/or modify it under the terms of 6# the GNU General Public License as published by the Free Software Foundation, either version 7# 3 of the License, or any later version. 8# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 9# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 10# See the GNU General Public License for more details. 11# You should have received a copy of the GNU General Public License along with this program. 12# If not, see <http://www.gnu.org/licenses/>. 13#------------------------------------------------------------------------------------------------- 14 15 16package KyotoCabinet; 17 18use strict; 19use warnings; 20 21require Exporter; 22require XSLoader; 23use base qw(Exporter); 24our $VERSION = '1.20'; 25XSLoader::load('KyotoCabinet', $VERSION); 26 27 28 29package KyotoCabinet::Error; 30 31use overload q("") => \&string; 32use overload "<=>" => \&compare; 33 34 35sub new { 36 my ($cls, $code, $message) = @_; 37 my $self = [SUCCESS(), "error"]; 38 if (defined($code) && defined($message)) { 39 $self->[0] = $code; 40 $self->[1] = $message; 41 } 42 bless $self; 43 return $self; 44} 45 46 47sub set { 48 my ($self, $code, $message) = @_; 49 $self->[0] = $code; 50 $self->[1] = $message; 51 return undef; 52} 53 54 55sub code { 56 my ($self) = @_; 57 return $self->[0]; 58} 59 60 61sub name { 62 my ($self) = @_; 63 return err_codename($self->[0]); 64} 65 66 67sub message { 68 my ($self) = @_; 69 return $self->[1]; 70} 71 72 73sub string { 74 my ($self) = @_; 75 return sprintf("%s: %s", $self->name, $self->message); 76} 77 78 79sub compare { 80 my ($self, $right) = @_; 81 $right = $right->code if (ref($right) eq __PACKAGE__); 82 return $self->code <=> $right; 83} 84 85 86 87package KyotoCabinet::Visitor; 88 89 90sub new { 91 my ($cls) = @_; 92 my $self = {}; 93 bless $self; 94 return $self; 95} 96 97 98sub visit_full { 99 my ($self, $key, $value) = @_; 100 return $self->NOP; 101} 102 103 104sub visit_empty { 105 my ($self, $key) = @_; 106 return $self->NOP; 107} 108 109 110 111package KyotoCabinet::FileProcessor; 112 113sub new { 114 my ($cls) = @_; 115 my $self = {}; 116 bless $self; 117 return $self; 118} 119 120 121sub process { 122 my ($self, $path, $count, $size) = @_; 123 return 1; 124} 125 126 127 128package KyotoCabinet::Cursor; 129 130use overload q("") => \&string; 131 132 133sub new { 134 my ($cls, $db) = @_; 135 my $self = [0, undef]; 136 $self->[0] = cur_new($db->[0]); 137 $self->[1] = $db; 138 bless $self; 139 return $self; 140} 141 142 143sub DESTROY { 144 my ($self) = @_; 145 cur_delete($self->[0]); 146 return undef; 147} 148 149 150sub disable { 151 my ($self) = @_; 152 cur_disable($self->[0]); 153 $self->[0] = 0; 154 return undef; 155} 156 157 158sub accept { 159 my ($self, $visitor, $writable, $step) = @_; 160 $writable = 1 if (!defined($writable)); 161 $step = 0 if (!defined($step)); 162 return cur_accept($self->[0], $visitor, $writable, $step); 163} 164 165 166sub set_value { 167 my ($self, $value, $step) = @_; 168 return cur_set_value($self->[0], $value, $step); 169} 170 171 172sub remove { 173 my ($self) = @_; 174 return cur_remove($self->[0]); 175} 176 177 178sub get_key { 179 my ($self, $step) = @_; 180 $step = 0 if (!defined($step)); 181 return cur_get_key($self->[0], $step); 182} 183 184 185sub get_value { 186 my ($self, $step) = @_; 187 $step = 0 if (!defined($step)); 188 return cur_get_value($self->[0], $step); 189} 190 191 192sub get { 193 my ($self, $step) = @_; 194 $step = 0 if (!defined($step)); 195 return cur_get($self->[0], $step); 196} 197 198 199sub seize { 200 my ($self) = @_; 201 return cur_seize($self->[0]); 202} 203 204 205sub jump { 206 my ($self, $key) = @_; 207 return cur_jump($self->[0], $key); 208} 209 210 211sub jump_back { 212 my ($self, $key) = @_; 213 return cur_jump_back($self->[0], $key); 214} 215 216 217sub step { 218 my ($self) = @_; 219 return cur_step($self->[0]); 220} 221 222 223sub step_back { 224 my ($self) = @_; 225 return cur_step_back($self->[0]); 226} 227 228 229sub db { 230 my ($self) = @_; 231 return $self->[1]; 232} 233 234 235sub error { 236 my ($self) = @_; 237 return $self->[1]->error; 238} 239 240 241sub string { 242 my ($self) = @_; 243 my $db = $self->[1]; 244 my $path = $db->path; 245 $path = "(undef)" if (!defined($path)); 246 my $key = $self->get_key; 247 $key = "(undef)" if (!defined($key)); 248 return sprintf("%s: %s", $path, $key); 249} 250 251 252 253package KyotoCabinet::DB; 254 255use overload q("") => \&string; 256 257 258sub new { 259 my ($cls) = @_; 260 my $self = [0, undef, undef]; 261 $self->[0] = db_new(); 262 bless $self; 263 return $self; 264} 265 266 267sub DESTROY { 268 my ($self) = @_; 269 db_delete($self->[0]); 270 return undef; 271} 272 273 274sub error { 275 my ($self) = @_; 276 my ($code, $message) = db_error($self->[0]); 277 return KyotoCabinet::Error->new($code, $message); 278} 279 280 281sub open { 282 my ($self, $path, $mode) = @_; 283 $path = ":" if (!defined($path)); 284 $mode = OWRITER() | OCREATE() if (!defined($mode) || $mode < 1); 285 return db_open($self->[0], $path, $mode); 286} 287 288 289sub close { 290 my ($self) = @_; 291 return db_close($self->[0]); 292} 293 294 295sub accept { 296 my ($self, $key, $visitor, $writable) = @_; 297 $writable = 1 if (!defined($writable)); 298 return db_accept($self->[0], $key, $visitor, $writable); 299} 300 301 302sub accept_bulk { 303 my ($self, $keys, $visitor, $writable) = @_; 304 return 0 if (ref($keys) ne 'ARRAY'); 305 $writable = 1 if (!defined($writable)); 306 foreach my $key (@$keys) { 307 return 0 if (!db_accept($self->[0], $key, $visitor, $writable)); 308 } 309 return 1; 310} 311 312 313sub iterate { 314 my ($self, $visitor, $writable) = @_; 315 $writable = 1 if (!defined($writable)); 316 return db_iterate($self->[0], $visitor, $writable); 317} 318 319 320sub set { 321 my ($self, $key, $value) = @_; 322 return db_set($self->[0], $key, $value); 323} 324 325 326sub add { 327 my ($self, $key, $value) = @_; 328 return db_add($self->[0], $key, $value); 329} 330 331 332sub replace { 333 my ($self, $key, $value) = @_; 334 return db_replace($self->[0], $key, $value); 335} 336 337 338sub append { 339 my ($self, $key, $value) = @_; 340 return db_append($self->[0], $key, $value); 341} 342 343 344sub increment { 345 my ($self, $key, $num, $orig) = @_; 346 $num = 0 if (!defined($num)); 347 $orig = 0 if (!defined($orig)); 348 return db_increment($self->[0], $key, $num, $orig); 349} 350 351 352sub increment_double { 353 my ($self, $key, $num, $orig) = @_; 354 $num = 0 if (!defined($num)); 355 $orig = 0 if (!defined($orig)); 356 return db_increment_double($self->[0], $key, $num, $orig); 357} 358 359 360sub cas { 361 my ($self, $key, $oval, $nval) = @_; 362 return db_cas($self->[0], $key, $oval, $nval); 363} 364 365 366sub remove { 367 my ($self, $key) = @_; 368 return db_remove($self->[0], $key); 369} 370 371 372sub get { 373 my ($self, $key) = @_; 374 return db_get($self->[0], $key); 375} 376 377 378sub check { 379 my ($self, $key) = @_; 380 return db_check($self->[0], $key); 381} 382 383 384sub seize { 385 my ($self, $key) = @_; 386 return db_seize($self->[0], $key); 387} 388 389 390sub set_bulk { 391 my ($self, $recs) = @_; 392 return -1 if (ref($recs) ne 'HASH'); 393 my $rv = 0; 394 while (my ($key, $value) = each(%$recs)) { 395 return -1 if (!db_set($self->[0], $key, $value)); 396 $rv++; 397 } 398 return $rv; 399} 400 401 402sub remove_bulk { 403 my ($self, $keys) = @_; 404 return -1 if (ref($keys) ne 'ARRAY'); 405 my $rv = 0; 406 foreach my $key (@$keys) { 407 $rv++ if (db_remove($self->[0], $key)); 408 } 409 return $rv; 410} 411 412 413sub get_bulk { 414 my ($self, $keys) = @_; 415 return -1 if (ref($keys) ne 'ARRAY'); 416 my %recs; 417 foreach my $key (@$keys) { 418 my $value = db_get($self->[0], $key); 419 $recs{$key} = $value if (defined($value)); 420 } 421 return \%recs; 422} 423 424 425sub clear { 426 my ($self) = @_; 427 return db_clear($self->[0]); 428} 429 430 431sub synchronize { 432 my ($self, $hard, $proc) = @_; 433 return db_synchronize($self->[0], $hard, $proc); 434} 435 436 437sub occupy { 438 my ($self, $writable, $proc) = @_; 439 return db_occupy($self->[0], $writable, $proc); 440} 441 442 443sub copy { 444 my ($self, $dest) = @_; 445 return db_copy($self->[0], $dest); 446} 447 448 449sub begin_transaction { 450 my ($self, $hard) = @_; 451 $hard = 0 if (!defined($hard)); 452 return db_begin_transaction($self->[0], $hard); 453} 454 455 456sub end_transaction { 457 my ($self, $commit) = @_; 458 $commit = 1 if (!defined($commit)); 459 return db_end_transaction($self->[0], $commit); 460} 461 462 463sub transaction { 464 my ($self, $proc, $hard) = @_; 465 return 0 if (!$self->begin_transaction($hard)); 466 my $commit = 0; 467 eval { 468 $commit = &$proc($self); 469 }; 470 return 0 if (!$self->end_transaction($commit)); 471 return 1; 472} 473 474 475sub dump_snapshot { 476 my ($self, $dest) = @_; 477 return db_dump_snapshot($self->[0], $dest); 478} 479 480 481sub load_snapshot { 482 my ($self, $src) = @_; 483 return db_load_snapshot($self->[0], $src); 484} 485 486 487sub count { 488 my ($self) = @_; 489 return db_count($self->[0]); 490} 491 492 493sub size { 494 my ($self) = @_; 495 return db_size($self->[0]); 496} 497 498 499sub path { 500 my ($self) = @_; 501 return db_path($self->[0]); 502} 503 504 505sub status { 506 my ($self) = @_; 507 my $ststr = db_status($self->[0]); 508 return undef if (!defined($ststr)); 509 my %stmap; 510 my @lines = split(/\n/, $ststr); 511 foreach my $line (@lines) { 512 my @fields = split(/\t/, $line); 513 $stmap{$fields[0]} = $fields[1] if (scalar(@fields) > 1); 514 } 515 return \%stmap; 516} 517 518 519sub match_prefix { 520 my ($self, $prefix, $max) = @_; 521 $max = -1 if (!defined($max)); 522 return db_match_prefix($self->[0], $prefix, $max); 523} 524 525 526sub match_regex { 527 my ($self, $regex, $max) = @_; 528 $max = -1 if (!defined($max)); 529 return db_match_regex($self->[0], $regex, $max); 530} 531 532 533sub match_similar { 534 my ($self, $origin, $range, $utf, $max) = @_; 535 $range = 1 if (!defined($range)); 536 $utf = 0 if (!defined($utf)); 537 $max = -1 if (!defined($max)); 538 return db_match_similar($self->[0], $origin, $range, $utf, $max); 539} 540 541 542sub merge { 543 my ($self, $srcary, $mode) = @_; 544 $mode = MSET() if (!defined($mode)); 545 return db_merge($self->[0], $srcary, $mode); 546} 547 548 549sub cursor { 550 my ($self) = @_; 551 return KyotoCabinet::Cursor->new($self); 552} 553 554 555sub cursor_process { 556 my ($self, $proc) = @_; 557 my $cur = $self->cursor; 558 eval { 559 &$proc($cur); 560 }; 561 $cur->disable; 562 return undef; 563} 564 565 566sub string { 567 my ($self) = @_; 568 my $path = $self->path; 569 $path = "(undef)" if (!defined($path)); 570 return sprintf("%s: %ld: %ld", $path, $self->count, $self->size); 571} 572 573 574sub process { 575 my ($cls, $proc, $path, $mode) = @_; 576 my $db = $cls->new; 577 return $db->error if (!$db->open($path, $mode)); 578 &$proc($db); 579 return $db->error if (!$db->close); 580 return undef; 581} 582 583 584sub TIEHASH { 585 my ($cls, $path, $mode) = @_; 586 my $db = $cls->new; 587 return undef if (!$db->open($path, $mode)); 588 my $cur = $db->cursor; 589 undef($cur->[1]); 590 $db->[1] = $cur; 591 return $db; 592} 593 594 595sub UNTIE { 596 my ($self) = @_; 597 return $self->close; 598} 599 600 601sub FETCH { 602 return db_get($_[0]->[0], $_[1]); 603} 604 605 606sub STORE { 607 return db_set($_[0]->[0], $_[1], $_[2]); 608} 609 610 611sub DELETE { 612 return db_remove($_[0]->[0], $_[1]); 613} 614 615 616sub CLEAR { 617 return db_clear($_[0]->[0]); 618} 619 620 621sub EXISTS { 622 return defined(db_get($_[0]->[0], $_[1])); 623} 624 625 626sub FIRSTKEY { 627 my $cur = $_[0]->[1]; 628 $cur->jump; 629 my $key = $cur->get_key(1); 630 $_[0]->[2] = $key; 631 return $key; 632} 633 634 635sub NEXTKEY { 636 my $cur = $_[0]->[1]; 637 my $key = $cur->get_key(1); 638 return undef if (!defined($key)); 639 if ($key eq $_[0]->[2]) { 640 undef($_[0]->[2]); 641 return undef; 642 } 643 return $key; 644} 645 646 647 6481; 649 650# END OF FILE 651