Automating Open and closing databases on Windows

It’s been 3 months since I’ve bleated about quickly closing FileMaker files on FileMaker Server using a script, and nearly a year since I mentioned a windows version
so here’s some more.

A colleague (let’s call him Midds) at a client took my previous .cmd file to stop FileMaker Server and made some neat modifications:

He modified the script to run on Windows start up and shut down automatically.

The script creates little “flag” files to indicate whether to start up or shut down and uses (good?) old fashioned goto statements (it has been years since I’ve used those, but you don’t have many tools in batch files!).

It has been fantastically successful starting and stopping their FileMaker Server (which sits on a very large array of virtual machines), leading to a very hands off approach from admin.

Here is a version of the .cmd that will automatically start and stop the Athenaeum Pro files. There is plenty of documentation on Microsoft’s web site how to configure Windows to run a .cmd file on startup and shutdown.

Don’t forget to replace your FileMaker Server admin account and password.

@echo off

rem Modded by Midds

rem check if startfms.flg file exists and if so start fms
rem otherwise write stopfms.flg file write a log file and then continue

if exist C:\startfms.flg goto startfms
echo > C:\stopfms.flg
echo stop-start %username% %date% %time% >> C:\athprofmp.log

rem set variables
set myaccount=FMSADMINACCOUNT
set mypassword=FMSADMINPASSWORD

rem change to the filemaker server directory where the command fmsadmin lives

chdir "C:\Program Files (x86)\FileMaker\FileMaker Server\Database Server"

rem force disconnect all clients

fmsadmin disconnect client -yf -u%myaccount% -p%mypassword%

fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_AthenaeumPro.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_barcode.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_borrower.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_catalog.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_catalogarchive.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_catalogSupport.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_circulation.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_circulationarchive.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_MARC.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_photo.fp7" -yf -u%myaccount% -p%mypassword%
fmsadmin close file "filewin:/C:/Program Files (x86)/FileMaker/FileMaker Server/Data/Databases/ap_web.fp7" -yf -u%myaccount% -p%mypassword%

fmsadmin stop server -yf -u%myaccount% -p%mypassword%

rem delete stopfms.flg file on success and write startfms.flg file append log file and then exit

del /f /q C:\stopfms.flg
echo stop-end %username% %date% %time% >> C:\athprofmp.log
echo > C:\startfms.flg
echo start-start %username% %date% %time% >> C:\athprofmp.log
goto EOF

rem start fms delete startfms.flg file and then append log file

:startfms
chdir "C:\Program Files (x86)\FileMaker\FileMaker Server\Database Server"
fmsadmin start server
fmsadmin start wpc
fmsadmin start cwp
del /f /q C:\startfms.flg
echo start-end %username% %date% %time% >> C:\athprofmp.log

:EOF
exit

Colour Commenting

A wish of mine is that ScriptMaker™ will get an overhaul and include syntax colouring, amongst many other improvements. That’s a pretty common wish, I think, amongst the FileMaker developer base.

For the last few days, I’ve been working on a few complex scripts that get quite long. Whether juggling long rambling scripts or lots of shorter scripts and maintaining parameters or global variables (some still say globals are the work of the devil), syntax colouring would definitely help with these beasts, hopefully making it easier to identify exit points, variables, etc..

I was cleaning up some comments (I do that sort of thing!) and my mind wandered about how to make them stand out in a different way, particularly parts of the code that I want to come back and decode. I’ve never liked the way comments are bold black and script steps are plain black. Most development environments seem to have comments in grey text as a default setting.

Here’s a FileMaker script with some comments embedded.

Blah

The comments don’t really stand out, or, they stand out the wrong way (I want to look at the code, not always the comments).

To improve that slightly, we can put blank comment lines in and indent the comment text with tabs or spaces to move them away from that cluttered left margin (which is my modus operandi):

Less blah

Obviously this takes up more vertical space, but it’s a lot clearer, I think.

You can also stuff comments in to all sorts of places in script step. Anything that has a specify calculation component can handle a comment wrapped in /* */ or at the end of a line following a //. Try it, there are heaps of places.

But still, no colour syntax.

I did stumble onto something a tiny bit special. Emoji! Mac OS X’s Emoji font is in colour. And guess what, it works!

Blinged

Even though the effect is limited, you can obviously go too far with your symbols.

Methinks judicious use of the bug and flag symbols and maybe the construction symbol might be useful.

Favourites

Alas, the feature doesn’t work on Windows, which is a shame. Never mind!

