1 | ###########################################################################
|
---|
2 | #
|
---|
3 | # TDBCLUSTER -- utility functions for writing to TDB databases. Should be
|
---|
4 | # hauntingly similar to GDBM utility functions. However, allows
|
---|
5 | # TDB to be run on a cluster where the locking mechanism for
|
---|
6 | # multiple reader/writers only works on a per-computer node
|
---|
7 | # basis. Essentially, each compute node gets its own data-
|
---|
8 | # base to write to (possible with multiple writers) and then
|
---|
9 | # the top-level caller merges these individual databases back
|
---|
10 | # into a single database.
|
---|
11 | #
|
---|
12 | # A component of the Greenstone digital library software
|
---|
13 | # from the New Zealand Digital Library Project at the
|
---|
14 | # University of Waikato, New Zealand.
|
---|
15 | #
|
---|
16 | # Copyright (c) 2015 New Zealand Digital Library Project
|
---|
17 | #
|
---|
18 | # This program is free software; you can redistribute it and/or modify
|
---|
19 | # it under the terms of the GNU General Public License as published by
|
---|
20 | # the Free Software Foundation; either version 2 of the License, or
|
---|
21 | # (at your option) any later version.
|
---|
22 | #
|
---|
23 | # This program is distributed in the hope that it will be useful,
|
---|
24 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
25 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
26 | # GNU General Public License for more details.
|
---|
27 | #
|
---|
28 | # You should have received a copy of the GNU General Public License
|
---|
29 | # along with this program; if not, write to the Free Software
|
---|
30 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
31 | #
|
---|
32 | ###########################################################################
|
---|
33 |
|
---|
34 | package DBDrivers::TDBCLUSTER;
|
---|
35 |
|
---|
36 | # Pragma
|
---|
37 | use strict;
|
---|
38 |
|
---|
39 | sub BEGIN
|
---|
40 | {
|
---|
41 | if (!defined $ENV{'GSDLHOME'} || !defined $ENV{'GSDLOS'}) {
|
---|
42 | die("Error! Environment not prepared. Have you sourced setup.bash?\n");
|
---|
43 | }
|
---|
44 | if (!defined $ENV{'GEXTTDBEDIT_INSTALLED'}) {
|
---|
45 | die("Error! Path to TDB binaries not found. Have you sourced setup.bash?\n");
|
---|
46 | }
|
---|
47 | }
|
---|
48 |
|
---|
49 | # Libraries/Modules
|
---|
50 | use Cwd;
|
---|
51 | use dbutil::gdbmtxtgz;
|
---|
52 | use dbutil::tdb;
|
---|
53 | use parent 'DBDrivers::70HyphenFormat';
|
---|
54 |
|
---|
55 | ##
|
---|
56 | #
|
---|
57 | sub new
|
---|
58 | {
|
---|
59 | my $class = shift(@_);
|
---|
60 |
|
---|
61 | my $self = DBDrivers::70HyphenFormat->new(@_);
|
---|
62 |
|
---|
63 | # Default TDB file extension
|
---|
64 | $self->{'default_file_extension'} = 'tdb';
|
---|
65 | # Should the TDB used a specific affinity?
|
---|
66 | $self->{'forced_affinity'} = -1; # zero upwards indicates the affinity
|
---|
67 | # Ask TDB executables to display debugging information?
|
---|
68 | $self->{'tdb_debug'} = 0; # 1 to enable
|
---|
69 |
|
---|
70 | # On a cluster, we need to know the hostname of the headnode
|
---|
71 | $self->{'headnode'} = 'medusa';
|
---|
72 |
|
---|
73 | # note: file separator agnostic
|
---|
74 | $self->{'executable_path'} = $ENV{GEXTTDBEDIT_INSTALLED} . '/bin/';
|
---|
75 | $self->{'read_executable'} = 'tdb2txt';
|
---|
76 | $self->{'keyread_executable'} = 'tdbkeys';
|
---|
77 | $self->{'write_executable'} = 'txt2tdb';
|
---|
78 |
|
---|
79 | # Optional Support
|
---|
80 | $self->{'supports_persistentconnection'} = 1;
|
---|
81 | $self->{'supports_set'} = 1;
|
---|
82 |
|
---|
83 | bless($self, $class);
|
---|
84 | return $self;
|
---|
85 | }
|
---|
86 |
|
---|
87 | # -----------------------------------------------------------------------------
|
---|
88 | # TDB IMPLEMENTATION
|
---|
89 | # -----------------------------------------------------------------------------
|
---|
90 |
|
---|
91 | ## @function get_tdb_executable(string)
|
---|
92 | #
|
---|
93 | sub get_tdb_executable
|
---|
94 | {
|
---|
95 | my $self = shift(@_);
|
---|
96 | my $program = shift(@_);
|
---|
97 | my $program_exe = &util::filename_cat($program . &util::get_os_exe());
|
---|
98 | #if (!-x $program_exe) {
|
---|
99 | # die('Fatal Error! File doesn\'t exist or isn\'t executable: ' . $program_exe);
|
---|
100 | #}
|
---|
101 | return $program_exe;
|
---|
102 | }
|
---|
103 | ## get_tdb_executable(string) => string ##
|
---|
104 |
|
---|
105 | ## @function
|
---|
106 | #
|
---|
107 | sub get_infodb_file_path
|
---|
108 | {
|
---|
109 | my $self = shift(@_);
|
---|
110 | my $collection_name = shift(@_);
|
---|
111 | my $infodb_directory_path = shift(@_);
|
---|
112 | # my $perform_firsttime_initialization = shift(@_);
|
---|
113 | my $hostname = shift(@_);
|
---|
114 | # if (!defined $perform_firsttime_initialization) {
|
---|
115 | # $perform_firsttime_initialization = 0;
|
---|
116 | # }
|
---|
117 | if (!defined $hostname) {
|
---|
118 | $hostname = `hostname -s`;
|
---|
119 | $hostname =~ s/^\s*|\s*$//gi;
|
---|
120 | # Special case: look up the head node (top of list) from mpi.conf and do
|
---|
121 | # not add suffix if a match
|
---|
122 | if ($hostname eq $self->{'headnode'}) {
|
---|
123 | $hostname = '';
|
---|
124 | }
|
---|
125 | }
|
---|
126 | my $infodb_file_extension = $self->{'default_file_extension'};
|
---|
127 | $self->debugPrint('DBDrivers::TDBCLUSTER::get_infodb_file_path("' . $collection_name . '","' . $infodb_directory_path . '","' . $hostname . '")' . "\n");
|
---|
128 | if ($hostname ne '') {
|
---|
129 | $infodb_file_extension = '.' . $hostname . '.' . $infodb_file_extension;
|
---|
130 | }
|
---|
131 | my $infodb_file_name = &util::get_dirsep_tail($collection_name) . $infodb_file_extension;
|
---|
132 | my $path = &util::filename_cat($infodb_directory_path, $infodb_file_name);
|
---|
133 | ###rint STDERR ' => ' . $path . "\n";
|
---|
134 | return $path;
|
---|
135 | }
|
---|
136 | ## get_infodb_file_path() => string ##
|
---|
137 |
|
---|
138 |
|
---|
139 | ## @function mergeDatabases(string, string) => integer
|
---|
140 | #
|
---|
141 | sub mergeDatabases
|
---|
142 | {
|
---|
143 | my $self = shift(@_);
|
---|
144 | my $source_infodb_file_path = shift(@_);
|
---|
145 | my $target_infodb_file_path = shift(@_);
|
---|
146 | # path specific filenames
|
---|
147 | my $tdb2txt_exe = &FileUtils::filenameConcatenate($self->{'executable_path'}, $self->{'read_executable'} . &util::get_os_exe());
|
---|
148 | my $txt2tdb_exe = &FileUtils::filenameConcatenate($self->{'executable_path'}, $self->{'write_executable'} . &util::get_os_exe());
|
---|
149 | my $cmd = $tdb2txt_exe . ' "' . $source_infodb_file_path . '" | ' . $txt2tdb_exe . ' -append "' . $target_infodb_file_path . '"';
|
---|
150 | ###rint STDERR "[DEBUG] cmd: " . $cmd . "\n";
|
---|
151 | my $status = system($cmd);
|
---|
152 | ###rint STDERR "[DEBUG] status: $status\n";
|
---|
153 | if ($status == 0) {
|
---|
154 | &FileUtils::removeFiles($source_infodb_file_path);
|
---|
155 | }
|
---|
156 | return $status;
|
---|
157 | }
|
---|
158 | ## mergeDatabases(string, string) => integer ##
|
---|
159 |
|
---|
160 |
|
---|
161 | 1;
|
---|