Blog › ICP guides

Clarion developer on retainer: TPS file record lock not released, SoftVelocity Clarion developer, Clarion for Windows developer on monthly retainer

October 9, 2026 · ~15 min read

A Clarion developer was maintaining an order entry application built in Clarion 11 for a regional auto parts distributor. The application ran on eight Windows 10 workstations sharing a TopSpeed (TPS) database on a Windows Server file share. A window procedure named ProcessOrderWindow retrieved the customer record before creating each order, calling ACCESS:CustomerFile.TryLock(Record) to acquire an exclusive TPS record lock for credit limit validation. When a customer had insufficient credit, the procedure called MESSAGE('Credit limit exceeded. Please verify with the customer.') followed by RETURN to exit the embed code and return the operator to the order form without placing the order. The ACCESS:CustomerFile.Release() call that released the TPS record lock was placed only on the success path — after credit validation passed and the order was created. Three operators whose customers failed credit validation on the same shift held exclusive TPS locks on those three customer records for the rest of the shift, because the Clarion TryLock lock persists until the matching Release call is executed, the owning Clarion session exits, or the TPS file is closed. Other operators attempting to open or modify those same three customer records received Clarion’s TPS file access error indicating the record was locked by another workstation. Lock contention errors reported per shift: 8–12 before fix; 0 after ACCESS:CustomerFile.Release() was added before every RETURN on the failure branch.

The root cause was the structure of Clarion’s TPS file locking API and its interaction with the application’s control flow. Clarion’s ACCESS:SomeFile.TryLock(Record) method acquires an exclusive lock on the current record in a TopSpeed file. The lock is held at the session level — specifically, by the Clarion process’s file driver instance for that file — and is not automatically released when the executing embed code returns to its caller, when the window accept loop iterates, or when any local Clarion variable goes out of scope. The lock persists until an explicit ACCESS:SomeFile.Release() call is made, the file is explicitly closed, or the Clarion process terminates. In the ProcessOrderWindow procedure, the developer placed ACCESS:CustomerFile.Release() only inside the “credit passed” code path, reasoning that the validation logic would always reach that path if it successfully processed an order. The MESSAGE + RETURN path for credit failure — the path added months after the original procedure was written to handle the edge case of over-limit customers — exited the embed before the Release call was reached. The Clarion IDE’s template system does not generate warnings about TryLock calls with unmatched Release calls across control flow branches; the compiler does not flag the missing Release. The only indication of the problem is the TPS lock contention error received by other operators.

The invisibility of the bug has two distinct layers in a Clarion development environment. First, the developer who wrote and tested ProcessOrderWindow tested it on a single workstation without concurrent operators. When the developer tested the credit failure path, the MESSAGE dialog appeared and the operator returned to the order form as intended — the feature appeared to work correctly. The TPS record lock on the customer record was held by the developer’s own Clarion session, which is the only session in the test environment, so no lock contention error could occur. The developer had no reason to check whether the customer record lock had been released after the failure path exited, because no second session was trying to access the same record. Second, when the bug appeared in production, the operators receiving lock contention errors had no visibility into which other workstation held the lock or why. The error message from Clarion’s TPS file driver (“Record is locked by another user”) does not name the holding workstation or the procedure that acquired the lock. The operators reported the error to the IT contact as “can’t open customer record,” and the resolution was to ask the holding operator to log out and back in, which released all TPS locks for that session. The underlying cause — Release() missing on the credit failure branch — persisted undetected for weeks, generating 8–12 lock contention incidents per shift.

Clarion: TopSpeed’s RAD database application platform from the DOS era to Windows

Clarion was originally developed by Bruce Barrington at Clarion Software Corporation and released in 1986 as a DOS-based rapid application development (RAD) tool for building business database applications. The product was designed around a tight integration between application UI definition, business logic, and a proprietary flat-file database format — the TopSpeed (TPS) file format — that provided B-tree indexed storage with record-level locking for multi-user access over a DOS file-sharing network. Clarion for DOS found rapid adoption among small-to-medium business developers building order entry, inventory management, accounts receivable, and scheduling applications for industries including automotive dealerships, medical offices, property management, and light manufacturing. The appeal was the same as other DOS-era RAD tools: a developer who understood Clarion templates could produce a fully functional multi-user database application for a small business in days rather than weeks, with no need to write SQL, design normalized schemas, or configure a separate database server.