Win nonbling

File renaming bug in the Developer Utilities

I was working on a very old solution of a client recently. This started life before FileMaker 3 and has been converted through many versions.

Finally, I had been tasked with updating an important part of the solution (though currently still on FileMaker 11) and I was using the developer tools of FileMaker Pro Advanced to rename the files for a test run. I simply prefixed the file names with “test_” and let the developer tool do the file renaming and update the internal file references.

When I opened the solution, the renamed solution couldn’t find one of the files, yet I could see the file in amongst the others.

I had forgotten about a long standing bug where the developer tool won’t successfully rename files and references if the CASE of the file names don’t match.

File renaming bug

Not a biggie, easily fixed. Hopefully, this might help anyone else who performs this task from time to time.

You FileMaker developers should code in other environments

FileMaker is one of those tools that introduces many people to computer development. Some of those people even make new careers on their new found skills.

I think FileMaker developers should code in as many environments as possible. Certainly the professional developers.

  • It build your coding skills because you will have to think differently than when you are coding with FileMaker.
  • It will help you deal with diverse production environments and help you rely less on others.
  • It will give you ideas for things you would like to see in future versions of FileMaker.

But mostly, it should make you realise how much FileMaker does for you as the developer.

That last point is very easy to forget, when you have your head buried in the environment for hours each day. FileMaker is not perfect, but when you stand back and look at what it is trying to achieve, it’s a pretty good view. Sometimes, I’m just astonished at what some managers, “knowledge workers” if you will, and experts in fields quite far removed from computing succeed in achieving.

Just saying!

Update to Mac shell script to close FileMaker Server files quickly

I’ve banged on about shell scripts to manage FileMaker Server before: OS X Shell Script to close all FileMaker Server files.

With the recent kerfuffle around Java and updates continuing to break the FileMaker Server Admin Console (geez I’m getting sick of this shit…someone aught to line up the java team against a wall and give them a jolly good talking to), mastering the command line is getting even more useful.

So while I was eating my own dog food late last year, I ran into a client’s files where their FileMaker file names had spaces in them which would cause certain versions of the shell script to fall over.

The solution was to adjust the fmsadmin close step to not refer to the files by name and have to worry about ‘escaping’ the spaces, but simply refer to the file by ID.

If you read the help page for the fmsadmin close command, you see this:

Usage: fmsadmin CLOSE [FILE...] [PATH...] [options]

Description:
    Closes the specified databases (FILE) or all the hosted databases in the
    specified folders (PATH). If no FILE or PATH is specified, closes all 
    hosted databases. 

    To specify a database by its ID rather than its filename, first use the 
    LIST FILES -s command to get a list of databases and their IDs.

So that looks pretty easy.

Here is a sample of the standard listing from fmsadmin list files:

filemac:/Ararimu/Library/FileMaker Server/Data/Databases/pro2012/ap_AthenaeumPro.fmp12
filemac:/Ararimu/Library/FileMaker Server/Data/Databases/pro2012/ap_MARC.fmp12
filemac:/Ararimu/Library/FileMaker Server/Data/Databases/pro2012/ap_barcode.fmp12
filemac:/Ararimu/Library/FileMaker Server/Data/Databases/pro2012/ap_borrower.fmp12

And the same listing from fmsadmin list files -s:

8  ap_AthenaeumPro       0       16015360 Normal fmiwp fmapp fmxml fmphp fmreauthenticate0                             
9  ap_MARC               0       1396736  Normal *fmapp fmreauthenticate0                                              
10 ap_barcode            0       1626112  Normal *fmapp fmreauthenticate0                                              
11 ap_borrower           0       4182016  Normal *fmiwp *fmapp fmxml fmphp fmreauthenticate0

Columns 1 to 3 contain the ID, so we can use the “cut” command to extract that from the listing. The “Normal” attributes means the file is open for business, so we can use grep while we are at it to filter only the open files. If you do have closed or paused files, the output might look like this:

8  ap_AthenaeumPro       0       16015360 Normal fmiwp fmapp fmxml fmphp fmreauthenticate0                             
9  ap_MARC               0       1396736  Paused *fmapp fmreauthenticate0                                              
10 ap_barcode            0       1626112  Closed -                                                                     
11 ap_borrower           0       4182016  Normal *fmiwp *fmapp fmxml fmphp fmreauthenticate0

Now combining IDs with the force disconnect option I described in Stopping a Server with a Batch File and only operating on the open files, the new shell script for Mac looks like this:

