Working with Resources

Working with Resources

It can be advantageous at times to attach auxiliary information to a particular table that does not conform to the record structure of that table. For example, features such as versioning or special flags relating to the status of the table. Generally, this information is not repeated in every record of the table. You could create a special record, with a special key value, that you do not process as you do your regular records. Ultimately, however, this forces exceptional handling routines for this special case and can impose a heavy maintenance cost on the life cycle of the application.

FairCom DB provides a unique feature created for exactly this purpose: FairCom DB Resources. Resources are special variable-length records stored within your data file, whether you use fixed or variable-length records. A set of FairCom DB API functions provide access to create, update, and delete these resource records. These records do not require a key in an index, therefore your program does not access them via routine data handling functions.

Resources provide critical support for many advanced FairCom DB features. FairCom-defined resources allow seamless functionality of many of the Incremental ISAM features, conditional index support, FairCom DB API, FairCom DB SQL, c-tree ODBC Drivers, and the r-tree Report Engine. These resources continue to be important as new technology is added. Resources are added either automatically by some FairCom DB features or manually by the developer. The use of resources requires the RESOURCES define in the FairCom DB library, which is the default.

This article focuses on user defined resources added by you, the developer, and provides important background information on the use of resources.


Types of Resources

There are three general types of resources that can be attached to a file.

User-defined resources

Information that you wish to store in the table, such as a version number, or an infrequently accessed counter. Use resources to store information associated with a table that varies from the type of information stored repetitively in the data records.

FairCom-defined resources

There is a variety of information that, under certain circumstances, FairCom wishes to store in the table. This can be information relating to IFIL structures, alternate collating sequences, special characters for key padding, and so forth. Usually you do not access this information directly. It is available to a variety of FairCom DB API functions that use it.

Third-party resources

As other developers create utilities integrating with FairCom DB, FairCom assigns resource identifiers when necessary.

Resource Identification

Within a given data file, a Resource is identified by three elements.

Resource Element Data Type
Type unsigned long integer
Number unsigned long integer
Name null terminated string

Within each file, you can identify a Resource by its unique combination of Type and Number, or by its Name.

Note: The Resource Name is not guaranteed to be unique.

Resource Type

Resource Type gathers Resources into related groups. Resource Types in the range of 1 to 127 are reserved for use by FairCom. These are special Resources used by the FairCom DB, r-tree Report Generator, the d-tree application builder, FairCom DB API, and FairCom DB SQL. Resource Types in the range of 128 to 65536 are also reserved and are explicitly assigned to third party developers by FairCom. Resource Types numbered 65537 and above are available to any developer and can be assigned as desired.

Resource Number

There are no restrictions on assigning Resource Numbers. They separate various Resources within a given Resource Type. When adding a Resource to a file, FairCom DB can assign the next available value for this Resource Type in the referenced table.

Resource Name

You can use the Resource Name as a way to access Resources in a file instead of using the Type and Number. This can make application code more readable if you use a symbolic name rather than a pair of numbers. If you are adding a number of Resources to a data file over a period of time you may not know what Resource Number has been used, particularly as FairCom DB can automatically assign the next available Resource Number. Access via Resource Name is simpler than keeping track of what Resource Number has been assigned.

However, use caution when assigning Resource Names. FairCom DB cannot guarantee that each Resource Name is unique within a table. It is possible to add a duplicated Resource name to a table.

Resource Names are optional. They are not required for a Resource. The Resource Name is a null terminated character string of any length. FairCom recommends you do not make them too long. Resource Names starting with the character sequence "FC!" are reserved for use by FairCom. Resource Names starting with with the character sequence "RD!" are reserved for Resources assigned to third party developers by FairCom.


FairCom DB API C API - Working with Resources

Resource operations are usually performed in the following sequence:

  1. Allocate a resource handle with the FairCom DB API call, ctdbAllocResource().
  2. Perform the desired resource operation such as adding, updating, deleting or reading resources.
  3. Once a resource handle is no longer required, call ctdbFreeResource() to free any resource locks and release the memory allocated for the resource handle.

Allocating and Releasing Resource Handles

