home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / srev13g.zip / SREFQUE.DOC < prev    next >
Text File  |  1998-07-14  |  31KB  |  746 lines

  1. 15 Apr 1998: SREF_QUEUE: Working with SRE-http queues.
  2.  
  3. Abstract: SREF_QUEUE is an SRE-http "macrospace" procedure that allows you to
  4.           work with "SRE-http queues".  These queues provide
  5.           a convenient, queue-like means of storing and sharing data
  6.           in a globally accessible, semi-permanent location.
  7.  
  8.  
  9.                      Table of Contents
  10.  
  11. I.          Introduction
  12. II.         The SREF_QUEUE procedure
  13. II.a         SREF_QUEUE actions
  14. II.a.1           POP and READ
  15. II.a.1.i           The TYPE modifer
  16. II.a.1.ii          The INFOFIELD modifer
  17. II.a.1.iii         Examples
  18. II.b            FIND
  19. II.c            PUSH and QUEUE
  20. III.        The INIT, KILL, LOCK and INFO actions
  21. III.a         INIT
  22. III.b         KILL
  23. III.c         INFO
  24. III.d         LOCK
  25. IV.         Examples
  26. V.          Using SREF_QUEUE with a dedicated daemon
  27. Appendix 1. SREF_QUEUE error codes   
  28.  
  29.                         --------------------
  30.  
  31. I. Introduction
  32.  
  33. SRE-http (as of ver 1.2L) supports a flexible form of "queue". 
  34. The primary purpose of these SRE-http queues is to store and retrieve 
  35. information in a globally accessible, semi-permanent location. In many ways, 
  36. they are functionally similar to REXX queues, but are much more easily
  37. manipulated. 
  38.  
  39. SREF_QUEUE "macrospace" procedure is primarily meant to be used by SRE-http 
  40. addons that have light to moderate needs (for passing and storing data).
  41. If you have more substantial needs, you might want to use regular REXX queues, 
  42. or create an SRE-http daemon (see DAEMONS.DOC for a discussion of how 
  43. to work with SRE-http daemons). Another interesting possiblity is the SRE-Data
  44. addon; which is designed to perform fast lookup in fairly large, 
  45. static datasets.
  46.  
  47. To support these queues, SRE-http uses it's "variable storage daemon". This 
  48. introduces a few drawbacks:
  49.    >  when GoServe shuts down, SRE-http queues disappear.
  50.    >  The variable storage daemon services a number of SRE-http needs; 
  51.       if an SRE-http queue is heavily used, other SRE-http functions will 
  52.       be impacted.
  53. The latter problem can be partially overcome by starting multiple 
  54. "variable storage" daemons.  This does require some special configuration;
  55. which is discussed in section V below. 
  56.  
  57.                         --------------------
  58.  
  59. II. SREF_QUEUE
  60.  
  61. The SREF_QUEUE procedure is used to access and manipulate SRE-http queues. 
  62.  
  63. SREF_QUEUE is called as:
  64.     
  65.       retvalue=SREF_QUEUE(queueName,action,value,port)
  66.  
  67. where:
  68.    queuename: The name of a queue; it can be any REXX-style, variable name.
  69.               Queueame can also contain a daemon identifier, in which
  70.               case quenamename will be of the form: name.daemon_id
  71.       action: Type of action. and list of modifier. Valid actions include:
  72.                  INIT, INFO, LOCK, PUSH, POP, READ, FIND, and KILL.
  73.        value: The record to be added (used with PUSH, FIND, and INFO)
  74.         port: Used when SREF_QUEUE is called from an external process (i.e;
  75.               not from a thread or child-process of GoServe).
  76.               Port should be the port that GoServe/SRE-http is running under 
  77.               (typically, port=80).
  78.  
  79. The action parameter consists of an action, plus an optional list of modifiers. 
  80. The POP, READ, FIND, QUEUE and PUSH actions are described in section II.a to II.c.
  81. Section III discusses the KILL, INIT, LOCK and INFO actions; and section IV
  82. contains a simple example.
  83.  
  84. Summarizing what follows, to use SREF_QUEUE you should:
  85.   1) Initialize a queue using INIT. 
  86.   2) Write to a queue using PUSH and QUEUE.
  87.      Read from a queue using FIND, POP or READ.
  88.      Administer a queue using the LOCK and INFO
  89.   3) Stop a queue using the KILL action
  90.  
  91.  
  92.                         --------------------
  93.  
  94. II.a: The action parameter:
  95.  
  96. The action is used to specify what you want to do with an SRE-http queue.
  97. It consists of two components: the action, and a list of modifiers.
  98.  
  99. There are five read/write actions: POP, READ, FIND, QUEUE, and PUSH
  100. There are four administrative actions: INIT, INFO, LOCK, and KILL.
  101. The modifiers (there can be several) depend on the action. 
  102.  
  103. Notes:
  104.    *  At it's simplest, without specifing modifiers, using POP and QUEUE
  105.       will create a LIFO (last in,first out) queue.
  106.    *  The actions and modifiers should be seperated by spaces. The "action"
  107.       should ALWAYS be first, but the modifiers can appear in any order.
  108.    *  Several of the actions and modifiers can contain an = sign, followed
  109.       by a value. This = sign should NOT be surrounded by spaces.
  110.       For example: REC=19 is okay, REC= 19  is bad.
  111.    
  112.  
  113. For most of these actions, a string (text or binary), or a numeric count,
  114. will be returned. If an error occurs, either an empty string or a negative valued 
  115. error code will be returned.  Appendix 1 summarizes the error codes.
  116.  
  117. II.a.1. POP and READ
  118.  
  119. POP will "read and remove" a record, while READ will "read and retain" 
  120. a record.  Otherwise (with a few small exceptions) they are similar.
  121. You can POP (or READ) from the top of a queue, the bottom of a queue.
  122. You can also POP (or READ) multiple records; either explicitily specified,
  123. or based on a timespan.
  124.  
  125. POP and READ can have two modifiers: a TYPE and an INFOFIELD.
  126.   TYPE:  The location and size of the POP or READ. Valid TYPEs are:
  127.           TOP, BOTTOM, TOP=nnn, BOTTOM=nnn, NEWEST=ttt, OLDEST=ttt, and  REC=nnn
  128.   INFOFIELD: The information to be returned. Valid INFOFIELDs are:
  129.           VALUE, TIME, SIZE, NOREAD, and #RECORDS 
  130. Note that the default TYPE is TOP, and the default INFOTYPE is VALUE.
  131. Also, REC=nnn can only be used with READ.
  132.  
  133. II.a.1.i: The TYPE modifier
  134.  
  135. The TYPE modifiers have the following effects:
  136.  
  137.        TOP : Read  one record from the top of the queue
  138.      BOTTOM: Read  one record from the bottom of the queue
  139.    TOP=nnn : Read  nnn records from the top of the queue.
  140.                For example, TOP=3 will read (and remove) the top 3 records.
  141.                Note that TOP=1 and TOP have the same effect
  142.  BOTTOM=nnn: Read  nnn records from the bottom of the queue
  143.                Note that BOTTOM=1 and BOTTOM have the same effect
  144.  NEWEST=ttt: Similar to TOP=nnn, but ttt refers to a time offset.
  145.               Thus, records written (to the top) within ttt (of the 
  146.               current time) will be read (and removed).
  147.               ttt should contain a value and a time unit: where the case-
  148.               insensitive time unit is D,H,M or S (for days, hours, minutes
  149.               or seconds). For example:  0.042D=1H=60M=3600S.
  150.  OLDEST=ttt : Similar to NEWEST=ttt, but from the bottom of the queue,
  151.               and using the "queue creation time" as the reference time.
  152.   REC=nnn :   Read from the nnn'th record: from the top if nnn<0 
  153.               or from the bottom if nnn>0. For example:
  154.                  READ REC=-1 is the same as READ TOP
  155.                  READ REC=-2 will read the 2nd record from the top
  156.                  READ REC=1 is the same as READ BOTTOM
  157.  
  158. Removing versus Retaining:
  159.   POP will read and REMOVE records; while READ will read and RETAIN
  160.   records. Thus, multiple calls to READ will return the same record (say,
  161.   the top record), while multiple calls to POP will return progressively 
  162.   older records (until the queue is empty).
  163.   To READ progressively older records (without removing), you can increase (or
  164.   decrease) the nnn in a series of READ REC=nnn calls.  That is, use 
  165.   READ REC=-1, READ REC=-2, etc. Note that you may want to LOCK the queue
  166.   first (see section III for a discussion of queue LOCKing).
  167.  
  168. Multiple record returns:
  169.   For multiple record returns, each record will be delimited by a 
  170.   CRLF ('0d0a'x). If your records are multi-line records, or contain
  171.   binary information, this will cause problems. You can work around this
  172.   by setting an alternate DELIMiter when you INITialize
  173.  
  174. No data results:
  175.     >  If the SRE-http queue is empty, an empty string or a -3 error
  176.        code is returned.
  177.     >  If the NEWEST (or OLDEST) record is older (newer) then specified
  178.        (as set by the value), then an empty string is returned (or 
  179.        a -9 error code).
  180.  
  181. Multiple record READs and POPs:
  182.     >  By default, when a "multiple record request" is made (such as TOP=5), then 
  183.        CRLFs ('0d0a'x) are used to seperate records when. For binary records, 
  184.        or for multiple-line records, this will clearly cause problems.
  185.        You can work-around this dilemna by setting a queue-specific DELIMiter
  186.        when you INITialize.
  187.     >  If you ask for more records then exist, all records will be 
  188.        returned (you can use the INFO action to get the length of an SRE-http 
  189.        queue).
  190.     >  For TOP or NEWEST: the topmost records are written first
  191.        For BOTTOM or OLDEST: the bottommost records are written first
  192.     >  To extract records from the value returned, you can use:
  193.            mm=0  ; dlm='0d0a'x
  194.            do until value=""
  195.                  parse var value aline (dlm) value
  196.                  mm=mm+1; stuff.mm=aline
  197.            end
  198.  
  199.  
  200. II.a.1.ii: The INFOFIELD  modifier
  201.  
  202. You can specify a VALUE, TIME, SIZE, #RECORDS or NOREAD 
  203. INFOFIELD modifiers.  These effect what information is returned.
  204. Bot READ and POP recognize the same INFOFIELD delimiters:
  205.  
  206.    VALUE : Return the value of the record(s). Note that records may be
  207.            of any length, and may be text or binary.  
  208.       ID : Return the value of the ID field.
  209.    TIME  : The time the record was written,as an absolute date. For example:
  210.             13:33:51 21 Nov 1997 will yield 729348.56517
  211.     SIZE : Size of the record, in bytes
  212. #RECORDS : A count of the number of records that would be returned.
  213.             This is designed to be used with READ NEWEST and READ OLDEST --
  214.             it tells you how many records are newer (or older)
  215.             then the specified timespan. And if used with POP, it's 
  216.             a quick way of removing too new (or too old) records.
  217.   NOREAD : Used with POP. 
  218.            POP the record(s), but don't bother returning any information.
  219.            This speeds up removal of records from the queue, since SREF_QUEUE
  220.            won't wait for a status message to be returned from the
  221.            storage daemon.  However, this means that several errors will
  222.            not be reported; thus, NOREAD should be used with some caution.
  223.  
  224. A Shortcut: You can use STRIP as a short hand for POP NOREAD.
  225.  
  226. II.a.1.iii Examples of POP and READ
  227.  
  228. a=sref_queue('myqueue','POP TOP')
  229. a=sref_queue('myqueue','POP TOP VALUE ')       -- this is the same as POP TOP
  230. a=sref_queue('myqueue','POP NEWEST=30s')
  231. a=sref_queue('myqueue','POP BOTTOM=6 ')
  232. a=sref_queue('myqueue','POP TOP TIME')
  233. a=sref_queue('myqueue','READ REC=1')
  234. a=sref_queue('myqueue','READ BOTTOM REC=3')
  235. a=sref_queue('myqueue','READ OLDEST=1h #RECORDS')
  236. a=sref_queue('myqueue','READ TOP=5 SIZE ')     -- 5 sizes, seperated by CRLFS      
  237. a=sref_queue('myqueue','POP NOREAD TOP ')      -- removes top record
  238. a=sref_queue('myqueue','STRIP')                -- same as POP TOP  NOREAD
  239.  
  240.  
  241. II.a.2: FIND
  242.  
  243. FIND is used to search the queue for a match.  By default, it will search
  244. the "ID" field (that can be optionally set when you PUSH or QUEUE a
  245. record).  However, it can also be used to search the "values" of the
  246. records (but the search will be slower).
  247.  
  248. FIND can have a TYPE, ID, MATCH, and INFOFIELD modifiers. You MUST also
  249. specify a "value" parameter containing the string (text or binary) to search for.  
  250. Based on the TYPE and INFOFIELD modifiers, the first match will be returned.
  251.  
  252. The valid TYPE modifiers are:
  253.        TOP  : Start search from the top of the queue.
  254.      TOP=nnn: Start search from the nnn'th record (inclusive), where
  255.               nnn=1 means "top of the queue".
  256.  
  257.       BOTTOM: Start search from the bottom of the queue.
  258.   BOTTOM=nnn: Start search from the nnn'th record (inclusive), where
  259.               nnn=1 means "bottom of the queue".
  260. Note that if the TYPE modifier is not specified, TOP is assumed.
  261.  
  262. The ID modifier is used to select whether to search the ID or "value" fields
  263. of the record. 
  264.     ID=YES : search the ID field
  265.     ID=NO  : search the "value" of the record
  266. By default, ID=YES is used.
  267. Note that when searching the ID, a case insensitive search is used. When
  268. searching the "value" field, a case sensitive search is used.
  269.  
  270. The MATCH modifier is used to set what kind of search to perform. 
  271.    MATCH=EXACT   : Exact match.
  272.    MATCH=PARTIAL : Case insensitive partial match -- can match any substring
  273.                    (note that ID searchs are always case insensitive).
  274.    MATCH=WILD    : Wildcard match -- * characters will be used to do a
  275.                    wildcard match.
  276. Note that the default is EXACT. Although WILD= is fairly powerful (you can
  277. have multiple *s), it's somewhat slower; in many cases PARTIAL can be used 
  278. instead. 
  279.  
  280. The INFOFIELD modifier dictates what information should be returned
  281. (see the descriptions of the READ and POP INFOTYPE modifier for 
  282. further details):
  283.    VALUE: Return the value of the record.   
  284.     TIME: The time the record was written,as an absolute date.
  285.     SIZE: Size of the record, in bytes
  286.       ID: Id of the field 
  287.      REC: Record number of the match (from the bottom if READ BOTTOM,
  288.           otherwise from the TOP). Can be used with READ REC= to directly 
  289.           query the record (after you've found a match), or as a base
  290.           for another search (i.e.; add 1 and use in TOP=nnn).
  291. Note that if the INFOFIELD modifier is not specified, VALUE is assumed.
  292.  
  293. The "value" parameter should contain the string to search for.
  294. This string will be compared against the ID field, or the "value" field, of
  295. each record, with the first match returned.
  296.  
  297.  
  298. Examples:
  299.   a=sref_queue('myqueue','FIND','MY_DAD ')
  300.   a=sref_queue('myqueue','FIND BOTTOM TIME ID=NO MATCH=PARTIAL ','chevy')  
  301.   a=sref_queue('myqueue','FIND BOTTOM=10 TIME ','WILD=*TRUCK*')  
  302.  
  303.  
  304. II.a.3: PUSH and QUEUE
  305.  
  306. PUSH and QUEUE are used to place records on the queue. You can add a record 
  307. to the top or bottom of the queue. 
  308.  
  309. The action parameter consists of a TYPE and several OPTIONs. With PUSH the 
  310. TYPES are TOP, BOTTOM and REC=nnn. The OPTIONS include QUICK, REMOVE, and ID.
  311.  
  312. QUEUE is actually a shorthand for PUSH BOTTOM -- hence, no TYPE is needed.
  313.  
  314. In addition to the action, you must specify a value parameter. The value
  315. parameter can be any text or binary string.  
  316.  
  317. TYPEs for PUSH:
  318.       TOP: Write a record to the top of the queue.
  319.    BOTTOM: Write a record on the bottom of the queue. Note that QUEUE = PUSH BOTTOM
  320.   REC=nnn: Write to record nnn; where nnn=1 is the bottom, and
  321.            nnn=-1 is the top. 
  322.  
  323. Note that if a PUSH actions has no TYPE modifier, TOP is assumed. 
  324. A TYPE should never be used with QUEUE -- QUEUE always means PUSH BOTTOM!
  325.  
  326.  
  327. OPTIONS for PUSH and QUEUE:
  328.     QUICK: Do not wait for a response from the variable storage queue.
  329.            This speeds things up a bit, but is somewhat riskier
  330.            (since errors are more likely to be undetected).
  331.  
  332.    REMOVE: If the queue currently has it's maximum value of records
  333.            (as specified by the INIT action) remove a record and then
  334.            write this record.
  335.            If REMOVE is not specified, a "can't write new record"
  336.            error is returned.
  337.            The record removed will be at the "other end" of the queue. Thus,
  338.            PUSH TOP REMOVE may cause the bottom record to be removed; while
  339.            PUSH BOTTOM REMOVE (or QUEUE REMOVE) may cause the top record to be 
  340.            removed.
  341.  
  342.    ID=xxx: Set the ID field for this record with value xxx.
  343.            xxx can be any length text string, but can not contain 
  344.            spaces or CRLFs. We recommend keeping it relatively short
  345.            (say, less than 30 characters).
  346.            The ID field is used with the POP and READ "ID" INFOTYPE, 
  347.            and can be searched by the FIND action.
  348.  
  349. Caution concerning PUSH REC=nnn
  350.   As with READ REC=nnn, the sign of nnn determines whether the record
  351.   is determined from the top or bottom of the queue.
  352.   As a relative number (from the top or bottom), additions/subtractions
  353.   from the queue will change a record's REC number.
  354.   This can cause unexpected problems in cases where multiple threads have 
  355.   access to the queue.
  356.          Therefore, you may want to LOCK the queue before using 
  357.          PUSH REC=nnn and READ REC=nnn.
  358.  
  359. Time of Creation:
  360.     When you PUSH or QUEUE stores a record, the current time is also stored
  361.     (accurate to about 1 second).  READ NEWEST=ttt and POP NEWEST=ttt use 
  362.     this to selectively return a set of records -- all records stored within 
  363.     a specified timespan will be returned.
  364.  
  365. Examples:
  366.  
  367. a=srefqueue('myq','PUSH TOP', ' this is a record on the top')
  368. a=srefqueue('myq','QUEUE ',' this is a bottom record')
  369. a=srefqueue('myq','PUSH TOP ID=MY_DAD',birthday)
  370. a=srefqueue('myq','PUSH BOTTOM QUICK','store me, and move on ')
  371. a=srefqueue('myq','PUSH REMOVE',' store me, and make room ')
  372. a=srefqueue('myq','PUSH REC=10  ID=TENTH_VICTIM ',' replace the 10th record')
  373.  
  374.                         --------------------
  375.  
  376. III. INIT, KILL, INFO and LOCK
  377.  
  378. III.a. INIT
  379.  
  380. The INIT action is used to initialize a queue, and to set a few INIT_OPTIONS.
  381. The INIT_OPTIONS should be set in the "value" parameter; and may include any
  382. or all of the following:
  383.  
  384.    SIZE=nnn : Maximum size of the queue (in records). Thus, SIZE=100
  385.               means "no more then 100 records". 
  386.               SIZE=0 means "no limit"
  387.  
  388.  LIFESPAN=ttt : Clear out records with that are older then lifespan.
  389.                 As with other SREF_QUEUE timespans, you can specify
  390.                 days, hours, minutes or seconds (i.e.; 1D=24M=3600M).
  391.                 LIFESPAN=0 means "indefinite lifespan".
  392.                 Caution:
  393.                    To save time, LIFESPAN will only check from the
  394.                    bottom of the queue up; and stop when it hits a
  395.                    "still alive" record. Thus, LIFESPAN should NOT be
  396.                    used for queues that will have records added to the
  397.                    bottom!
  398.  
  399.    DELIM=ppp :  Specify an alternate delimiter to use to seperate records
  400.                 on multiple-record returns. By default, a CRLF ('0d0a'x) is
  401.                 used.  If you have multiple-line records, or binary records,
  402.                 this can cause problems.  The use of an alternate "delimiter"
  403.                 can often offer a workaround (so long as you know that the
  404.                 alternate delimiter is never used in the records!).
  405.                 Note that ppp MUST be a "packed 64" string.  You can 
  406.                 use SREF_MKPACK64 to create such a string. For example:
  407.  
  408.                    mydelim='0d0a'x||' &&%**%&& '||'0d0a'x
  409.                    ppp=mk_pack64(mydelim)
  410.                    foo=sref_queue('ourqueue','INIT ','DELIM='||ppp)
  411.                 and then use mydelim when parsing multiple line returns
  412.                    (that is, do NOT use ppp; ppp is only used to transfer 
  413.                     information to SREF_QUEUE).
  414.                   
  415.                 
  416. By default, SIZE=0, LIFESPAN=0 and DLM='0d0a'x
  417.  
  418. Examples:
  419.  
  420.    Set up an unlimited length queue named 'myqueue_1'
  421.       status=SREF_QUEUE('myqueue_1','INIT')
  422.  
  423.    Set up an 100 record (maximum) queue with the name 'his_queue', and
  424.    automatically remove records older then 1 hour.
  425.       status=SREF_QUEUE('his_queue','INIT',' size=100 lifespan=1h ')
  426.         
  427. The returned value (status) will be 1 if success, and a negative number if 
  428. an error occured. Error codes include:
  429.    -5 : Queuename already exists
  430.   -10 : Queue not specified
  431.   -187: System error.
  432.  
  433. Notes:
  434.   * When a maximum is hit...
  435.     If REMOVE is not a PUSH (or QUEUE) OPTION:
  436.        then additional records will not be accepted -- and a -8
  437.        error code is returned.
  438.        You'll have to  POP  open a space on the queue.
  439.  
  440.     If REMOVE is a PUSH OPTION
  441.        then a record will be removed from the "other end" -- 
  442.        for example: for PUSH TOP, a record will be removed from the
  443.        bottom end (the new record being added to the top).
  444.  
  445.   * If you write to a queue without initializing, a new queue will be created
  446.     with unlimited length, infinite lifespan, and a CRLF delimiter.
  447.  
  448.   * When you INITialize a queue, the "creation time" is recorded. The "creation
  449.     time" is used with READ OLDEST. Note that the creation time can not 
  450.     be changed (short of KILLing and reINITializing the queue).
  451.  
  452.   * Removal of "older then lifespan" records occurs after every PUSH 
  453.     (or QUEUE). As noted above, a "work from the bottom up until
  454.     you hit a live record" algorithim is used -- thus, if you add records
  455.     to the bottom of a queue, LIFESPAN will have unexpected consequences.
  456.  
  457.                         --------------------
  458.  
  459. III.b KILL
  460.  
  461. KILL is used to end a queue. Use KILL to save resources.
  462.  
  463. Example:
  464.     status=sref_queue('myqueue','KILL')
  465. will kill the myqueue SRE-http queue.
  466.  
  467. The returned value will equal the number of records that were in
  468. the queue. If an error occurs, a negative value will be returned.
  469. Error codes include:
  470.    -1 : No such queuename
  471.   -10 : Queue not specified
  472.  
  473. Note that anyone call kill an SRE-http queue -- SRE-http queues are not 
  474. "owned" !
  475.  
  476.                         --------------------
  477.  
  478. III.c INFO
  479.  
  480. INFO is used to obtain info about the SRE-http queue. The value parameter is 
  481. used to specify what to get. Valid values are:
  482.    RECORDS  : # of records in queue; 0 if none.
  483.    SIZE     : Total storage, in bytes. 0 if no records, or if all empty
  484.                      records.
  485.    CREATION : Time of creation, in "julian" format. For example:
  486.                          13:33:51 21 Nov 1997 will yield 729348.56517
  487.     MAX     : Maximum size (0 if unlimited)
  488.     LOCK    : Return LOCKING status. If not locked, or if the LOCK has 
  489.               expire, a 0 is returned.  Otherwise, the current
  490.               key is returned (note that the default key is "1").
  491.  
  492. There several "summary of all queues" options. To uses these, queuename
  493. should be * (or *.daemon_id). These "summary options" are:
  494.    #QUEUES  : Number of queues
  495.    SIZE     : Size (in bytes) of all queues
  496.    NAMES    : Names of all the queues (in a space delimited list)
  497.  
  498. A negative returned value is used as an error code, including:
  499.    -1 : No such queuename
  500.    -4 : No such value parameter
  501.   -10 : Queue not specified
  502.  
  503. Examples:
  504.  
  505. To find the current number of records in the myqueue:
  506.    ngot=sref_queue('myqueue','INFO','Records')
  507.  
  508. To find the maximum size of myqueue:
  509.    maxsize=sref_queue('myqueue','info','max')
  510.  
  511. To list all currnently active queues:
  512.    nqueues=sref_queue('*','INFO','NAMES')
  513.  
  514.  
  515. III.d LOCK
  516.  
  517. The LOCK action is used to lock a queue; which means that records can
  518. not be added or removed. There are two variants of LOCK.
  519.    LOCK ON=aaa  : Lock a queue, with a key of aaa
  520. and 
  521.    LOCK OFF=aaa : Unlock a queue, using the aaa key.
  522.  
  523. The "aaa" key is optional; if not specified, a value of 1 is used. 
  524. Key's can be used to help independent processes know "who has locked the queue".  
  525. For example:
  526.   LOCK ON     : Lock the queue, using the default key (1).
  527.   LOCK ON=T1  : Lock the queue, using a key of T1
  528.   LOCK OFF=T1 : Unlock the queue IF it was locked with a key of T1
  529.   LOCK OFF    : Unlock the queue, regardless of what the key is.
  530. Thus, LOCK OFF is universal -- which means that anyone can unlock a
  531. queue!
  532.  
  533. When you LOCK a queue you can also specify, in the value parameter, a 
  534. timspan; after this timepspan the queue will be unlocked. If not
  535. specified, the queue will be locked indefinitely.  As with other SREF_QUEUE
  536. timespans (such as in POP NEWEST=ttt), a (case insensitive) D,H,M, or S 
  537. unit should be the last character of the timespan.
  538. For example, six hours can be spedified as: 0.25D, 6H, 360M, or 21600s 
  539.  
  540. Queue locking is most useful when used prior to a READ REC= and PUSH REC=
  541. (since it prevents additions to, and removals from, the queue; relative 
  542. positions will be stable). However, should a thread that locks a 
  543. queue fail/forget to unlock it, the queue will remain locked until
  544. the timespan expires (perhaps indefinitely), or until some other thread
  545. decides to unlock it (note that anyone can LOCK or UNLOCK a queue). 
  546. As mentioned above, in highly multi-threaded environments, the KEY
  547. can be used to help keep track of who's "locked" the queue.
  548.  
  549. LOCK will return a 1 for success (either locked or unlocked), or 
  550. a negatively valued error code: 
  551.    -1 : No such queuename
  552.   -10 : Queue not specified
  553.   -15 : Mismatched key (you can use INFO to find the current key)
  554.   -14 : Queue already locked
  555.  
  556. Examples: 
  557.  
  558.   astat=sref_queue('myqueue','LOCK ON','10s')
  559.   astat=sref_queue('myqueue','LOCK ON=T1')
  560.   astat=sref_queue('myqueue','LOCK OFF=T2')
  561.   astat=sref_queue('myqueue','LOCK OFF')
  562.  
  563.                         --------------------
  564.  
  565. IV: An Example
  566.  
  567. **** The following is an SRE-http addon that provides a useless demonstration:
  568.  
  569. parse arg  ddir, tempfile
  570.  
  571. myq='myqueue'
  572. a1=sref_queue(myq,'INIT 100')   /* initialize a queue, max of 100 records */
  573.  
  574.  
  575. call lineout tempfile,' Sample results '
  576. call lineout tempfile,' '
  577. if a1<0 then call lineout tempfile,' Warning: queue exists '
  578. call lineout tempfile,' '
  579. call lineout tempfile, ' loading ... '
  580. aa=sref_queue(myq,'PUSH ','This is line 1')
  581. call lineout tempfile," PUSH result= "aa
  582.  
  583. aa=sref_queue(myq,'PUSH ID=GREAT_1 ','This is line 2 ')
  584. call lineout tempfile,' PUSH ID result = 'aa
  585.  
  586. aa=sref_queue(myq,'QUEUE ID=BOT_ONE ','This is line zero')
  587. call lineout queuefile', QUEUE result= ' aa
  588. call lineout tempfile, ' '
  589. call lineout tempfile, ' retrieving ... '
  590.  
  591. in=sref_queue(myq,'INFO','SIZE')
  592. call lineout tempfile,' INFO SIZE='in
  593.  
  594. w1=sref_queue(myq,'FIND BOTTOM  ','GREAT_1')
  595. call lineout tempfile,' FIND ID = ' w1
  596.  
  597. b1=sref_queue(myq,'POP')
  598. b2a=sref_queue(myq,'READ BOTTOM SIZE')
  599. b2b=sref_queue(myq,'READ BOTTOM')
  600. b2ba=sref_queue(myq,'READ BOTTOM SIZE')
  601. b2bb=sref_queue(myq,'READ BOTTOM TIME')
  602. b2bc=sref_queue(myq,'READ BOTTOM ID')
  603.  
  604. b3=sref_queue(myq,'POP top=2')
  605. b4=sref_queue(myq,'READ')
  606.  
  607. call lineout tempfile,' POP result=' b1
  608. call lineout tempfile,' READ BOTTOM SIZE=' b2a
  609. call lineout tempfile,' READ BOTTOM (val,size,time,id) = ' b2b', 'b2ba', 'b2bb', 'b2bc
  610. call lineout tempfile,' POP top=2 = ' b3
  611. call lineout tempfile,' READ = ' b4
  612. call lineout tempfile
  613. 'FILE ERASE type text/plain name ' tempfile
  614. return 'test queue '
  615.  
  616. **** Will return:
  617.  
  618.  Sample results 
  619.  
  620.  Warning: queue exists 
  621.  
  622.  loading ... 
  623.  PUSH result= 1
  624.  PUSH ID result = 1
  625.  
  626.  retrieving ... 
  627.  INFO SIZE=45
  628.  FIND ID =  This is line 2
  629.  POP result= This is line 2
  630.  READ BOTTOM SIZE= 17
  631.  READ BOTTOM (val,size,time,id) =  This is line zero, 17, 729352.04117, BOT_ONE
  632.  POP top=2 =  This is line 1
  633. This is line zero
  634.  READ =  
  635.  
  636.  
  637.                         --------------------
  638.  
  639. V: Running SREF_QUEUE with a dedicated daemon
  640.  
  641. As mentioned in the introduction, SREF_QUEUE uses the SRE-http "variable
  642. storage daemon" to store SRE-http queues.  This daemon also provides a number
  643. of other services to SRE-http, such as "variable storage" and storage for
  644. the "hit cache".  Thus, heavy use of SREF_QUEUE (such as extensive
  645. ID searches) may adversely impact the performance of other SRE-http functions;
  646. hence reponse time for other requests (that have nothing to do with the 
  647. SRE-http queues).
  648.  
  649. In order to avoid some of these problems, you may want to use a seperate
  650. "daemon" for SRE-http queue storage.  In fact, you can even generate several
  651. queue storage daemons, with each of these daemons handling a subset
  652. of the SRE-http queues (in the extreme, you could have one daemon per
  653. SRE-http queue).
  654.  
  655. To do this requires two steps:
  656.   1) Changing the STORAGE_DAEMONS parameter
  657.   2) Modifying the queuename argument
  658.  
  659. The STORAGE_DAEMONS parameter (which is set in SREFMON.CMD) controls how
  660. many instances of the SRE-http "variable storage" daemon are launched.
  661. By default (STORAGE_DAEMONS=1) a single instance is launched. Increasing 
  662. this parameter will increase the number of "variable storage daemons" 
  663. launched. That is, when STORAGE_DAEMONS=3, then 3 instances of this daemon 
  664. are launched.
  665.  
  666. Note that these daemons are functionally independent -- they do NOT share
  667. data storage.  Thus, when using an particular SRE-http queue, you have to 
  668. decide which "instance" of the daemon to use, and stick with this decision.
  669.  
  670. Given that multiple storage daemons are avaiable, you can dictate
  671. which one to use by appending (after a .) a daemon_id to the end of the 
  672. queuename.  The daemon_id is simply a number between 1 and STORAGE_DAEMONS.
  673.  
  674. Example: to initialize the "myqueue" SRE-http queue under the number 2 daemon,
  675.          and then PUSH a record:
  676.  
  677.      stat=sref_queue('myqueue.2','INIT')
  678.      if stat>0 then do
  679.          stat2=sref_queue('myqueue.2','PUSH','Hello world')
  680.      end
  681.  
  682. Notes:
  683.  *   queuename.1 is the same as queuename -- the "number 1 daemon" is always 
  684.      the default daemon.
  685.  *   if you specify a non-existent daemon id, an error will occur; with
  686.      either an empty string returned, or a -187 error code.
  687.                         --------------------
  688.  
  689. Appendix 1. SREF_QUEUE Error codes
  690.  
  691. Error codes will be returned when some kind of error occurs. Their
  692. values will depend on what action was requested.
  693.  
  694. action=READ, FIND or POP
  695.  
  696.    If INFOFIELD=VALUE
  697.       For all errors, an empty string is returned. 
  698.  
  699.    If INFOFIELD=SIZE, ID, TIME, RECNUM
  700.        -1 = no such queuename
  701.        -2 = no such record (only used with READ REC)
  702.        -3 = empty queue
  703.        -8 = bad value
  704.        -9 = no records within selected timespan (used with NEWEST and OLDEST)
  705.       -10 = queue name not specified
  706.       -11 = no id specified (only used with FIND)
  707.       -12 = no id match (only used with FIND)
  708.       -16 = FIND: offset > then # records in queue
  709.       -20 = queue locked (only used with POP)
  710.      -100 = no such modifier (2nd word not OLDEST NEWEST TOP or BOTTOM)
  711.  
  712. action=INIT
  713.        -5 = queuename in use
  714.        -6 = bad value for maximum size
  715.       -10 = queuename not specified
  716.  
  717. action=KILL or INFO
  718.        -1 = no such queuename
  719.        -4 = no such INFO value (not RECORDS CREATION MAX SIZE #QUEUES NAMES) 
  720.       -10 = queuename not specified
  721.  
  722. action=LOCK
  723.    -1 : No such queuename
  724.   -10 : Queue not specified
  725.   -15 : Mismatched key
  726.   -14 : Queue already locked
  727.  
  728. action=PUSH
  729.        -1 = no such queuename
  730.        -2 = no such record (used with PUSH REC)
  731.        -8 = no room left on queue
  732.       -10 = queuename not specified
  733.       -20 = queue locked
  734.  
  735. For all actions:
  736.   System errors cause a -187 to be returned.
  737.   System error include:
  738.      specifying a non-existent daemon_id that
  739.      could not create semaphore (used to communicate with daemon)
  740.      could not use semaphore
  741.      problem communication with daemon
  742.   Note that  when a system error occurs, error messages will be displayed
  743.   in the pmprintf window.
  744.  
  745.  
  746.