1# -*- cperl -*-
2# Copyright (c) 2006, 2008 MySQL AB, 2009 Sun Microsystems, Inc.
3# Use is subject to license terms.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License, version 2.0,
7# as published by the Free Software Foundation.
8#
9# This program is also distributed with certain software (including
10# but not limited to OpenSSL) that is licensed under separate terms,
11# as designated in a particular file or component or in included license
12# documentation.  The authors of MySQL hereby grant you an additional
13# permission to link the program and your derivative works with the
14# separately licensed software that they have included with MySQL.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License, version 2.0, for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24
25package mtr_unique;
26
27use strict;
28use Fcntl ':flock';
29
30use base qw(Exporter);
31our @EXPORT= qw(mtr_get_unique_id mtr_release_unique_id);
32
33use My::Platform;
34
35sub msg {
36 # print "### unique($$) - ", join(" ", @_), "\n";
37}
38
39my $dir;
40
41if(!IS_WINDOWS)
42{
43  $dir= "/tmp/mysql-unique-ids";
44}
45else
46{
47  # Try to use machine-wide directory location for unique IDs,
48  # $ALLUSERSPROFILE . IF it is not available, fallback to $TEMP
49  # which is typically a per-user temporary directory
50  if (exists $ENV{'ALLUSERSPROFILE'} && -w $ENV{'ALLUSERSPROFILE'})
51  {
52    $dir= $ENV{'ALLUSERSPROFILE'}."/mysql-unique-ids";
53  }
54  else
55  {
56    $dir= $ENV{'TEMP'}."/mysql-unique-ids";
57  }
58}
59
60my $mtr_unique_fh = undef;
61
62END
63{
64  mtr_release_unique_id();
65}
66
67#
68# Get a unique, numerical ID in a specified range.
69#
70# If no unique ID within the specified parameters can be
71# obtained, return undef.
72#
73sub mtr_get_unique_id($$) {
74  my ($min, $max)= @_;;
75
76  msg("get $min-$max, $$");
77
78  die "Can only get one unique id per process!" if defined $mtr_unique_fh;
79
80
81  # Make sure our ID directory exists
82  if (! -d $dir)
83  {
84    # If there is a file with the reserved
85    # directory name, just delete the file.
86    if (-e $dir)
87    {
88      unlink($dir);
89    }
90
91    mkdir $dir;
92    chmod 0777, $dir;
93
94    if(! -d $dir)
95    {
96      die "can't make directory $dir";
97    }
98  }
99
100
101  my $fh;
102  for(my $id = $min; $id <= $max; $id++)
103  {
104    open( $fh, ">$dir/$id");
105    chmod 0666, "$dir/$id";
106    # Try to lock the file exclusively. If lock succeeds, we're done.
107    if (flock($fh, LOCK_EX|LOCK_NB))
108    {
109      # Store file handle - we would need it to release the ID (==unlock the file)
110      $mtr_unique_fh = $fh;
111      return $id;
112    }
113    else
114    {
115      close $fh;
116    }
117  }
118  return undef;
119}
120
121
122#
123# Release a unique ID.
124#
125sub mtr_release_unique_id()
126{
127  msg("release $$");
128  if (defined $mtr_unique_fh)
129  {
130    close $mtr_unique_fh;
131    $mtr_unique_fh = undef;
132  }
133}
134
135
1361;
137
138