Before any operations can be performed on resources with FairCom DB API, you are required to allocate a resource handle. Resource handles are opaque handles whose contents are not available to the developer. You must use the set of functions provided by FairCom DB API to set and get properties and perform resource operations. Handles allocated with ctdbAllocResource() should only be used with resource related functions.

To allocate a new resource handle you need to call the following functions:

CTHANDLE ctdbDECL ctdbAllocResource(CTHANDLE Handle, ULONG type, ULONG number, pTEXT name);

  • Handle is a FairCom DB API table handle.
  • type is the resource type.
  • number is the resource number.
  • name is the resource name.

If you do not know these values in advance, you can set the type and number parameters to zero and name to a NULL pointer or empty string (""). If the resource handle is allocated correctly, ctdbAllocResource() returns a pointer to the new resource handle. If an error occurs while allocating the resource handle, ctdbAllocResource() returns NULL and you should call ctdbGetError(Handle) to retrieve the error code of the error.

Once the resource handle is no longer needed, you must call ctdbFreeResource() to release all system resources used by FairCom DB API Resource processing. To release a resource handle you should invoke the following FairCom DB API function:

CTDBRET ctdbDECL ctdbFreeResource(CTHANDLE resource);

resource is a resource handle allocated by ctdbAllocResource(). ctdbFreeResource() returns CTDBRET_OK on success or a CTDBRET_NOTRESOURCE error if the handle passed to ctdbFreeResource() was not allocated by ctdbAllocResource() or is invalid. Once a resource handle is released by ctdbFreeResource(), the resource handle is invalid should not be used again.

FairCom DB API C API Allocate Resource Example