TopSpeed Corporation acquired Clarion in 1991 and renamed the company to match the proprietary file format they had developed — the TopSpeed B-tree file format that became the TPS format Clarion applications still use today. TopSpeed released Clarion for Windows 2.0 in 1994, porting the RAD application model to the Win16 environment and introducing the Clarion Application Builder (ABC) template system that remains the core of Clarion’s code generation architecture. The ABC template system codifies common application patterns — browse windows, form windows, process procedures, report procedures — as templates that generate Clarion language source code when instantiated with data structure definitions and application settings. A Clarion developer builds an application primarily by defining data dictionaries (the Clarion DCT file: column types, key structures, validation rules), configuring ABC application templates in the Clarion Application Builder, and embedding custom Clarion code at template embed points for logic that the standard templates do not cover. The generator produces complete Clarion source code from this configuration, which the Clarion compiler compiles into a Windows executable. Computer Associates acquired TopSpeed in 1994, then sold the Clarion product line to SoftVelocity Inc. in 2000, which continues to develop and sell Clarion today. SoftVelocity has released Clarion 6, 7, 8, 9, 10, and 11, each adding IDE improvements, updated ABC template sets, and new file driver options while maintaining backward compatibility with the TPS file format and the ABC template architecture established in the mid-1990s.

Clarion’s market presence today is almost entirely in legacy application maintenance. The tens of thousands of Clarion applications built between 1988 and 2005 for small-to-medium businesses — auto dealer management systems, medical billing applications, property management systems, distributor order entry and inventory applications, insurance agency management systems, and light manufacturing ERP applications — continue to run in production today. The businesses that built them or had them custom-developed cannot easily migrate to a modern web stack: the data is in TPS files, the business logic is embedded in Clarion template embed points, and the users are accustomed to the Clarion thick-client Windows UI. A Clarion developer who can navigate the Clarion IDE, understand the ABC template architecture, read the generated Clarion source code, diagnose TPS file locking issues, and make targeted changes to embed points without triggering cascading template regeneration problems is the profile most in demand for Clarion maintenance retainers. The pool of developers who have this skill set is small and shrinking as the developer generation that built Clarion applications in the 1990s and 2000s retires.

The Clarion TPS file locking model is fundamentally different from the SQL row-level locking model that most modern developers are familiar with. A TPS file is a TopSpeed B-tree flat file stored as a single .tps file on the file system. Multi-user access relies entirely on the TPS file driver implementing record-level locking over a shared Windows network file share — there is no separate database server process managing concurrency. The TPS record lock is acquired by calling ACCESS:SomeFile.TryLock(Record) (returns 0 on success, non-zero if the record is already locked by another session) or ACCESS:SomeFile.Lock(Record) (blocks until the lock is available or a timeout occurs). The lock is held at the file driver instance level within the Clarion process — it is associated with the Clarion application’s file driver object for that TPS file, not with a transaction scope, a procedure scope, or a local variable. Releasing the lock requires an explicit call to ACCESS:SomeFile.Release(), which removes the record lock from the TPS lock table maintained by the file driver across all workstations sharing the TPS file. If Release() is not called on a code path, the lock persists for the lifetime of the file driver instance — effectively for the lifetime of the Clarion application session on that workstation. Unlike SQL transactional locking, there is no automatic lock release at a transaction boundary or a scope boundary; the Clarion developer is entirely responsible for ensuring that every TryLock call is matched by a Release call on every possible exit path from the code that acquired the lock.

Clarion TPS locking API: TryLock, Release, and the multi-branch failure pattern

Clarion’s TPS locking API requires precise pairing of TryLock and Release calls across all control flow paths. The ACCESS:SomeFile.TryLock(Record) method acquires an exclusive lock on the record currently positioned in the file driver (the record most recently fetched by ACCESS:SomeFile.Fetch, Next, or Previous). The return value is a LONG: 0 indicates successful lock acquisition; any non-zero value indicates the record is already locked by another session (typically Clarion error code 40 for “record locked”), the file is open in read-only mode, or a file I/O error occurred. The correct pattern for conditional lock acquisition is: call TryLock, check the return value, execute the protected operation only on success, and call Release immediately after the protected operation completes — including on every exception or validation failure path that exits the protected region. In the ProcessOrderWindow procedure, the protected operation was credit validation followed by order creation. The developer correctly called TryLock before the credit check and Release after order creation on the success path. The omission was failing to add Release before the MESSAGE + RETURN on the credit failure path added months after initial development.

