1#!/usr/bin/perl
2
3my $test_name     = $ARGV[0] || './t/flags.t';
4my $topology_name = $ARGV[1] || 'simple';
5my $protocol_name = $ARGV[2] || 'ascii';
6my $hashlib_name  = $ARGV[3] || 'libvbucket';
7
8print "moxi_one.pl: " . $test_name . " " .
9                        $topology_name . " " .
10                        $protocol_name . " " .
11                        $hashlib_name . "\n";
12
13my $prefix = <<'PREFIX';
14
15use strict;
16use FindBin qw($Bin);
17use lib "$Bin/lib";
18use MemcachedTest;
19
20*new_memcached_orig = *new_memcached;
21
22use IO::Socket::INET;
23use IO::Socket::UNIX;
24use Exporter 'import';
25use Carp qw(croak);
26use vars qw(@EXPORT);
27
28use Cwd;
29my $builddir = getcwd;
30
31sub new_memcached_proxy {
32    my ($args, $passed_port) = @_;
33    my $port = $passed_port || free_port();
34
35    TOPOLOGY
36
37    print("new moxi $args\n");
38
39    my $udpport = free_port("udp");
40    if (supports_udp()) {
41        $args .= " -U $udpport";
42    }
43    if ($< == 0) {
44        $args .= " -u root";
45    }
46    my $childpid = fork();
47
48    my $exe = "$builddir/moxi";
49    croak("moxi binary doesn't exist.  Haven't run 'make' ?\n") unless -e $exe;
50    croak("moxi binary not executable\n") unless -x _;
51
52    unless ($childpid) {
53        setpgrp();
54        exec "$exe $args";
55        exit; # never gets here.
56    }
57    setpgrp $childpid, $childpid;
58
59    # unix domain sockets
60    if ($args =~ /-s (\S+)/) {
61        sleep 1;
62	my $filename = $1;
63	my $conn = IO::Socket::UNIX->new(Peer => $filename) ||
64	    croak("Failed to connect to unix domain socket: $! '$filename'");
65
66	return Memcached::Handle->new(pid  => -$childpid,
67				      conn => $conn,
68				      domainsocket => $filename,
69				      port => $port);
70    }
71
72    # try to connect / find open port, only if we're not using unix domain
73    # sockets
74
75    for (1..20) {
76	my $conn = IO::Socket::INET->new(PeerAddr => "127.0.0.1:$port");
77	if ($conn) {
78	    return Memcached::Handle->new(pid  => -$childpid,
79					  conn => $conn,
80					  udpport => $udpport,
81					  port => $port);
82	}
83	select undef, undef, undef, 0.10;
84    }
85    croak("Failed to startup/connect to moxi server.");
86}
87
88sub supports_udp {
89    my $output = `$builddir/moxi -h`;
90    return 0 if $output =~ /^memcached 1\.1\./;
91    return 1;
92}
93
94*new_memcached = *new_memcached_proxy;
95
96PREFIX
97
98# ------------------------------------------------------
99
100my $simple_topology_libmemcached = <<'SIMPLE_TOPOLOGY';
101    my $portA = free_port();
102    my $portC = $portA;
103    my $topology =
104      " -z \"".
105        "$port=".
106          "localhost:$portA\"".
107      " -p $portC";
108    $args .= $topology;
109SIMPLE_TOPOLOGY
110
111my $simple_topology_libvbucket = <<'SIMPLE_TOPOLOGY';
112    my $portA = free_port();
113    my $portC = $portA;
114    my $topology =
115      " -z \'".
116       "$port={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
117              "\"serverList\":[\"127.0.0.1:$portA\"],".
118              "\"vBucketMap\":[[0]]}\"\'".
119      " -p $portC";
120    $args .= $topology;
121SIMPLE_TOPOLOGY
122
123# ------------------------------------------------------
124
125my $chain_topology_libmemcached = <<'CHAIN_TOPOLOGY';
126    my $portA0 = free_port();
127    my $portA1 = free_port();
128    my $portA2 = free_port();
129    my $portA3 = free_port();
130    my $portA4 = free_port();
131    my $portC = $portA4;
132    my $topology =
133      " -z \"".
134        "$port=".
135          "localhost:$portA0;".
136        "$portA0=".
137          "localhost:$portA1;".
138        "$portA1=".
139          "localhost:$portA2;".
140        "$portA2=".
141          "localhost:$portA3;".
142        "$portA3=".
143          "localhost:$portA4\"".
144      " -p $portC";
145    $args .= $topology;
146CHAIN_TOPOLOGY
147
148my $chain_topology_libvbucket = <<'CHAIN_TOPOLOGY';
149    my $portA0 = free_port();
150    my $portA1 = free_port();
151    my $portA2 = free_port();
152    my $portA3 = free_port();
153    my $portA4 = free_port();
154    my $portC = $portA4;
155    my $topology =
156      " -z \'".
157       "$port={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
158              "\"serverList\":[\"127.0.0.1:$portA0\"],".
159              "\"vBucketMap\":[[0]]};".
160       "$portA0={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
161              "\"serverList\":[\"127.0.0.1:$portA1\"],".
162              "\"vBucketMap\":[[0]]};".
163       "$portA1={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
164              "\"serverList\":[\"127.0.0.1:$portA2\"],".
165              "\"vBucketMap\":[[0]]};".
166       "$portA2={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
167              "\"serverList\":[\"127.0.0.1:$portA3\"],".
168              "\"vBucketMap\":[[0]]};".
169       "$portA3={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
170              "\"serverList\":[\"127.0.0.1:$portA4\"],".
171              "\"vBucketMap\":[[0]]}\'".
172      " -p $portC";
173    $args .= $topology;
174CHAIN_TOPOLOGY
175
176# ------------------------------------------------------
177
178my $fanout_topology_libmemcached = <<'FANOUT_TOPOLOGY';
179    my $portA = free_port();
180    my $portC = $portA;
181    my $topology =
182      " -z \"".
183        "$port=".
184          "localhost:$portA,".
185          "localhost:$portA,".
186          "localhost:$portA,".
187          "localhost:$portA\"".
188      " -p $portC";
189    $args .= $topology;
190FANOUT_TOPOLOGY
191
192my $fanout_topology_libvbucket = <<'FANOUT_TOPOLOGY';
193    my $portA = free_port();
194    my $portC = $portA;
195    my $topology =
196      " -z \'".
197       "$port={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
198              "\"serverList\":[\"127.0.0.1:$portA\",\"127.0.0.1:$portA\",\"127.0.0.1:$portA\",\"127.0.0.1:$portA\"],".
199              "\"vBucketMap\":[[0],[1],[2],[3]]}\'".
200      " -p $portC";
201    $args .= $topology;
202FANOUT_TOPOLOGY
203
204# ------------------------------------------------------
205
206my $fanoutin_topology_libmemcached = <<'FANOUTIN_TOPOLOGY';
207    my $portA = free_port();
208    my $portB = free_port();
209    my $portC = $portB;
210    my $topology =
211      " -z \"".
212        "$port=".
213          "localhost:$portA,".
214          "localhost:$portA,".
215          "localhost:$portA,".
216          "localhost:$portA;".
217        "$portA=".
218          "localhost:$portB\"".
219      " -p $portC";
220    $args .= $topology;
221FANOUTIN_TOPOLOGY
222
223my $fanoutin_topology_libvbucket = <<'FANOUTIN_TOPOLOGY';
224    my $portA = free_port();
225    my $portB = free_port();
226    my $portC = $portB;
227    my $topology =
228      " -z \'".
229       "$port={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
230              "\"serverList\":[\"127.0.0.1:$portA\",\"127.0.0.1:$portA\",\"127.0.0.1:$portA\",\"127.0.0.1:$portA\"],".
231              "\"vBucketMap\":[[0],[1],[2],[3]]};".
232       "$portA={\"hashAlgorithm\": \"CRC\",\"numReplicas\": 0,".
233              "\"serverList\":[\"127.0.0.1:$portB\"],".
234              "\"vBucketMap\":[[0]]}\'".
235      " -p $portC";
236    $args .= $topology;
237FANOUTIN_TOPOLOGY
238
239# ------------------------------------------------------
240
241my %topology_map_libmemcached = (
242    'simple' => $simple_topology_libmemcached,
243    'chain' => $chain_topology_libmemcached,
244    'fanout' => $fanout_topology_libmemcached,
245    'fanoutin' => $fanoutin_topology_libmemcached
246);
247
248my %topology_map_libvbucket = (
249    'simple' => $simple_topology_libvbucket,
250    'chain' => $chain_topology_libvbucket,
251    'fanout' => $fanout_topology_libvbucket,
252    'fanoutin' => $fanoutin_topology_libvbucket,
253);
254
255# ------------------------------------------------------
256
257my $topology = $topology_map_libvbucket{$topology_name};
258
259if ($hashlib_name eq 'libmemcached') {
260    $topology = $topology_map_libmemcached{$topology_name};
261}
262
263# ------------------------------------------------------
264
265$topology .= ("\$args .= \" -Z downstream_protocol=$protocol_name," .
266              "downstream_max=1,downstream_conn_max=0\";");
267
268# Tack on ./t/ directory prefix if needed.
269if ($test_name !~ /^\.\/t/) {
270  $test_name = "./t/$test_name";
271}
272
273# Tack on .t filename suffix if needed.
274if ($test_name !~ /\.t$/) {
275  $test_name = "$test_name.t";
276}
277
278$prefix =~ s/TOPOLOGY/{$topology }/g;
279
280eval($prefix . `cat $test_name`);
281
282print($@);
283