CTDBRET DisplayAllResources(CTHANDLE hTable)
{
	CTDBRET eRet;
	CTHANDLE hRes = ctdbAllocResource(hTable, 0, 0, NULL);
	
	/* check if resource was allocated */
	if (!hRes)
		return ctdbGetError(hTable);

	/* get the first resource */
	/* note that no resource locks are acquired since we are not changing the resources */
	if ((eRet = ctdbFirstResource(hRes, false)) != CTDBRET_OK)
	{
		ctdbFreeResource(hRes);
		return eRet;
	}

	/* get the other resources */
	do
	{
		/* display resource type, number and name */
		printf("Resource type: %u, number: %u", ctdbGetResourceType(hRes), ctdbGetResourceNumber(hRes));
		if (ctdbGetResourceName(hRes) != NULL)
			printf(", name: \"\"\n", ctdbGetResourceName(hRes));
		else
			printf(", name: NULL"\n");
	}
	while ((eRet = ctdbNextResource(hRes, false)) != CTDBRET_OK);

	ctdbFreeResource(hRes);
	return eRet;
}

Adding New Resources

When adding a Resource to a table, a special variable-length record is written to the table, containing the information from the Resource Data Block. This is done even if a data file contains fixed-length records. Every Resource is identified by a unique combination of a Resource Type and a Resource Number. The Resource Number can optionally be assigned by FairCom DB when calling ctdbAddResource(). In addition, each Resource can be identified by a Resource Name. A Resource Name is not guaranteed to be unique.

The following steps are required to add a new resource to a table:

  1. Allocate a resource handle by calling ctdbAllocResource() and pass a unique resource type and number and an optional resource name.
  2. Call ctdbAddResource() to add the new resource, passing the resource data and the length of the data.
  3. Release the resource handle by calling ctdbFreeResource().

To add a new resource you must call the following function:

CTDBRET ctdbDECL ctdbAddResource(CTHANDLE resource, pVOID data, VRLEN size);
  • resource is a resource handle allocated by ctdbAllocResource().
  • data is any collection of data you wish to store as a Resource. This can be a character string, a structure, or any variable type.
  • size indicates the number of bytes occupied by the data parameter value.

The Resource Type must be a value greater than 65536. 0 through 65536 are reserved for FairCom use. If the Resource Number is a value of CTDB_ASSIGN_RESOURCE_NUMBER (0xffffffff), FairCom DB assigns to this Resource the next available Resource Number for this Resource Type in the specified data file. The assigned number can be retrieved by calling ctdbGetResourceNumber() before the resource handle is released. The Resource Name is optional. FairCom DB does not guarantee unique Resource Names. Names starting with the character sequences "FC!" or "RD!", are reserved for FairCom use.

FairCom DB API C API Add Resource Example

/* return CTDB_ASSIGN_RESOURCE_NUMBER on error */
ULONG AddMyResource(CTHANDLE Handle, ULONG type, pTEXT name, pVOID data, VRLEN size)
{
	ULONG number = CTDB_ASSIGN_RESOURCE_NUMBER;
	CTHANDLE hRes = ctdbAllocResource(Handle, type, number, name);
	CTDBRET eRet;
		
	/* check if resource handle was allocated */
	if (!hRes)
	{
		printf("ctdbAllocResource failed with error %d\n", ctdbGetError(Handle));
		return number;
	}

	/* Add the resource */
	if ((eRet = ctdbAddResource(hRes, data, size)) != CTDBRET_OK)
	{
		printf("ctdbAddResource failed with error %d\n", eRet);
		ctdbFreeResource(hRes);
		return eRet;
	}

	/* retrieve the assigned resource number */
	number = ctdbGetResourceNumber(hRes);

	/* release the resource handle */
	ctdbFreeResource(hRes);
	return number;
}

Deleting Resources

A resource can be deleted from a table by calling the following FairCom DB API C API function:

CTDBRET ctdbDECL ctdbDeleteResource(CTHANDLE resource);

Before the resource can be deleted, the table must be opened with exclusive mode CTOPEN_EXCLUSIVE.

  • resource is a resource handle allocated by ctdbAllocResource(), and the resource type and resource number that identify this resource must be passed to ctdbAllocResource().

After the resource is deleted, its name, number and name are reset.

FairCom DB API C API Delete Resource Example

/* delete a resource */
CTDBRET DelMyResource(CTHANDLE Handle, ULONG type, ULONG number, pTEXT name)
{
	CTDBRET Retval;
	CTHANDLE hRes = ctdbAllocResource(Handle, type, number, name);

	if (hRes)
	{
		if ((Retval = ctdbDeleteResource(hRes)) != CTDBRET_OK)
			printf("ctdbDeleteResource failed with error %d\n", Retval);

		ctdbFreeResource(hRes);
	}
	else
	{
		printf("Failed to allocate resource handle\n");
		Retval = CTDBRET_NOMEMORY;
	}	
	return Retval;
}

Updating Existing Resources

An existing resource can be updated by calling the following function:

CTDBRET ctdbDECL ctdbUpdateResource(CTHANDLE resource, pVOID data, VRLEN size);

You must call ctdbAllocResource() with specific resource type and number that will uniquely identify the resource being updated.

  • resource is a resource handle allocated by ctdbAllocResource().
  • data is any collection of data that you wish to store as a Resource. It can be a character string, a structure, or any variable type.
  • size indicates the number of bytes occupied by data parameter value. ctdbUpdateResource() returns CTDBRET_OK on success.

FairCom DB API C API Update Resource Example

CTDBRET UpdateMyResource(CTHANDLE Handle, ULONG type, ULONG number, pTEXT name, pVOID data, VRLEN size)
{
	CTDBRET Retval;
	CTHANDLE hRes = ctdbAllocResource(Handle, type, number, name);
	
	if (hRes)
	{
		if ((Retval = ctdbUpdateResource(hRes, data, size)) != CTDBRET_OK)
			printf("ctdbUpdateResource failed with error %d\n", Retval);
			
		ctdbFreeResource(hRes);
	}
	else
	{
		printf("Failed to allocate resource handle\n");
		Retval = CTDBRET_NOMEMORY;
	}
	return Retval;
}

Reading Resources

Essentially, there are four different methods to read resources from a FairCom DB table. Read all table resources, read all resources starting past a resource type and number, read a specific resource by specifying the Resource Type and Resource Number, or read a resource by specifying a Resource Name. Described below are examples of each method.

Read all c-tree Plus Resources from a Table

Read all resource starting with the first resource by calling ctdbFirstResource() and then read the remaining resources by calling ctdbNextResource(). To read the first resource in a table, call the following function:

CTDBRET ctdbDECL ctdbFirstResource(CTHANDLE resource, CTBOOL lock);

ctdbFirstResource() retrieves the first resource stored in a table.

  • resource is a handle allocated with a call to ctdbAllocHandle().
  • lock indicates if the resource should be locked, if it is found.

ctdbFirstResource() returns CTDBRET_OK on success. If the table contains no resources, ctdbFirstResource() returns RNOT_ERR (408).

To read the rest of the resources from the table, call the following function:

CTDBRET ctdbDECL ctdbNextResource(CTHANDLE resource, CTBOOL lock);

ctdbNextResource() retrieves the next resource stored in a table, after a successful call to ctdbFirstResource() is made.

  • resource is a handle allocated with a call to ctdbAllocHandle().
  • lock indicates if the resource should be locked, if it is found.

ctdbNextResource() returns CTDBRET_OK on success. After the last resource has been retrieved from the table, ctdbNextResource() returns RNOT_ERR (408).

Example

CTDBRET DisplayAllResources(CTHANDLE hTable)
{
	CTDBRET eRet;
	CTHANDLE hRes = ctdbAllocResource(hTable, 0, 0, NULL);
	
	/* check if resource was allocated */
	if (!hRes)
		return ctdbGetError(hTable);

	/* get the first resource */
	/* note that no resource locks are acquired since we are not changing the resources */
	if ((eRet = ctdbFirstResource(hRes, false)) != CTDBRET_OK)
	{
		ctdbFreeResource(hRes);
		return eRet;
	}

	/* get the other resources */
	do
	{
		/* display resource type, number and name */
		printf("Resource type: %u, number: %u", ctdbGetResourceType(hRes), ctdbGetResourceNumber(hRes));
		if (ctdbGetResourceName(hRes) != NULL)
			printf(", name: \"\"\n", ctdbGetResourceName(hRes));
		else
			printf(", name: NULL"\n");
	}
	while ((eRet = ctdbNextResource(hRes, false)) == CTDBRET_OK);

	ctdbFreeResource(hRes);
	return eRet;
}

 

Read all FairCom DB Resources Given a Starting Point from a Table

Read all resources from a table starting from a given resource type and number by calling ctdbNextResource(). Start by allocating a resource handle, set the resource type and a resource number and then call ctdbNextResource(). In this case a resource is found if its type is greater or equal to the specified type and its number is greater than the specified number.

Example

/* read resources with type >= type and number > 0 */
CTDBRET DisplayResources(CTHANDLE hTable, ULONG type)
{
	CTDBRET eRet;
	CTHANDLE hRes = ctdbAllocResource(hTable, type, 0, NULL);
	
	/* check if resource was allocated */
	if (!hRes)
		return ctdbGetError(hTable);

	/* note that no resource locks are acquired since we are not changing the resources */
	while ((eRet = ctdbNextResource(hRes)) == CTDBRET_OK)
	{
		/* display resource type, number and name */
		printf("Resource type: %u, number: %u", ctdbGetResourceType(hRes), ctdbGetResourceNumber(hRes));
		if (ctdbGetResourceName(hRes) != NULL)
			printf(", name: \"\"\n", ctdbGetResourceName(hRes));
		else
			printf(", name: NULL"\n");
	}

	ctdbFreeResource(hRes);
	return eRet;
}

Read a Specific FairCom DB Resource from a Table

Read a specific resource by providing the exact resource type and number by calling ctdbFindResource():

CTDBRET ctdbDECL ctdbFindResource(CTHANDLE resource, ULONG type, ULONG number, CTBOOL lock);

ctdbFindResource() locates and retrieves a resource from a table based on the Resource Type and Resource Number.

  • resource is a resource handle allocated by ctdbAllocResource().
  • type is a value of the resource type.
  • number is the value of the resource number to be located.
  • lock indicates if the resource should be locked, if it is found.

ctdbFindResource() returns CTDBRET_OK on success. If the specified resource is not in the table, ctdbFindResource() returns RNOT_ERR (408).

Example

/* display a particular resource */
CTDBRET DisplayResource(CTHANDLE hTable, ULONG type, ULONG number)
{
	CTDBRET eRet;
	CTHANDLE hRes = ctdbAllocResource(hTable, 0, 0, NULL);
	
	/* check if resource was allocated */
	if (!hRes)
		return ctdbGetError(hTable);

	/* note that no resource locks are acquired since we are not changing the resources */
	if ((eRet = ctdbFindResource(hRes, type, number, NO)) == CTDBRET_OK)
	{
		printf("Resource type: %u, number: %u", ctdbGetResourceType(hRes), ctdbGetResourceNumber(hRes));
		if (ctdbGetResourceName(hRes) != NULL)
			printf(", name: \"\"\n", ctdbGetResourceName(hRes));
		else
			printf(", name: NULL"\n");
	}
	ctdbFreeResource(hRes);
	return eRet;
}

Read a FairCom DB Resources by Name from a Table

Read a resource by providing its name with the ctdbFindResourceByName() FairCom DB API C API call.

CTDBRET ctdbDECL ctdbFindResourceByName(CTHANDLE resource, pTEXT name, CTBOOL lock);

ctdbFindResourceByName() locates and retrieves a resource by name. FairCom DB cannot guarantee unique resource names.

  • resource is a handle allocated with ctdbAllocHandle().
  • name is the resource name being located.
  • lock indicates if the resource should locked, if it is found.

ctdbFindResourceByName() returns CTDBRET_OK on success. If there are no resources for the table with the specified name, ctdbFindResourceByName() returns RNOT_ERR (408).

Example

/* display a particular resource */
CTDBRET DisplayResource(CTHANDLE hTable, pTEXT name)
{
	CTDBRET eRet;
	CTHANDLE hRes = ctdbAllocResource(hTable, 0, 0, NULL);
	
	/* check if resource was allocated */
	if (!hRes)
		return ctdbGetError(hTable);

	/* note that no resource locks are acquired since we are not changing the resources */
	if ((eRet = ctdbFindResourceByName(hRes, name, NO)) == CTDBRET_OK)
	{
		printf("Resource type: %u, number: %u", ctdbGetResourceType(hRes), ctdbGetResourceNumber(hRes));
		if (ctdbGetResourceName(hRes) != NULL)
			printf(", name: \"\"\n", ctdbGetResourceName(hRes));
		else
			printf(", name: NULL"\n");
	}
	ctdbFreeResource(hRes);
	return eRet;
}

 

Get and Set Resource Properties with the FairCom DB API C API

A number of functions are provided to enable getting and setting resource handle properties. The table below describes each function.

FairCom DB API Resource API Function Description
ctdbGetResourceType() get the resource type
ctdbSetResourceType() set the resource type
ctdbGetResourceNumber() get the resource number
ctdbSetResourceNumber() set the resource number
ctdbGetResourceName() get the resource name
ctdbSetResourceName() set the resource name
ctdbGetResourceDataLength() get the resource data buffer length in bytes
ctdbGetResourceData() get a pointer to resource data buffer
ctdbSetResourceData() set the resource data buffer

 

Resource Locks

It is expected that you process resource updates without permitting user interactions to occur during the actual update. It is important for performance considerations and FairCom DB API assumes that resource entries will be locked only for very short intervals. Do not lock a resource and then request user input. Be careful not to include resource updates, (additions, deletions or updates), in long held transactions when the table is under transaction processing control. Locks cannot be released until a transaction either commits or aborts.

FairCom DB API resource handling automatically unlocks resources when necessary. A resource can be manually unlocked by the user. Use the following function to check if a resource is locked or not:

CTBOOL ctdbDECL ctdbIsResourceLocked(CTHANDLE resource);

where:

  • resource is a resource handle allocated by ctdbAllocHandle().

ctdbIsResourceLocked() returns YES if the resource referenced by the resource handle is locked, otherwise it returns NO.

The following function should be used to unlock resources whose locks are no longer necessary:

CTDBRET ctdbDECL ctdbUnlockResource(CTHANDLE resource);

ctdbUnlockResource() releases a lock placed on a resource by one of the following read resource functions: ctdbFirstResource(), ctdbNextResource(), ctdbFindResource() or ctdbFindResourceByName().

Return

ctdbUnlockResource() returns CTDBRET_OK on success.

If a resource is not locked, ctdbUnlockResource() performs no operation and returns CTDBRET_OK.

FairCom DB API C API Resource Unlocking Example

if (ctdbIsResourceLocked(resource))
	ctdbUnlockResource(resource);