Diagnosing TPS record lock contention in a Clarion production environment requires identifying both the locked record and the workstation holding the lock. Clarion’s TPS file driver maintains a lock table in the TPS file itself — a section of the file header that records the active locks held by each workstation session using the shared file. The TpsFileInfo command-line utility (available from SoftVelocity and various Clarion community tool repositories) can open a TPS file and display the current lock table, showing the record number of each locked record and the machine name or session ID of the workstation holding each lock. In the ProcessOrderWindow case: running TpsFileInfo CUSTFILE.TPS from the file server during a lock contention incident would show record numbers corresponding to the three customers whose credit had failed, with the lock holder machine names matching the three operators who had encountered the credit validation failure. This correlates the locked record (specific customer records by key value) with the holding workstation, enabling the diagnosis that the lock was acquired during credit validation but not released on the failure path. An alternative diagnostic approach is enabling Clarion’s file trace logging — setting FILELOG in the Clarion application’s INI file logs each TPS file operation including TryLock, Lock, and Release calls with timestamps and call site context, allowing the retainer developer to replay the sequence of operations that led to the unreleased lock.

The fix for the ProcessOrderWindow TPS lock leak is adding ACCESS:CustomerFile.Release() before every RETURN, MESSAGE-and-exit, and loop-CYCLE that can exit the lock-protected region without having called Release on the success path. In Clarion embed code, this typically requires auditing every control flow path from the TryLock call to the end of the embed. The corrected embed pattern for the credit validation case: call ACCESS:CustomerFile.TryLock(Record); check return value (0 = success); if non-zero, handle the “could not lock” case and RETURN; if zero (locked successfully), run credit validation; if credit fails, call ACCESS:CustomerFile.Release() followed by MESSAGE and RETURN; if credit passes, proceed with order creation, then call ACCESS:CustomerFile.Release() on the success path before the embed exits. The critical discipline is treating TryLock like a resource acquisition that must be explicitly released on every exit path — exactly as a C++ developer treats a mutex lock, or as a database developer treats an explicit LOCK TABLE statement that requires an explicit UNLOCK. Clarion’s ABC template system does not generate this pairing automatically for custom embed code; the developer must implement it manually in every embed point that calls TryLock.

Typical Clarion developer retainer work and what it looks like in a work log

TPS record lock not released on failure branch is the canonical Clarion invisible production lock bug, and it appears in the work logs of nearly every Clarion retainer engagement for auto dealer, medical billing, property management, or manufacturing order entry applications with more than three concurrent users. The pattern is consistent across all Clarion versions from Clarion 6 through 11: a window procedure or process procedure calls TryLock to protect a critical section of data modification logic; the original developer tested the lock acquisition on the success path; a validation failure code path added later exits the embed without calling Release; production users on other workstations intermittently cannot open or modify the locked records; the IT contact resolves the incident by forcing the holding operator to log out and restart Clarion, which releases all TPS locks. The work log entry that makes this diagnosable and auditable: “OrderEntry.app (Clarion 11, TPS file driver); ProcessOrderWindow procedure; TryLock call site: ACCESS:CustomerFile.TryLock(Record) in Accept embed at the Pre-TakeField embed for the customer lookup field; failure branch missing Release: credit validation failure path (MESSAGE + RETURN at Accept embed line 47) exits without ACCESS:CustomerFile.Release(); concurrent operators affected: 3 operators holding TPS locks on 3 customer records for the full shift; lock contention errors reported per shift before fix: 8–12 ('Record is locked by another user'); TpsFileInfo confirmed: 3 locked record entries in CUSTFILE.TPS lock table, machine names matching the 3 affected operators; fix: ACCESS:CustomerFile.Release() added before MESSAGE + RETURN on credit failure branch, and before every other RETURN in the TryLock-to-Release span; lock contention errors per shift after fix: 0; 3h.”

