# todo: latex this # # 18 July 2003 # # rob latham and team pvfs2 # Adding a new server operation is currently rather involved. I'm going to try to lay out what i did to add a flush operation to pvfs2 CLIENT-SIDE Add a prototype for your function to pvfs2-sysint.h. If your function just needs to know if it suceeded or failed, you are done. If not, you must also define a server response structure. We are moving to using state machines for both client and server operations, so if you are adding a new operation, make it a state machine. Define your operation-specific state machine structure in client-state-machine.h and add it to the PINT_client_sm structure. Add your operation to the switch statement in PINT_client_state_machine_post() there is an unnamed enum in client-state-machine.h with some other operations (PVFS_SYS_REMOVE, PVFS_SYS_IO, etc). Add your operation to that enum. also in client-state-machine.h, declare your state machine 'extern' with the other operation state machine declarations. add the .c file for your operation to src/client/sysint/module.mk.in A client-side state machine can take advantage of several nested state machines. The client state machines tend to have a certain pattern to them: check_parameters, then for each time they talk to the server there is a 'setup/xfer/failure' triplet of states to send a msgpair (or a bunch of msgpairs in one msgpairarray). lastly, 'cleanup'. As with the server, the best documentation is other state machines. SERVER-SIDE It's probably a good idea to start implementing your new operation at the trove layer, then adding support for it at the job interface. Once the job interface is in place, then you can implement the state machine. Doing things this way means you can always compile the tree to catch errors. Trove: If you need to extend trove functionality to implement your new operation, start by adding a prototype to trove-proto.h. This will autogenerate the code that links the trove api to the underlying storage implementation (currently dbpf). Define a new member of the TROVE_bstream_ops, TROVE_keyval_ops, and/or TROVE_dspace_ops structure. Add the dbpf implementation: check out trove-dbpf/dbpf-bstream.c and trove-dbpf/dbpf-keyval. At the bottom of those files is a structure of function pointers. Add your new function. If your new function is nonblocking, add it to the dbpf_op_type enum. Job: You can follow the example of the other job functions to get error handling/reporting, mutex locking, and calling down to trove correct. Add a prototype for your function to job.h State Machine: Write a state machine to deal with the server-side of your operation. The 'prelude' and 'final_response' states take care of some common tasks. look at the other server state machines to see how things should go: that's the best documetnation so far. Declare this new state machine in pvfs2-server.h with the other server operation state machines. Everything Else: define a PINT_server_xxx_op with the information specific to your new operation, and add it to the union in PINT_server_op. Add a new enum to PVFS_server_op, just before the sentinel PVFS_SERV_NUM_OPS. Define a server request structure (PVFS_servreq_xxx) and optionally (but encouraged) a PINT_SERVREQ_xxx_FILL macro. If your operation needs information back from the server (beyond 'success' or 'fail'), define a PVFS_servresp_xxx structure for the server response. Add these new structures to the union in the declaration of the PVFS_server_req and PVFS_server_resp (if necessary). For many operations, -TROVE_ENOENT is ok (e.g. operations on datafiles [because we do not store attributes with datafiles], flushing a keyval when the keyval space has not been created on disk, or setting attributes on a file that didn't have atributes previously). If your operation is like that, modifly prelude_perm_check and add it to the list of operations for which TROVE_ENOENT is ok. If you haven't figured out what it means to 'check permissions' for your operation, add it towards the bottom of the function with the other oddball operations. Help out the debugging helper functions by adding a text representation of your operation to PINT_map_server_op_to_string() The server will not know how to handle the new operation until you've addded it along with the other operations in server_state_table_initialize(). If your operation needs data from the request structure (and most of them do), modify PINT_req_sched_target_handle to make the apropriate copies. PROTOCOL the encode and decode system needs to know how to handle your new operation. If it is a self-contained structure -- that is, it has no pointers -- then it can be added with the other self-contained structures in do_decode_req(), do_encode_req(), do_decode_resp(), and do_encode_resp(). Otherwise, you'll have to perform more steps like those done in PVFS_SERV_IO and PVFS_SERV_MKDIR and others. TESTING no new operation should go in without a testcase exercising that operation. add it to the other tests in tests/client/sysint and add it to the list of targets to build in module.mk.in # vim: tw=72