[
Table Of Contents
| Keyword Index
]
nsv(n) 4.99 "NaviServer Built-in Commands"
nsv - NaviServer nsv Commands
TABLE OF CONTENTS
SYNOPSIS
DESCRIPTION
COMMANDS
Migrating From ns_share
Multithreading Features
Compatibility with Tcl Arrays
Configuration
SEE ALSO
The nsv commands provide a high performance data sharing mechanism.
This facility is much flexible alternative to the obsolete ns_share
command. The model uses an array syntax and includes more features.
In addition, lock contention is managed in a much more scalable
way--something that is not possible with the obsolete ns_share
facility.
- nsv_array get array ?pattern?
-
- nsv_array set array value-list
-
- nsv_array reset array value-list
-
- nsv_array exists array
-
- nsv_array size array
-
- nsv_array names array ?pattern?
-
Commands for the most part mirror the cooresponding Tcl command for
ordinary variables.
| |
% nsv_array set shared_array { key1 value1 key2 value2 }
% nsv_array get shared_array
key1 value1 key2 value2
% nsv_array reset shared_array { key3 value3 }
% nsv_array exists shared_array
1
% nsv_array size shared_array
1
% nsv_array names shared_array
key3
% nsv_array set shared_array [array get tmp_shared_array]
% array set tmp_shared_array [nsv_array get shared_array]
% nsv_array reset shared_array [array get tmp_shared_array]
|
- nsv_exists array key
-
Test whether a key exists in the nsv array.
| |
% nsv_exists shared_array key1
1
% nsv_exists shared_array key2
0
|
- nsv_get array key
-
Get the value for the key from the nsv array. Error occurs if key does not exist.
| |
% nsv_get shared_array key1
value1
|
- nsv_incr arrayName key ?increment?
-
If increment is supplied then its value (which must be an integer) is added to the
value of the element key; otherwise 1 is added to the value of the element key.
Unlike the TCL equivalent if key does not exists it is created. Returns the new value
of the element specified by key. Internally interlocked so it is thread safe, no mutex required.
| |
% nsv_incr shared_array foo
1
% nsv_incr shared_array foo -1
0
|
- nsv_append array key value ?value ...?
-
Append all of the value arguments to the current value of variable key in the array.
If key doesn't exist, it is given a value equal to the concatenation of all the value arguments
| |
% nsv_append shared_array key1 foo
value1foo
|
- nsv_lappend array key value ?value ...?
-
Append all of the value arguments as list elements to variable key in the array.
If key doesn't exist, it is created as a list with elements given by the value arguments
| |
% nsv_lappend shared_array key1 value2
value1 value2
|
- nsv_names ?pattern?
-
Return a list of all the nsvs in use, optionally only those matching pattern. If no
matching nsvs are in use returns the empty string.
- nsv_set array key value
-
Set the value for a key in an nsv array. Returns the value the key is set to.
| |
% nsv_set shared_array key1 value1
value1
|
- nsv_unset array ?key?
-
Unset an array or a single key from an array. If successful returns an empty string.
| |
% nsv_unset shared_array key1
%nsv_unset shared_array
|
Migrating from ns_share is straightforward. If your init.tcl included commands such as:
| |
ns_share myshare
set myshare(lock) [ns_mutex create]
|
use instead:
| |
nsv_set myshare lock [ns_mutex create]
|
In your procedures, instead of:
| |
proc myproc {} {
ns_share myshare
ns_mutex lock $myshare(lock)
...
|
use:
| |
proc myproc {} {
ns_mutex lock [nsv_get myshare lock]
...
|
and within an ADP page, instead of:
| |
<%
ns_share myshare
ns_puts $myshare(key1)
%>
<%=$myshare(key2)%>
|
use:
| |
<%
ns_puts [nsv_get myshare key1]
%>
<%=[nsv_get myshare key2]%>
|
Notice that, unlike ns_share, no command is required to define the
shared array. The first attempt at setting the variable through any
means will automaticaly create the array. Also notice that only arrays
are supported. However, to migrate from ns_share you can simply package
up all existing ns_share scalars into a single array with a short name,
perhaps just ".". For example, if you had:
| |
ns_share mylock myfile
set myfile /tmp/some.file
set mylock [ns_mutex create]
|
you can use:
| |
nsv_set . myfile /tmp/some.file
nsv_set . mylock [ns_mutex create]
|
One advantages of nsv is built in interlocking for thread safety.
For example, consider a case of a "increment-by-one" unique id system.
Here's the ns_share solution:
| |
ns_share ids
set ids(lock) [ns_mutex create]
set ids(next) 0
proc nextid {} {
ns_share ids
ns_mutex lock $ids(lock)
set next [incr ids(next)]
ns_mutex unlock $ids(lock)
return $next
}
|
and here's an nsv solution:
| |
nsv_set ids next 0
proc nextid {} {
return [nsv_incr ids next]
}
|
Note that the nsv solution does not need a mutex as the nsv_incr command
is internally interlocked.
Another useful feature of nsv is the nsv_array command which works much
like the Tcl array command. This can be used to import and export values
from ordinary Tcl arrays. For example, to copy from Tcl use:
| |
nsv_array set meta [array get tmpmeta]
|
and to copy to Tcl use:
| |
array set metacopy [nsv_array get meta]
|
As with all other nsv command, nsv_array is atomic and no explicit
locking is required. This feature can be used to contruct a new nsv
array by first filling up an ordinary temporary Tcl array via some time
consuming process and then swapping it into place as above. While the
new temporary array is being constructed, other threads can access the
old array without delay or inconsistant data. You can even reset a
complete nsv array in one step with "reset". For example, instead of:
| |
ns_share lock meta
set lock [ns_mutex create]
ns_mutex lock $lock
unset meta
array set meta [array get tmpmeta]
ns_mutex unlock $lock
|
you can simply use:
| |
nsv_array reset meta [array get tmpmeta]
|
The reset option will flush and then reset all values atomically,
eliminating the need for the explicit lock.
The nsv system uses a common multithreading technique to reduce the
potential for lock contention which is to split the locks to acheive
finer grained locking. This technique groups arrays randomly into
buckets and only the arrays within a particular bucket share a lock.
The number of buckets to be used can be configured by setting the
"nsvbuckets" tcl parameters, e.g.:
| |
[ns/server/server1/tcl]
nsvbuckets=20
|
The default is 8 which should be reasonalbe. Note that you can monitor
the lock contention, if any, by enabling mutex metering:
| |
[ns/threads]
mutexmetering=on
|
and then viewing the results of "ns_info locks" command after the server
has been running for some time. The nsv locks all have names of the
form "nsv:##". If you find many lock attempts which did not successed
immediately, try increasing nsvbuckets.
nsd