Clarion TPS-to-SQL backend migration is the highest-stakes Clarion retainer engagement category, typically arising when a client needs multi-site access, higher concurrent user counts, web frontend integration, or cloud backup capabilities that the TPS flat-file model cannot provide. The retainer developer begins with a data assessment: count the TPS files, document the key structures and relationship definitions in the Clarion DCT file, and identify any application code that relies on TPS-specific behaviors (TPS sequence numbers, TPS encryption, or TPS bulk import/export operations). The migration workflow using Clarion’s SQL file driver involves creating an ODBC or native SQL driver configuration in the Clarion DCT to target the new SQL backend (typically SQL Server or MySQL for Clarion migration projects), running the Clarion SQL data migration wizard to create the target tables and migrate TPS data, updating the application’s file declarations to use the SQL driver instead of TPS, and testing each browse window and form window for SQL query performance regressions (TPS’s B-tree sequential access patterns differ from SQL optimizer behavior on large tables). The critical locking change to validate during migration: SQL row-level locking behavior differs fundamentally from TPS record-level locking — SQL backends use transactional locking with automatic release at transaction commit, meaning that TryLock / Release patterns in embed code that managed TPS locks must be reviewed to confirm they still produce the correct behavior under SQL transactional semantics. Work log: “OrderEntry.app; TPS-to-SQL Server migration; 14 TPS files; DCT: 14 table definitions updated to SQL Server ODBC driver; TPS data migration: 14 tables, largest 280,000 records (ORDERS.TPS), migration time 8 minutes; TryLock/Release audit: 7 embed points using TryLock identified; SQL transaction behavior confirmed correct for 6; 1 embed point using TryLock in a loop without a surrounding transaction required a Clarion TRANSACTION block wrapper for correct SQL lock semantics; browse window SQL performance: 3 windows required index addition on SQL Server for acceptable query time; hours: 12h.”

Clarion ABC template embed point customization and version migration is the routine Clarion retainer work for applications that need new functionality without a full rewrite. The ABC template system structures a Clarion application as a set of derived classes from the Clarion ABC class library (AppFrame, Window Manager, Browse Manager, Form Manager, Report Manager, Process Manager), with embed points at standardized locations in each class method where the developer can insert custom Clarion code. Adding a new business rule — for example, auto-populating the customer’s last-order date when a new order is created — requires finding the correct embed point in the Form Manager’s TakeCompleted method (the embed that fires after the form record is validated and saved), inserting the Clarion code to query the customer file and update the last-order-date field, and rebuilding the application. A Clarion 10 or 11 migration from Clarion 6 or 7 requires reviewing each custom embed point for compatibility with the updated ABC class library (class method signatures, embed point names, and property accessor patterns have changed across major Clarion versions), updating the DCT for new file driver options, and retesting each browse, form, and report for functional equivalence. Work log: “OrderEntry.app; Clarion 7 to Clarion 11 migration; 23 custom embed points reviewed; 4 embed points using deprecated ABC property accessor patterns updated for Clarion 11 class library (Window Manager SELF.Response replaced with SELF.ViewManager.Response in 3 embeds; Form Manager SELF.Files() loop updated for new FileManager iterator syntax in 1 embed); TryLock/Release audit performed as part of migration: 7 embed points reviewed, 1 missing Release on failure branch fixed (the fix described above); all 14 browse windows and 9 form windows tested for functional equivalence; hours: 8h.”

Track Clarion developer retainer hours without the status emails

When a 3-hour investigation traces 8–12 TPS record lock contention errors per shift to a Clarion ProcessOrderWindow procedure that calls ACCESS:CustomerFile.TryLock(Record) but exits the credit validation failure branch with MESSAGE + RETURN without calling ACCESS:CustomerFile.Release() — holding the exclusive TPS lock on the customer record for the operator’s entire session — the work log must name the procedure, the TryLock call site, the failure branch, the number of affected operators, and the lock contention rate before and after the Release fix. HourTab gives your Clarion retainer client a public dashboard URL they can bookmark: hours used, hours remaining, and a work log naming the missing Release call on the failure branch. No client login. No status emails. CSV in, URL out.

See HourTab pricing →

How HourTab tracks Clarion developer retainer hours

