Monthly Archives: May 2026

Dynamic arrays and offset caching

As you know, dynamic arrays in OpenInsight are internally represented as delimiter-separated strings commonly containing fields, values and sub-values. Traditionally, locating an element required scanning the string from the start to find the required delimiters at the specified index . This can be a performance issue on large arrays, so one of the new features we’ve added to OpenInsight 11 is index/offset caching.

This is a technique that involves caching the byte offsets of previously located field, value and sub-value indexes when you use the “<>” operators, and the Insert/Extract/Replace/Delete functions. This means that we don’t always have to start scanning from the beginning of the string each time an element is accessed.

For example, suppose field 67 is located at byte offset 234, and field 68 begins at offset 245.

  • Without caching, locating field 68 requires rescanning the dynamic array from the beginning to find all preceding field marks.
  • With caching, once field 67 has already been located, the search for field 68 can begin from offset 234 instead of offset 1.

This optimization is especially effective when forward-iterating through large dynamic arrays, where successive accesses are close together. In previous versions, repeatedly accessing successive fields could result in near O(n²) scanning behaviour for large arrays. Offset caching eliminates much of this repeated work.

Consider the following program which processes 10000 SYSOBJ keys:

compile function test_dyn_cache( void )
$insert rti_Struct_Equates
$insert logical
select @file_sysobj
eof = FALSE$
idList = ""
loop
readNext id else eof = TRUE$
until eof
idList := id : @fm
repeat
idList[-1,1] = ""
idList = field( idList, @fm, 1, 10000 )
ctr = fieldCount( idList, @fm )
pf = blank_Struct( "MSWIN_LARGE_INTEGER" )
pcStart = blank_Struct( "MSWIN_LARGE_INTEGER" )
pcEnd = blank_Struct( "MSWIN_LARGE_INTEGER" )
call msWin_QueryPerformanceFrequency( pf )
call msWin_QueryPerformanceCounter( pcStart )
for x = 1 to ctr
id = idList<x>
next
call msWin_QueryPerformanceCounter( pcEnd )
pcStart = struct_To_Var( pcStart, "MSWIN_LARGE_INTEGER" )
pcEnd = struct_To_Var( pcEnd, "MSWIN_LARGE_INTEGER" )
pf = struct_To_Var( pf, "MSWIN_LARGE_INTEGER" )
pcTime = ( ( pcEnd - pcStart ) * 1000 ) / pf
call send_Dyn( "TEST_DYN_CACHE processed " : ctr : " items -> " : pcTime : " ms" )
return ""

Running this benchmark on the same machine using v10.2.4 took approximately 360ms, while OpenInsight 11 completed the same test in around 1–2ms.

For small dynamic arrays the difference may not be noticeable, but performance improvements become increasingly significant as array sizes grow.

This means you can continue using the familiar “<>” syntax for sequential dynamic array processing without needing to rewrite code using LOOP/REMOVE or LOOP/[] parsing patterns.

Introducing OpenInsight 11

With the recent release of OI 10.2.4 it’s time to look ahead at OpenInsight 11 and some of the new features that will be heading your way with the next major release. We’ve been working on it for some time, with a focus on cloud-based features, and there’s plenty to talk about over the next few months as we get it ready, but in the meantime here’s a few highlights:

Revelation Application Server

This is a new native Windows Service application that can host one or more concurrent OpenInsight application instances in a variety of modes:

  • Background Task processing
  • Index Server processing
  • General-purpose “engine-server” with access via a Basic+/Windows DLL/.Net class library/Linux SO, Python wrapper etc.
  • Thin-Client mode for RTP57R (see below)
  • Web-CGI Server (Windows ISAPI, Linux S/CGI, FastCGI, CGI, PHP modules)
  • Internal Web Server with reverse proxying for use with Linux Ngnix/Apache, HTTPS and static file serving support.
  • MCP endpoint for AI access.

RTP57R – Cloud-Optimized Data Access

With the new Application Server we’ve introduced a specialized filing system driver engineered with the Thin-Client mode to meet the demands of distributed applications. As you know, when databases migrate to remote cloud servers and corporate WANs, connection stability and latency often become greater bottlenecks than raw bandwidth. RTP57R (the “R” stands for Remote) addresses these challenges by seamlessly offloading processing to the server when needed and minimizing “chatter” across the wire.

AI Integration

OpenInsight 11 will also feature AI integration features, including a “chat” interface to agentic AI that can be either self-hosted or available through subscription. The Application Server provides an MCP (Model Context Protocol) interface to expose tools and resources to an AI client – we provide a standard set of tools for stored procedure and general DB access, and you can define your own as well.

Basic+ DYNLIST data type

We’ve added a new data type called a “DynList” to Basic+. Basically this is similar to a dimensioned array but it can be resized at runtime. If you’re used to working with other languages then you can think of this as similar to a C++ vector or a C# List<> type etc. DynList variables can store other DynList variables so you can implement fully multi-dimensional data structures.

Basic+ JSON data type

We’ve also made JSON a first class citizen and implemented a set of new JSON functions into Basic+. OI10 included a set of JSON functions exported from RevJSON.dll, but there was always the issue of manual handle management, and some memory management issues. Having JSON in Basic+ removes these concerns.

And there’s more…

So that’s just a few new things that we can tell you about now, and of course there will be more work on improving the performance and functionality of other existing areas like the IDE, Form Designer and other tools. We’ll reveal more details in future posts.