Go to content Go to navigation Go to search

MySQL Proxy Query Profiling

December 7th, 2007 by eric

Since I am now finally getting to play with MySQL Proxy, I am going to outline some recipes here that I have found/created/modified that may be useful to someone other than me. This is a recipe for profiling queries. It writes the information to the PROXY_LOG_FILE currently name mysql.log. It is a file that will be created in the directory that you run mysql-proxy from. The file itself is mostly commented and should therefore be pretty self-explanatory. It was adapted from the reference documentation listed at the bottom of this entry.

assert(proxy.PROXY_VERSION >= 0x00600,
  "You need to be running mysql-proxy 0.6.0 or greater")

 -- Set up the log file
 local log_file = os.getenv("PROXY_LOG_FILE")
 if (log_file == nil) then
    log_file = "mysql.log"
 end

 -- Open up our log file in append mode
 local fh = io.open(log_file, "a+")

 -- Set some variables
 local original_query = ""
 local executed_query = ""
 local replace = false
 local comment = ""

 -- For profilign
 local profile = 0

-- Push the query onto the Queue
function read_query( packet )
  if string.byte(packet) == proxy.COM_QUERY then
    query = string.sub(packet, 2)

    -- Pull out the comment and store it
    original_query = string.gsub(query, "%s*%*%*%*%s(.+)%s%*%*%*%s*",'')
    comment = string.match(query, "%s*%*%*%*%s(.+)%s%*%*%*%s*")

    -- Add the original packet to the query if we have a comment
    if (comment) then
        if string.match(string.upper(comment), '%s*PROFILE') then
          -- Profile types:
          --   ALL, BLOCK IO, CONTEXT SWITCHES, IPC,
          --        MEMORY, PAGE FAULTS, SOURCE, SWAPS

          -- Set it up for profiling
          -- Generate a new COM_QUERY packet
          --   and inject it with a new id (11)
          original_query = "SET PROFILING=1; " .. original_query
      end -- End if (PROFILE)
    end -- End if (comment)

    executed_query = original_query
    -- Check for a 'SELECT' typo
    if string.match(string.upper(original_query), '^%s*SLECT') then
        executed_query = string.gsub(original_query,'^%s*%w+', 'SELECT')
        replace = true;
    -- matches "CD" as first word of the query
    elseif string.match(string.upper(original_query), '^%s*CD') then
        executed_query = string.gsub(original_query,'^%s*%w+', 'USE')
        replace = true
    end

    -- Postpend the other profiling strings to the query
    if (comment and string.match(string.upper(comment), '%s*PROFILE')) then
        executed_query = executed_query .. "; SHOW " .. comment
    end

    -- Actually execute the query here
    proxy.queries:append(1, string.char(proxy.COM_QUERY) .. executed_query )
    return proxy.PROXY_SEND_QUERY
  else
    executed_query = ""
  end
end

function read_query_result (inj)
  local res = assert(inj.resultset)
  local num_cols = string.byte(res.raw, 1)
  if num_cols > 0 and num_cols < 255 then
     for row in inj.resultset.rows do
         row_count = row_count + 1
     end
  end

  -- Prepend the error tag in the log
  local error_status = ""
  if res.query_status and (res.query_status < 0) then
     error_status = "[ERROR]"
  end

  -- Gets the rows affected by the actual query
  local row_count = 0
  if (res.affected_rows) then
     row_count = res.affected_rows
  end

  -- Prepend the comment line in the log
  if (comment) then
     fh:write( string.format("%s %6d -- [COMMENT] %s\n",
        os.date('%Y-%m-%d %H:%M:%S'),
        proxy.connection.server["thread_id"],
        comment))
  end

  -- Prepend the typo in the log
  if (replace) then
     fh:write( string.format("%s %6d -- [REPLACEMENT] %s\n\t\t\t%s\n",
        os.date('%Y-%m-%d %H:%M:%S'),
        proxy.connection.server["thread_id"],
        ("replaced " .. original_query),
        ("with " .. executed_query)))
  end

  -- Write the query adding the number of rows retrieved and query time
  fh:write( string.format("%s %6d -- %s %s {%d rows} {%d ms}\n",
     os.date('%Y-%m-%d %H:%M:%S'),
     proxy.connection.server["thread_id"],
     error_status,
     executed_query,
     row_count,
     inj.query_time)
  )
  fh:flush()