Clarion TPS record lock bugs caused by Release() missing on failure branches are invisible in single-user development by exactly the mechanism that makes all multi-user concurrency bugs invisible in single-user tests. The developer who writes and tests ProcessOrderWindow on a single workstation sees the credit validation failure path working as intended: the MESSAGE dialog appears, the operator clicks OK, and the window returns to the order form. The TPS lock acquired by TryLock is held by the developer’s own session — the only session in the development environment. No lock contention can occur because no second session is attempting to access the same customer record concurrently. The developer has no reason to verify that the TPS lock was released after the failure path exited, because there is no observable consequence of holding the lock in a single-user test. The lock release omission is entirely invisible to the developer at test time. In production, the contention pattern emerges only when two conditions are simultaneously true: a customer fails credit validation, leaving their record locked by the operator’s session, and another operator on a different workstation attempts to access or lock the same customer record within the same shift. Neither condition can occur in a single-workstation development environment.

The work log entry that makes Clarion TPS lock work auditable must name every element of the causal chain. The application name and Clarion version (OrderEntry.app, Clarion 11). The TPS file involved (CUSTFILE.TPS). The procedure name and embed point (ProcessOrderWindow, Accept embed at Pre-TakeField for the customer lookup field). The TryLock call site (line 31: ACCESS:CustomerFile.TryLock(Record)). The failure branch that skipped Release (credit validation failure at line 47: MESSAGE('Credit limit exceeded') + RETURN). The number of concurrent operators affected (3 operators holding locks on 3 customer records). The lock contention error rate before fix (8–12 per shift, all reported as “can’t open customer record”). The diagnostic evidence (TpsFileInfo output showing 3 locked records in CUSTFILE.TPS lock table, machine names matching the 3 affected operators). The fix applied (ACCESS:CustomerFile.Release() added before MESSAGE + RETURN on credit failure, and before all other early exits in the TryLock span). The error rate after fix (0 per shift). Hours (3h). A log entry that says “fixed Clarion locking issue, 3h” is not auditable. A log entry that names the procedure, the lock call site, the failure branch, the diagnostic evidence, and the before/after error rate is auditable and builds the trust that sustains a long-term Clarion retainer relationship. HourTab gives Clarion developers a public retainer-hours URL they send to clients — auto dealers, medical offices, property managers, and distributors running legacy Clarion applications built between the 1990s and 2000s that continue to power their business operations today.

The broader context for Clarion retainer billing is that the TPS lock-not-released-on-failure pattern is not unique to Clarion — it is the universal consequence of explicit lock management in flat-file database drivers where the developer is responsible for pairing every lock acquisition with a matching release on every code path. DataFlex developer retainers cover the DataFlex FIND implicit record lock pattern — the same lock acquired without an explicit API call and not released on the failure branch, producing the same invisible single-user test / multi-user production contention gap. Advantage Database Server developer retainers cover the AdsTable Edit method exclusive lock — the same exclusive record lock that must be released by calling Cancel on every failure path, structurally identical to Clarion’s TryLock / Release requirement. Progress OpenEdge ABL developer retainers cover the Progress ABL FIND FIRST EXCLUSIVE-LOCK without RELEASE pattern — the same lock not released on the failure branch, the same production lock-wait errors invisible in single-user development testing, the same root cause (explicit lock held beyond the minimum necessary scope). In each case, the retainer developer’s value is the same: understanding the platform’s locking API, auditing every lock acquisition call for matching releases on all control flow paths, diagnosing production contention using the platform-specific diagnostic tools, and adding the missing release calls in the correct locations.

FAQ: Clarion developer retainers

What does a Clarion developer on retainer typically do?

A Clarion developer on monthly retainer covers TPS file record lock audits (reviewing every procedure or window embed that calls ACCESS:SomeFile.TryLock(Record) to confirm that every failure branch, early return, and loop-exit path calls ACCESS:SomeFile.Release() before continuing); lock contention diagnosis (identifying which Clarion station holds a TPS record lock by running the TpsFileInfo utility on the shared TPS file, tracing the holding application thread to the procedure that called TryLock without a subsequent Release on the failure path, and adding the Release call before every RETURN and every MESSAGE-and-next-iteration path); Clarion ABC template embed point maintenance (updating window procedures, form embeds, and process procedures using the Clarion IDE’s embed tree, modifying the data dictionary for new field requirements, and rebuilding the application without triggering unnecessary template regeneration); Clarion version migration (migrating Clarion 6 or 7 applications to Clarion 10 or 11, updating deprecated ABC class property accessors, and validating each browse and form window for functional equivalence); and TPS-to-SQL backend migration for clients who need higher concurrency, multi-site access, or cloud deployment.

