Design Concepts

1 Introduction
2 Conventions
3 Buffering
4 Uncompressed Versus Compressed Indexes
5 Error Handling

1 Introduction

In order to facilitate thread safe programming, the core library has been developed to use isam file descriptor structures, rather than the standard integral handle concept. The external function calls are named after the original function names, but use capital letters to keep them separate, as in isOpen rather than isopen. the status and information globals, such is iserrno and iserrio, have been eliminated, and each file descriptor now carries it's own copy.

The standard (lower case) calls are provided as an optional wrapper layer which maintains a dictionary of descriptors to allow mapping via the standard integer file handles. It also defines and passes the standard global variables.

2 Conventions

All public library function names start with 'is' and use capital letters to distinguish keywords.

All structure definitions and typedefs start with a capital letter, and use the same capitalisation rules to distinguish keywords, with the exception of standard integers.

The posix standard system calls are wrapped in functions prefixed by is and an underscore.

Local support routines in each module are named in lowercase.

Macro definitions are all capitals.

Virtually all entry and internal functions return TRUE on success and FALSE on failure. TRUE is defined as 1, FALSE is 0.

3 Buffering

The tree node buffering system operates by handing node images which are no longer part of the current path to a storage mechanism. Each index carries it's own path list and storage array.

A single linked list holds the current path and facilitates traversal without having to move data around. The node description structures, which contain current status information and a copy of the node disk image, are are passed to and from the path list and the buffer array as pointers.

The buffer cache is currently optimised on a last in first out basis. it might be worthwhile to consider optimising this further by giving a degree of precedence to nodes from lower levels in the tree, on the assumption that these will take more hits.

Buffers are flagged invalid whenever the index file header transaction count has been changed by another process, and will be refreshed as required.

At some point in the future, at the cost of cisam concurrency, it may be worthwhile to consider designing a more detailed currency control which would maintain separate transaction counts for each index, and perhaps additional counts for the index and data free lists, variable length storage space, and so on.

The same buffering system provides a failsafe error recovery method in which updated node images are flagged invalid on error, which then results in a forced refresh before the image can be used again. this method allows for optimistic updates, eliminating the need to check first before embarking on potentially illegal updates. see error handling below for more details.

4 Uncompressed Versus Compressed Indexes

For the dual purpose of keeping the code cleaner and to improve performance, the index handling routines are split into separate functions where the associated handling is markedly different.

Flat indexes, in general, can be operated on mathematically, lend themselves to shell searches, and permit the current key value to be a simple pointer into the node image.

Compressed indexes require that each node be searched in a linear fashion, building the key image in an allocated buffer en route, and generally require a fair amount more processing to operate.

The index handing and manipulation modules - isnode, isgrow and isprune - all adhere to this standard. The decision as to which handling method to apply is made at the top level, eliminating the need for myriad if-then-else tests during processing.

5 Error Handling

The new library deals with errors via ''setjmp''/''longjmp''. Each external entry point is responsible for initialising a jump buffer and mode flag in the file descriptor. When an error is detected the thread is passed to an error handling routine which sets the error codes and drops the index locks before returning control the entry call.

The error handling routine is also responsible for clearing the update buffers when triggered in write mode.

The nature of setjmp/longjmp means that it appears to the calling function as if the ISFAIL call, made initially to initialise the jump buffer, had returned TRUE.