summaryrefslogtreecommitdiff
path: root/qpid/doc/book/src/LVQ.xml
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/doc/book/src/LVQ.xml')
-rw-r--r--qpid/doc/book/src/LVQ.xml362
1 files changed, 362 insertions, 0 deletions
diff --git a/qpid/doc/book/src/LVQ.xml b/qpid/doc/book/src/LVQ.xml
new file mode 100644
index 0000000000..7c9f588c51
--- /dev/null
+++ b/qpid/doc/book/src/LVQ.xml
@@ -0,0 +1,362 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<section><title>
+ LVQ
+ </title>
+
+ <section role="h2" id="LVQ-UnderstandingLVQ"><title>
+ Understanding LVQ
+ </title>
+ <para>
+ Last Value Queues are useful youUser Documentation are only
+ interested in the latest value entered into a queue. LVQ
+ semantics are typically used for things like stock symbol updates
+ when all you care about is the latest value for example.
+ </para><para>
+ Qpid C++ M4 or later supports two types of LVQ semantics:
+ </para><itemizedlist>
+ <listitem><para>LVQ
+ </para></listitem>
+ <listitem><para>LVQ_NO_BROWSE
+ </para></listitem>
+ </itemizedlist>
+ <!--h2--></section>
+
+
+ <section role="h2" id="LVQ-LVQsemantics-3A"><title>
+ LVQ semantics:
+ </title>
+ <para>
+ LVQ uses a header for a key, if the key matches it replaces the
+ message in-place in the queue except
+ a.) if the message with the matching key has been acquired
+ b.) if the message with the matching key has been browsed
+ In these two cases the message is placed into the queue in FIFO,
+ if another message with the same key is received it will the
+ 'un-accessed' message with the same key will be replaced
+ </para><para>
+ These two exceptions protect the consumer from missing the last
+ update where a consumer or browser accesses a message and an
+ update comes with the same key.
+ </para><para>
+ An example
+ </para>
+ <programlisting>
+[localhost tests]$ ./lvqtest --mode create_lvq
+[localhost tests]$ ./lvqtest --mode write
+Sending Data: key1=key1.0x7fffdf3f3180
+Sending Data: key2=key2.0x7fffdf3f3180
+Sending Data: key3=key3.0x7fffdf3f3180
+Sending Data: key1=key1.0x7fffdf3f3180
+Sending Data: last=last
+[localhost tests]$ ./lvqtest --mode browse
+Receiving Data:key1.0x7fffdf3f3180
+Receiving Data:key2.0x7fffdf3f3180
+Receiving Data:key3.0x7fffdf3f3180
+Receiving Data:last
+[localhost tests]$ ./lvqtest --mode write
+Sending Data: key1=key1.0x7fffe4c7fa10
+Sending Data: key2=key2.0x7fffe4c7fa10
+Sending Data: key3=key3.0x7fffe4c7fa10
+Sending Data: key1=key1.0x7fffe4c7fa10
+Sending Data: last=last
+[localhost tests]$ ./lvqtest --mode browse
+Receiving Data:key1.0x7fffe4c7fa10
+Receiving Data:key2.0x7fffe4c7fa10
+Receiving Data:key3.0x7fffe4c7fa10
+Receiving Data:last
+[localhost tests]$ ./lvqtest --mode consume
+Receiving Data:key1.0x7fffdf3f3180
+Receiving Data:key2.0x7fffdf3f3180
+Receiving Data:key3.0x7fffdf3f3180
+Receiving Data:last
+Receiving Data:key1.0x7fffe4c7fa10
+Receiving Data:key2.0x7fffe4c7fa10
+Receiving Data:key3.0x7fffe4c7fa10
+Receiving Data:last
+</programlisting>
+<!--h2--></section>
+ <section role="h2" id="LVQ-LVQNOBROWSEsemantics-3A"><title>
+ LVQ_NO_BROWSE
+ semantics:
+ </title>
+ <para>
+ LVQ uses a header for a key, if the key matches it replaces the
+ message in-place in the queue except
+ a.) if the message with the matching key has been acquired
+ In these two cases the message is placed into the queue in FIFO,
+ if another message with the same key is received it will the
+ 'un-accessed' message with the same key will be replaced
+ </para><para>
+ Note, in this case browsed messaged are not invalidated, so
+ updates can be missed.
+ </para><para>
+ An example
+ </para>
+ <programlisting>
+[localhost tests]$ ./lvqtest --mode create_lvq_no_browse
+[localhost tests]$ ./lvqtest --mode write
+Sending Data: key1=key1.0x7fffce5fb390
+Sending Data: key2=key2.0x7fffce5fb390
+Sending Data: key3=key3.0x7fffce5fb390
+Sending Data: key1=key1.0x7fffce5fb390
+Sending Data: last=last
+[localhost tests]$ ./lvqtest --mode write
+Sending Data: key1=key1.0x7fff346ae440
+Sending Data: key2=key2.0x7fff346ae440
+Sending Data: key3=key3.0x7fff346ae440
+Sending Data: key1=key1.0x7fff346ae440
+Sending Data: last=last
+[localhost tests]$ ./lvqtest --mode browse
+Receiving Data:key1.0x7fff346ae440
+Receiving Data:key2.0x7fff346ae440
+Receiving Data:key3.0x7fff346ae440
+Receiving Data:last
+[localhost tests]$ ./lvqtest --mode browse
+Receiving Data:key1.0x7fff346ae440
+Receiving Data:key2.0x7fff346ae440
+Receiving Data:key3.0x7fff346ae440
+Receiving Data:last
+[localhost tests]$ ./lvqtest --mode write
+Sending Data: key1=key1.0x7fff606583e0
+Sending Data: key2=key2.0x7fff606583e0
+Sending Data: key3=key3.0x7fff606583e0
+Sending Data: key1=key1.0x7fff606583e0
+Sending Data: last=last
+[localhost tests]$ ./lvqtest --mode consume
+Receiving Data:key1.0x7fff606583e0
+Receiving Data:key2.0x7fff606583e0
+Receiving Data:key3.0x7fff606583e0
+Receiving Data:last
+[localhost tests]$
+
+</programlisting>
+ <!--h2--></section>
+ <section role="h2" id="LVQ-Examplesource"><title>
+ LVQ Program Example
+ </title>
+
+ <programlisting>
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+#include &lt;qpid/client/AsyncSession.h&gt;
+#include &lt;qpid/client/Connection.h&gt;
+#include &lt;qpid/client/SubscriptionManager.h&gt;
+#include &lt;qpid/client/Session.h&gt;
+#include &lt;qpid/client/Message.h&gt;
+#include &lt;qpid/client/MessageListener.h&gt;
+#include &lt;qpid/client/QueueOptions.h&gt;
+
+#include &lt;iostream&gt;
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace qpid;
+using namespace std;
+
+
+enum Mode { CREATE_LVQ, CREATE_LVQ_NO_BROWSE, WRITE, BROWSE, CONSUME};
+const char* modeNames[] = { "create_lvq","create_lvq_no_browse","write","browse","consume" };
+
+// istream/ostream ops so Options can read/display Mode.
+istream&amp; operator&gt;&gt;(istream&amp; in, Mode&amp; mode) {
+ string s;
+ in &gt;&gt; s;
+ int i = find(modeNames, modeNames+5, s) - modeNames;
+ if (i &gt;= 5) throw Exception("Invalid mode: "+s);
+ mode = Mode(i);
+ return in;
+}
+
+ostream&amp; operator&lt;&lt;(ostream&amp; out, Mode mode) {
+ return out &lt;&lt; modeNames[mode];
+}
+
+struct Args : public qpid::Options,
+ public qpid::client::ConnectionSettings
+{
+ bool help;
+ Mode mode;
+
+ Args() : qpid::Options("Simple latency test optins"), help(false), mode(BROWSE)
+ {
+ using namespace qpid;
+ addOptions()
+ ("help", optValue(help), "Print this usage statement")
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("username", optValue(username, "USER"), "user name for broker log in.")
+ ("password", optValue(password, "PASSWORD"), "password for broker log in.")
+ ("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
+ ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
+ ("mode", optValue(mode, "'see below'"), "Action mode."
+ "\ncreate_lvq: create a new queue of type lvq.\n"
+ "\ncreate_lvq_no_browse: create a new queue of type lvq with no lvq on browse.\n"
+ "\nwrite: write a bunch of data &amp; keys.\n"
+ "\nbrowse: browse the queue.\n"
+ "\nconsume: consume from the queue.\n");
+ }
+};
+
+class Listener : public MessageListener
+{
+ private:
+ Session session;
+ SubscriptionManager subscriptions;
+ std::string queue;
+ Message request;
+ QueueOptions args;
+ public:
+ Listener(Session&amp; session);
+ void setup(bool browse);
+ void send(std::string kv);
+ void received(Message&amp; message);
+ void browse();
+ void consume();
+};
+
+Listener::Listener(Session&amp; s) :
+ session(s), subscriptions(s),
+ queue("LVQtester")
+{}
+
+void Listener::setup(bool browse)
+{
+ // set queue mode
+ args.setOrdering(browse?LVQ_NO_BROWSE:LVQ);
+
+ session.queueDeclare(arg::queue=queue, arg::exclusive=false, arg::autoDelete=false, arg::arguments=args);
+
+}
+
+void Listener::browse()
+{
+ subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE, ACQUIRE_MODE_NOT_ACQUIRED));
+ subscriptions.run();
+}
+
+void Listener::consume()
+{
+ subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE, ACQUIRE_MODE_PRE_ACQUIRED));
+ subscriptions.run();
+}
+
+void Listener::send(std::string kv)
+{
+ request.getDeliveryProperties().setRoutingKey(queue);
+
+ std::string key;
+ args.getLVQKey(key);
+ request.getHeaders().setString(key, kv);
+
+ std::ostringstream data;
+ data &lt;&lt; kv;
+ if (kv != "last") data &lt;&lt; "." &lt;&lt; hex &lt;&lt; this;
+ request.setData(data.str());
+
+ cout &lt;&lt; "Sending Data: " &lt;&lt; kv &lt;&lt; "=" &lt;&lt; data.str() &lt;&lt; std::endl;
+ async(session).messageTransfer(arg::content=request);
+
+}
+
+void Listener::received(Message&amp; response)
+{
+
+ cout &lt;&lt; "Receiving Data:" &lt;&lt; response.getData() &lt;&lt; std::endl;
+/* if (response.getData() == "last"){
+ subscriptions.cancel(queue);
+ }
+*/
+}
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ opts.parse(argc, argv);
+
+ if (opts.help) {
+ std::cout &lt;&lt; opts &lt;&lt; std::endl;
+ return 0;
+ }
+
+ Connection connection;
+ try {
+ connection.open(opts);
+ Session session = connection.newSession();
+ Listener listener(session);
+
+ switch (opts.mode)
+ {
+ case CONSUME:
+ listener.consume();
+ break;
+ case BROWSE:
+ listener.browse();
+ break;
+ case CREATE_LVQ:
+ listener.setup(false);
+ break;
+ case CREATE_LVQ_NO_BROWSE:
+ listener.setup(true);
+ break;
+ case WRITE:
+ listener.send("key1");
+ listener.send("key2");
+ listener.send("key3");
+ listener.send("key1");
+ listener.send("last");
+ break;
+ }
+ connection.close();
+ return 0;
+ } catch(const std::exception&amp; error) {
+ std::cout &lt;&lt; error.what() &lt;&lt; std::endl;
+ }
+ return 1;
+}
+
+</programlisting>
+<!--h2--></section>
+</section>