#!/bin/bash

# 2008,2012 Rob Russell SumWare Consulting      http://www.sumware.net/

# grab the user name and password from the command line
myuser=$1
mypassword=$2

# disconnect clients with force
fmsadmin disconnect client -yf -u$myuser -p$mypassword

# loop through the OPEN files and close each one
fmsadmin list files -su$myuser -p$mypassword  | grep "Normal" | cut -c 1-3 | while read line 
    do echo $line ; fmsadmin close $line -yu$myuser -p$mypassword
done

fmsadmin stop server -yf -u$myuser -p$mypassword

Save the script with a file name like fmsclosenow.sh, ensure the file has the appropriate execute attribute and trigger the script from the command line like this:

./fmsclosenow.sh user password

where user is an administration account on your FileMaker Server and password is the password for that account.

Easy!

Imagine if positional information was positional

I use the Info palette to precisely place and size layout objects frequently.

Original info palette

Despite having used this for just about as long as it has been in FileMaker (20 something years), I still get the order of the boundary positions wrong.

The order doesn’t match the left to right reading order of English nor are the positions of the positions…errr…positional.

I wonder if this would work better:

Proposed info palette

A small thing, I think the numbers should be right aligned, too!

Conditional buttons in 12

A neat feature of FileMaker 12 is using images to indicate boolean states. You could do this with FileMaker 11 and earlier, though this usually required a couple of fields and possibly a relationship or two. I think the FileMaker 12 way is much slicker.

Say you have a number field that only stores boolean values called “flag”.

Place a button on your layout and size it the way you want.

Create, buy or beg for a lightweight graphic indicating your “flagged” status and set the Normal and Hover states for that button to the image.

Image fill normal state

Because you are using the same image for both states, FileMaker only stores it once in the database.

The trick is to set conditional formatting for the button so the image disappears when the desired condition is set. e.g. if the field value is false (zero).

Conditional format clear fill

Do this by adding your conditional format rule where the fill colour is empty (the first box in the colour picker).

Finally, set the button so that it toggles the value of your boolean field.

That’s it.

Download the zipped sample file.

GetValue ( myData ; really? )

Optimising Expectations

Recently, I rewrote an old script that processes large files to gain speed. At least, that was my intent.

This was a very old script written in the pre-FileMaker 6 days and it had chugged along nicely for all of those years.

One would think that the obvious way to speed this up would be heavy use of variables (which didn’t exist back then) and chomp the data in memory and avoid writing data to fields opening and closing records and the like.

I had a great test file with just shy of 1 million lines of text to process. Given that computers have bucket loads of memory these days, the plan was to load the entire file into a variable (using any of the numerous plugins that do this kind of thing…or in FileMaker 12, of course you can use the Insert URL using the “file:/” protocol) and mash away.

I wrote my script, tested on a small file with 50,000 lines and the script zipped along very nicely indeed. I was very happy with the speed increase and so I loaded up the big file and waited.

Then I waited a bit more.

Then a lot more. I let it run for about an hour or so but I was getting impatient. Based on the first 50,000 line which took less than two minutes, I expected that a file 20 times larger should not take more than 40 minutes. Especially on this quad-core, maxed out with RAM, SSD based firestorming computer that I use (OK, it’s just quick).

Pausing the script with Script Debugger showed that it was barely a quarter of the way through the file.

Time to examine the script for the bottleneck.

Here is the basis of the looping portion of the script.