end

To make this work, simply append 3 asterisks ‘PROFILE <profile_type>’ and then 3 more asterisks and you will have the profile information returned to you in your query:
*** PROFILE ALL *** SELECT * FROM foo_bar;
2 tables will be returned. Your results and then the profile of your results.

Reference: Writing LUA Scripts for MySQL Proxy

Powered by Gregarious (37)

Text Messages to Cell Phones via Email

December 3rd, 2007 by eric

I have been compiling a list of the domains that one needs in order to send text messages to cell phones via email. As a huge user of Nagios, this is how I keep myself aware of the status changes. Below I have listed the carriers that I use most frequently. If you have any others to list here to make this more complete, please add a comment and I will add it to the list.

I have seen other instances of this before, but some are outdated. These are the newest ones that I have come across.

The assumption here is that the telephone number of the person that you are trying to text message is 2225551212. Just make sure that there is nothing in between the numbers (like a ‘.’ or a ‘-’), Also make sure that you don’t put the ‘1′ before the phone number.

  • ATT: 2225551212@txt.att.net
  • Verizon: 2225551212@vtext.com
  • T-Mobile: 2225551212@tmomail.net
  • Alltell: 2225551212@message.alltel.com
  • Virgin Mobile:2225551212@vmobl.com
  • Sprint: 2225551212@messaging.sprintpcs.com
  • Nextel: 2225551212@messaging.nextel.com
  • All Other: 2225551212@teleflip.com

It should be noted that the last item (Teleflip), can be used either in place of any of these or as a fall through. It seems to act as a universal text message system.

UPDATES:
Here are the contributed addresses. The thanks are in parentheses following the numbers:

  • Claro (Brazil): 2225551212@clarotorpedo.com.br (Rodrigo)
Powered by Gregarious (37)

Cloning a Virtual Machine in VMWare VI3 without Virtual Server

November 5th, 2007 by eric

I, like many other people working in a small company, have to fix problems and come up with solutions with cost at the forefront. I had to make many virtual machines appear from nowhere to create an environment in virtually no time at all. Since all I had was VMWare Server (for Linux), I started there. When I realized that those didn’t translate to ESX, I had to come up with another solution. I created a single template guest OS (of Gentoo 2006.1 which is our primary server OS here) and decided to clone that. How did I do it…well, I am glad you asked.

The key here was to figure out what the VI3 (Virtual Infrastructure 3) client did and mimic it. In order to figure this out, I copied the entire /etc directory to a place where I could later diff it. I created 3 VM (virtual machines) with nothing on them to discern the patterns that the client made in its files. I then diff’d the 2 version of the /etc directory and now I knew the main changes that had to be made. It also should be noted that the Temple VM should be powered off before creating the Clone VM.

I also kept a pristine copy of the template VM so I would always have something to copy from when creating a new VM. For the sake of argument, let’s go with the following names and terminology so we can all stay on the same page. The template VM is going to be named Template. The cloned VM is going to be named Clone. I am going to assume that the template VM that you are using is already fully created, configured, and installed. I am also assuming that you either have console or SSH access to the host since you will need to have access to the commands on the computer itself.

The first step is to copy the template directory. My volume is named Array1, so the command looks like this (Note: I add the & to put the command in the background since it takes a while):

[root@vm1 ~]# cp -arp /vmfs/volumes/Array1/Template /vmfs/volumes/Array1/Clone &

Now its time to get started on the file editing. The first group of files we have to mess with are in the /etc/vmware/hostd/.