What Clarion lock debugging work is most commonly underlogged?

TPS record lock bugs caused by ACCESS:SomeFile.Release() missing on failure branches are the most systematically underlogged Clarion retainer work. The pattern: a Clarion window procedure calls ACCESS:CustomerFile.TryLock(Record) to acquire an exclusive TPS record lock; the developer tests the procedure on a single workstation; in production, a validation failure causes the procedure to call MESSAGE + RETURN without calling Release; the TPS record lock on the customer record is held for the operator’s full session; other operators attempting to access the same record receive “Record is locked by another user”; the IT contact resolves each incident by asking the holding operator to restart Clarion, which releases all TPS locks for that session. The work log must name the procedure, the TryLock call site, the specific failure branch that returned without releasing, the number of operators affected, and the lock contention rate before and after the Release fix.

What are typical Clarion developer retainer rates?

Entry-level Clarion developers with experience in Clarion ABC application templates, TPS file drivers, basic window procedure embed points, and Clarion form validation logic typically bill at $55 to $90 per hour. Mid-level Clarion developers with experience in Clarion TPS file locking (ACCESS:File.TryLock, Release), HAND template embed code for custom lock management, Clarion SQL driver configuration, and Clarion 10/11 migration from Clarion 6/7 applications typically bill at $80 to $140 per hour. Senior Clarion developers with deep knowledge of Clarion TPS file internals (B-tree structure, record-level versus file-level locking, lock table limits), Clarion ABC class library architecture, multi-DLL application structure, and production lock forensics via the TopSpeed TPS file utilities and Clarion trace logging typically bill at $120 to $200 per hour. Monthly retainer ranges: $1,600 to $2,800 per month for advisory engagements covering TPS lock audits and Clarion version migration scoping; $2,500 to $4,500 per month for active Clarion application maintenance, template modification, and TPS-to-SQL migration work.

What should a Clarion developer retainer agreement include?

A Clarion developer retainer agreement should specify: Clarion version (Clarion 6, 7, 8, 9, 10, or 11 — each version has different ABC class library versions, embed point naming conventions, and IDE capabilities); the file driver in use (TPS for TopSpeed flat-file storage, or SQL driver for SQL Server, MySQL, or Oracle backends); whether the retainer developer has access to the Clarion application source (the .app file, the data dictionary .dct file, and all embedded source modules); whether the retainer covers TPS record lock audits (reviewing every ACCESS:File.TryLock call site for matching Release calls on all failure branches); the scope of Clarion ABC class customization (whether the retainer includes modifying derived AppFrame or Window Manager classes for custom locking policies); and whether the retainer includes TPS-to-SQL migration scoping for clients who need to move from TopSpeed flat-file storage to a SQL backend.

How should Clarion developer retainer hours be logged?

Log each Clarion retainer session with the application name, the Clarion version, the procedure or embed point affected, the specific issue, and the before/after outcome metric. For TPS record lock not released on failure: application name (OrderEntry.app), Clarion version (11), procedure name (ProcessOrderWindow), TryLock call site (ACCESS:CustomerFile.TryLock(Record) at Accept embed line 31), failure branch that skipped Release (credit validation failure: MESSAGE + RETURN at line 47), concurrent operators affected (3 operators holding TPS locks on 3 customer records for the full shift), lock contention errors reported per shift before fix (8–12, “Record is locked by another user”), diagnostic evidence (TpsFileInfo showing 3 locked record entries in CUSTFILE.TPS, machine names matching 3 affected operators), fix (ACCESS:CustomerFile.Release() added before MESSAGE + RETURN on credit failure branch and before all other early exits in the TryLock span), lock contention errors per shift after fix (0), hours (3h). For TPS-to-SQL migration: application name, TPS file count, SQL backend target, driver configuration, lock model change validated, hours.