PHP: http://code.svn.wordpress.org/lockd/lockd-client.php Python: https://gist.github.com/mdawaffe/e53c86e5163b48d5fe3a Go: https://github.com/apokalyptik/glockc
docker build -t glockd github.com/apokalyptik/glockd.git
docker run -p 9999:9999 -p 9998:9998 glockd -dump=false -registry=false -verbose=true
cd glockd
go run ./*.go -pidfile my.pid -port 9999 -ws 9998
cd glockd
go build
./glockd --pidfile my.pid -port 9999 -ws 9998
cd tester
go run test.go --host 127.0.0.1:9999
If TCPIP has not been disabled (by passing -port 0 as a command line parameter) then you may simply telnet to the port number that glockd is listening on (9999 by default.) You can open a TCPIP socket in any programming language this way (fsockopen in PHP for example.) There is no handshake, banner, or negotiation that takes place. Once connected it is ready for commands to be issued on the connection.
Client Implimentations: PHP http://code.svn.wordpress.org/lockd/lockd-client.php
If websockets have not been disabled (by passing -ws 0 as a command line parameter) then you may simply connect to it as you normally would on "ws://%s:%d/", host, port. Glockd listens for websocket connections on port 9998 by default. The api is not changed at all for websockets.
If a path to a local unix socket has been specified (via the -unix parameter) then you may connect to it how you would any AF_UNIX socket per your programming language (example below.) You may then read/write commands as you would a TCP/IP socket connection. This obviously only works when connecting to glockd from the same machine since a shared filesystem which supports unix sockets is required.
Example connecting to glockd via unix sockets (python)
import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/var/run/glockd/socket")
s.sendall("g foo\n")
print s.recv(4096)
Exclusive locks are... exclusive. They can only be held by one connection at a time.
Upon disconnection of a client all of that clients exclusive locks are considered to be "orphaned". All orphaned locks are automatically released. The intended purpose of this functionality is to help avoid the complicated gymnastics generally used in distributed locking (timeouts, heartbeating, etc) where a single process can maintain a lock simply by its continued presence, and can release its lock by its absence. A side effect of this methodology is that stale locks simply cannot exist in this environment. If the connection goes away then its locks are released. Any lock still extant, therefor, is still validly held by a process that is still literally running somewhere.
Shared locks are... not exclusive. They can be obtained by any number of clients at the same time.
One interesting feature of shared locks is that they are counted. That is if 4 people have a lock, and another goes to lock the same thing then when it does it will be told that it is the 5th client to obtain that lock. This makes shared locks good for things like rate limiting, throttling, etc, where the client can have logic built in in which after 5 active locks are obtained it waits, defers, or otherwise avoids doing work for which the shared lock was wanted.
Upon disconnection of a client all of that clients shared locks are considered to be "orphaned". All orphaned locks are automatically released. This behavior works just like the exclusive lock orphaning feature. Counts on shared locks are appropriately updated when locks are orphaned.
Generally speaking most commands for exclusive locks return a response thusly: "%d %s". The integer portion of the response is meant for programatic interpretation, and represent success (1) or failure (0), or represent taken (1) or available (0).
In the following example "foo" is available, but "bar" is already locked by another client
g foo < 1 Lock Get Success: foo g bar < 0 Lock Get Failure: bar
g foo < 1 Lock Get Success: foo r foo < 1 Lock Release Success: foo r bar < 0 Lock Release Failure: bar
i foo < 1 Lock Is Locked: foo i bar < 0 Lock Not Locked: bar
Get a list of one or more locks and their locking connections: "d\n", or "d %s\n", lockname (only available when -dump is true)
This is mainly useful for debugging
d < baz: 174.62.83.171:59060 < foo: 174.62.83.171:59056 < bar: 174.62.83.171:59060 < boo: 174.62.83.171:59060 d foo < foo: 174.62.83.171:59056
This is mainly useful for debugging
dump < map[boo:174.62.83.171:59060 baz:174.62.83.171:59060 foo:174.62.83.171:59056 bar:174.62.83.171:59060]
Generally speaking most commands for shared locks return a response thusly: "%d %s". The integer portion of the response is meant for programatic interpretation, and represent success %d >= 1 or failure %d == 0, or represent [lack of] concurrency %d >= 0
client1> sg foo client1< 1 Shared Lock Get Success: foo client2> sg foo client2< 2 Shared Lock Get Success: foo client2> sg bar client2< 1 Shared Lock Get Success: bar
client1> sg foo client1< 1 Shared Lock Get Success: foo client2> sg foo client2< 2 Shared Lock Get Success: foo client3> si foo client3< 2 Shared Lock Is Locked: foo client1> sr foo client1< 1 Shared Lock Release Success: foo client3> si foo client3< 1 Shared Lock Is Locked: foo client2> sr foo client2< 1 Shared Lock Release Success: foo client3> si foo client3< 0 Shared Lock Not Locked: foo
client1> si foo client1< 0 Shared Lock Not Locked: foo client1> sg foo client1< 1 Shared Lock Get Success: foo client2> si foo client2< 1 Shared Lock Is Locked: foo client2> sg foo client2< 2 Shared Lock Get Success: foo client1> si foo client1< 2 Shared Lock Get Success: foo
Get a list of one or more locks and their locking connections: "sd\n", or "sd %s\n", lockname (only available when -dump is true)
sd < blah: 174.62.83.171:59615 < bar: 174.62.83.171:59615 < foo: 174.62.83.171:59615 < foo: 174.62.83.171:59614 < baz: 174.62.83.171:59615 sd foo < foo: 174.62.83.171:59615 < foo: 174.62.83.171:59614
dump shared < map[blah:[174.62.83.171:59615] bar:[174.62.83.171:59615] foo:[174.62.83.171:59615 174.62.83.171:59614] baz:[174.62.83.171:59615]]
This command always returns two values. First the default connection name (which is what would be used in the output of the dump( shared)? commands) and the second is the registered name of the connection (which would be used in the output of the s?d commands and defaults to the first parameter if the iam command was not used to register a name for the current session)
< me
1 127.0.0.1:57871 127.0.0.1:57871 < iam foo 1 ok < me 1 127.0.0.1:57871 foo
g lock1 < 1 Got Lock d lock1 < lock1: 127.0.0.1:60882 iam foo < 1 ok d lock1 < lock1: foo iam < 1 ok d lock1 < lock1: 127.0.0.1:60882
Find which clients have chosen to be a specific name (only available when -dump is true and -registry is true)
client1> who client1< client1> iam me client1< 1 ok client2> iam someone_else client2< 1 ok client1> who client1< 127.0.0.1:60882: me client1< 127.0.0.1:60918: someone_else client1> who someone_else client1< 127.0.0.1:60918: someone_else
q < command_d: 4 < command_dump: 1 < command_g: 9 < command_i: 7 < command_q: 1 < command_r: 3 < command_sd: 1 < command_sg: 1 < command_si: 2 < command_sr: 1 < connections: 2 < invalid_commands: 23 < locks: 4 < orphans: 2 < shared_locks: 1 < shared_orphans: 1
The number of times a particular command has been issued since the glockd has been running. Zeroed on startup
The current active number of locked strings. For shared locks this is the number of locked strings and NOT the number of clients with active locks
Incrimented by one every time a lock is orphaned. If a client disconnects with 3 shared and 1 exclusive locks then the numbers are incrimented by 3 and 1 respecively. Zeroed on startup
The number of live connections to glockd. This number should always be 1 since you cannot get these stats except by connecting.
The number of times something has been sent to glockd but that something was not a valid command. Example: "stats\n" would incriment this counter by one since "stats" is not a valid command. Zeroed on startup