vmInventory.xml:
Assuming the only virtual machines you have are going to be Template and his buddy Clone, the following is what your vmInventory.xml should look like:

<ConfigRoot>
  <ConfigEntry id="0001">
    <objID>32</objID>
    <vmxCfgPath>/vmfs/volumes/4725ae82-4e276b80-4c76-001c23c38d80/Template/Template.vmx</vmxCfgPath>
  </ConfigEntry>
  <ConfigEntry id="0002">
    <objID>48</objID>
    <vmxCfgPath>/vmfs/volumes/4725ae82-4e276b80-4c76-001c23c38d80/Clone/Clone.vmx</vmxCfgPath>
  </ConfigEntry>
</ConfigRoot>

The 3 items that you have to note here are:

  1. id: This is a 4 digit zero-padded number going up in increments of 1
  2. objID: This is a number going up in increments of 16
  3. vmxCfgPath: Here you need to ensure that you have the proper hard path (not sym-linked)

pools.xml:
Using the same assumption as before, the only 2 VMs are Template and Clone

<ConfigRoot>
  <resourcePool id="0000">
    <name>Resources</name>
    <objID>ha-root-pool</objID>
    <path>host/user</path>
  </resourcePool>
  <vm id="0001">
    <lastModified>2007-10-30T16:23:57.618151Z</lastModified>
    <objID>32</objID>
    <resourcePool>ha-root-pool</resourcePool>
    <shares>
      <cpu>normal</cpu>
      <mem>normal</mem>
    </shares>
  </vm>
  <vm id="0002">
    <lastModified>2007-10-30T16:23:57.618151Z</lastModified>
    <objID>48</objID>
    <resourcePool>ha-root-pool</resourcePool>
    <shares>
      <cpu>normal</cpu>
      <mem>normal</mem>
    </shares>
  </vm>
</ConfigRoot>

The 3 items that you have to note here are:

  1. id: This is a 4 digit zero-padded number going up in increments of 1 (and it must match the id from vmInventory.xml
  2. objID: This is a number going up in increments of 16 (and it must match the id from vmInventory.xml
  3. The lastModified item here doesn’t matter as it will be changed when you make a change to VM anyway.

By now, the Template directory should be finished copying itself over to the directory that we will be using as our clone. First thing we have to do is rename all the files in the directory to mimic the name of our VM.

  # mv Template-flat.vmdk Clone-flat.vmdk
  # mv Template.nvram Clone.nvram
  # mv Template.vmdk Clone.vmdk
  # mv Template.vmx Clone.vmx
  # mv Template.vmxf Clone.vmxf

Now we just need to edit some files and we are ready to go. First let’s edit the Template.vmdk file. You need to change the line that reads something similar to (the difference will be in the size of your extents):

# Extent description
RW 20971520 VMFS "Template-flat.vmdk"

to look like:

# Extent description
RW 20971520 VMFS "Clone-flat.vmdk"

Save and exit this file. The next file is Template.vmx. The key here is to change every instance of the word Template to Clone. There should be 4 instances:

  1. nvram
  2. displayName
  3. extendedConfigFile
  4. scsi0:0.fileName

Don’t forget to change the MAC address(es). Their variable name(s) should be something like ethernet0.generateAddress. Delete the line that has the variable title sched.swap.derivedName. It will be regenerated and added to the config file. Lastly, add the following line to the end of the file if it doesn’t already exist elsewhere in the file:

uuid.action = "create"

The final item that needs to be done is the one that got me for such a long time. This is the step that will allow your changes to be seen in the client. (Drum roll …..)

Restart the VMWare management console daemon. So simple. Just run the following command:

  # /etc/init.d/mgmt-vmware restart

Note: This will log you out of the client console. But when you log back in, you will have access to the changes that you have made including the clones.

Good luck, and be careful as XML has a tendency to be easier to break than to fix.

Powered by Gregarious (37)

« Previous Entries Next Entries »