#                     load the file into a variable
Set Variable [ $file; Value:idma_File_Read( $path ; 0 ; $dataLength; "Raw Data" )  // ]
Set Variable [ $linecount; Value:ValueCount ( $file ) ]
Set Variable [ $counter; Value:1 ]
Loop
    Exit Loop If [ $counter > $linecount                 /* exit condition */ ]
    #                  load the appropriate line into a variable
    Set Variable [ $currentline; Value:GetValue ( $file ; $counter ) ]
    #                  do stuff here
    Set Variable [ $counter; Value:$counter + 1 ]
End Loop

Timings

The file load only took a second – despite the large number of lines, it was only 4.5MB. So I compared how long it took to load chunks of 1,000 lines for the first 10,000 lines versus each 1,000 lines over the last 10,000 lines.

(I initially timed many more chunks over the whole file so I could plot them to work out whether the change in performance was linear, logarithmic or just plain weird).

First 10,000 lines

A simple modification of the scripts to include timings which were written to a table and charted looked like this:

Set Variable [ $linecount; Value:ValueCount ( $file ) ]
Set Variable [ $oldtime; Value:GetAsNumber ( Get ( CurrentTime ) ) ]
Set Variable [ $counter; Value:1 ]
Set Variable [ $lastTag; Value:"" ]
Loop
    Exit Loop If [ $counter > $linecount                 /* exit condition */ ]
    If [ not Mod ( $counter ; $increment ) ]
        Set Variable [ $time; Value:GetAsNumber ( Get ( CurrentTime ) ) ]
        Set Variable [ $timing; Value:$timing & Right ( "      " & $counter ; 6 ) & Char ( 9 ) & $time - $oldtime & ¶ // very basic formatting ] 
        Set Variable [ $oldtime; Value:$time ]
    End If
    #                                 
    #                                 is this step the culprit?
    Set Variable [ $currentline; Value:GetValue ( $file ; $counter ) ]
    Set Variable [ $counter; Value:$counter + 1 ]
End Loop
#                                 
#                                 write results
#                                 
Set Variable [ $counter; Value:1 ]
Set Variable [ $maxloops; Value:ValueCount ( $timing ) ]
Loop
    Exit Loop If [ $counter > $maxloops                  /* exit condition */ ]
    New Record/Request
    Set Field [ data::counter; LeftWords ( GetValue ( $timing ; $counter ) ; 1 ) / $increment ]
    Set Field [ data::time taken; RightWords ( GetValue ( $timing ; $counter ) ; 1 ) ]
    Set Variable [ $counter; Value:$counter + 1 ]
End Loop

and the results are shown in this graphic:

First10000

You can see that each 1000 lines of the memory based variable take roughly between 2 and 4 seconds (FileMaker’s timing facility is only accurate to the second).

Last 10,000 lines

Repeating the process for the last 10,000 lines of our sample, by modifying the counters results in a chart like this (sorry for not resetting the y-axis to the same scales on each chart):

Last10000

Woah! What a difference. Each 1,000 line chunk took roughly 3-5 times longer.

Why

The time is taken up with this step:

    Set Variable [ $currentline; Value:GetValue ( $file ; $counter ) ]

or more specifically, with the GetValue function.

Now GetValue is fast in most situations. Have a look at an article on Daniel’s Weetbix (Thinking outside the loop) which shows GetValue to be part of the fastest solution on that web page.

Without seeing the C++ code behind the function, one is left to postulate that each time you call the function, FileMaker starts at the beginning of the string variable and counts the number of ¶ characters until it finds the one before the line you want and then extracts the line.

This makes sense and also would explain why it takes longer, the more data there is to process. My problem was that I was dealing with very large numbers of lines. (In this “mega/terra/peta” age, a million is still a large number to me). If this is linear, then a top of the head calculation results in the last 10,000 lines of a million line file requiring nearly 1,000 seconds… wow!

Back to importing

50000 records

Abandoning the large variable and simply importing the data into a work table (this does require a bit of jiggery pokery for random files like I was using) and testing the speeds again is very revealing.

Last1000 records

It only took 5 seconds to import the 50000 line file into an unindexed table. Modifying the looping test so that this line:

    Set Variable [ $currentline; Value:GetValue ( $file ; $counter ) ]

became

    Go to Record/Request [No dialog; $counter]
    Set Variable [ $currentline; Value:Table:f1 ]

and then re-running the tests on (say) the last 10,000 records showed a chart like this:

Each step took less than half a second (more or less, FileMaker’s time function granularity means this isn’t the way to measure if you want accurate figures). Allowing for the time to import the data, even with pre-processing the file before the import (so each line goes into a single field without tabs and commas) and post- processing each line as it is copied into the variable (putting back the tabs and commas).

As has been said in many other fora, optimisation is hard work. You have to analyse and try lots of things. You do get a gut feel for what works and what doesn’t, but it’s a wise developer who just doesn’t always assume!

Stopping FileMaker Server with a batch file

Here is a link to a screencast of a presentation I did at a conference.

It shows three scenarios when closing FileMaker Server databases from a simple windows batch file:

  • No users connected
  • A user connected who disconnects when prompted
  • A stubborn user who doesn’t want to disconnect

The batch file is very simple. No attempt to make it sophisticated was made as the purpose of the conference session was alerting the IT staff attending to the existence of command line tools!

Click to view on Youtube

This is related to my earlier posts on OS X shell scripts to close FileMaker Server files:

OS X Shell Script to close all FileMaker Server files