Added InstanceId to uniquely identify concurrent messages, transactions, etc.

Use InstanceId for async job and calls identification.

Side-effect: removes inconsistent prefixes for job debugging: ecapxN, icapxN, asyncN are now all jobN, simplifying searching and processing debugging logs.

-----------

We have a few classes that use mostly unique identifiers for debugging. More are coming, including MemBlob from the StringNG branch and IPC messages used by SMP code. The classes I know about benefit from having sequentially increasing IDs, specific to the class. For example, it is very convenient to have async jobs numbered 1,2,3,4,... because it often preserves the job number during repetitive debugging and also shows the relative "distance" between the jobs.

The first attached patch adds a InstanceId class that encapsulates the identifier maintenance logic. The second shows how the new class can be used in the existing code.


Beside the general review, here are a few specific discussion points:

We can force hex formatting for printed ID values. This will shorten printed IDs, but will also make them a little bit more difficult to find/see in the logs. Please let me know whether you think we should use hex.

We can also move custom "created/destructed" debug messages to InstanceId, but I am not sure that is a good idea because it will either remove constructor parameters from those lines or will force us to use two debugging lines per constructor (one standard and one custom). I think it is better to add global functions to standardize output prefix than ask InstanceId to emit "created/destructed" debug messages. What do you think?

Currently, InstanceId uses "int" to store ID values. I am not aware of any classes that need unique IDs with storage types other than int (e.g., to save space or further minimize wrapping). If there are such classes, we need to make the storage type into a second template parameter. Please let me know if you know of such classes.


Thank you,

Alex.

Added InstanceId to uniquely identify concurrent messages, transactions, etc.

=== added file 'src/base/InstanceId.h'
--- src/base/InstanceId.h	1970-01-01 00:00:00 +0000
+++ src/base/InstanceId.h	2010-09-29 16:43:27 +0000
@@ -0,0 +1,60 @@
+#ifndef SQUID_BASE_INSTANCE_ID_H
+#define SQUID_BASE_INSTANCE_ID_H
+
+#include "config.h"
+#include <iosfwd>
+
+/** Identifier for class instances
+ *   - unique IDs for a large number of concurrent instances, but may wrap;
+ *   - useful for debugging and insecure request/response matching;
+ *   - sequential IDs within a class except when wrapping;
+ *   - always positive IDs.
+ *  \todo: add storage type parameter to support configurable Value types?
+ *  \todo: add creation/destruction debugging?
+ */
+template <class Class>
+class InstanceId
+{
+public:
+    typedef unsigned int Value; ///< id storage type; \todo: parameterize?
+
+    InstanceId(): value(++Last ? Last : ++Last) {}
+
+    operator Value() const { return value; }
+    bool operator ==(const InstanceId &o) const { return value == o.value; }
+    bool operator !=(const InstanceId &o) const { return !(*this == o); }
+
+    /// prints Prefix followed by ID value; \todo: use HEX for value printing?
+    std::ostream &print(std::ostream &os) const;
+
+public:
+    static const char *Prefix; ///< Class shorthand string for debugging
+    const Value value; ///< instance identifier
+
+private:
+    InstanceId(const InstanceId& right); ///< not implemented; IDs are unique
+    InstanceId& operator=(const InstanceId &right); ///< not implemented
+
+private:
+    static Value Last; ///< the last used ID value
+};
+
+/// convenience macro to instantiate Class-specific stuff in .cc files
+#define InstanceIdDefinitions(Class, prefix) \
+    template<> std::ostream & \
+    InstanceId<Class>::print(std::ostream &os) const { \
+        return os << Prefix << value; \
+    } \
+    template<> const char *InstanceId<Class>::Prefix = prefix; \
+    template<> InstanceId<Class>::Value InstanceId<Class>::Last = 0
+
+
+/// print the id
+template <class Class>
+inline
+std::ostream &operator <<(std::ostream &os, const InstanceId<Class> &id) {
+    return id.print(os);
+}
+
+
+#endif /* SQUID_BASE_INSTANCE_ID_H */

=== modified file 'src/base/Makefile.am'
--- src/base/Makefile.am	2010-08-23 23:15:26 +0000
+++ src/base/Makefile.am	2010-09-29 16:15:11 +0000
@@ -13,5 +13,6 @@
 	AsyncCallQueue.cc \
 	AsyncCallQueue.h \
 	CbcPointer.h \
+	InstanceId.h \
 	TextException.cc \
 	TextException.h

Use InstanceId for async job and calls identification.

Side-effect: removes inconsistent prefixes for job debugging: ecapxN, icapxN,
asyncN are now all jobN, simplifying searching and processing debugging logs.

=== modified file 'src/adaptation/ecap/XactionRep.cc'
--- src/adaptation/ecap/XactionRep.cc	2010-08-29 21:50:09 +0000
+++ src/adaptation/ecap/XactionRep.cc	2010-09-29 18:14:05 +0000
@@ -446,7 +446,7 @@
             buf.append(" A.", 3);
     }
 
-    buf.Printf(" ecapx%d]", id);
+    buf.Printf(" %s%u]", id.Prefix, id.value);
 
     buf.terminate();
 

=== modified file 'src/adaptation/icap/Xaction.cc'
--- src/adaptation/icap/Xaction.cc	2010-09-13 00:19:25 +0000
+++ src/adaptation/icap/Xaction.cc	2010-09-29 18:14:27 +0000
@@ -538,7 +538,7 @@
     buf.append("/", 1);
     fillDoneStatus(buf);
 
-    buf.Printf(" icapx%d]", id);
+    buf.Printf(" %s%u]", id.Prefix, id.value);
 
     buf.terminate();
 

=== modified file 'src/base/AsyncCall.cc'
--- src/base/AsyncCall.cc	2009-04-09 22:31:13 +0000
+++ src/base/AsyncCall.cc	2010-09-29 16:40:44 +0000
@@ -7,17 +7,17 @@
 #include "base/AsyncCallQueue.h"
 #include "cbdata.h"
 
-unsigned int AsyncCall::TheLastId = 0;
+InstanceIdDefinitions(AsyncCall, "call");
 
 
 /* AsyncCall */
 
 AsyncCall::AsyncCall(int aDebugSection, int aDebugLevel,
                      const char *aName): name(aName), debugSection(aDebugSection),
-        debugLevel(aDebugLevel), id(++TheLastId), theNext(0), isCanceled(NULL)
+        debugLevel(aDebugLevel), theNext(0), isCanceled(NULL)
 {
     debugs(debugSection, debugLevel, "The AsyncCall " << name << " constructed, this=" << this <<
-           " [call" << id << ']');
+           " [" << id << ']');
 }
 
 AsyncCall::~AsyncCall()
@@ -29,7 +29,7 @@
 AsyncCall::make()
 {
     debugs(debugSection, debugLevel, HERE << "make call " << name <<
-           " [call"<< id << ']');
+           " [" << id << ']');
     if (canFire()) {
         fire();
         return;
@@ -39,7 +39,7 @@
         isCanceled = "unknown reason";
 
     debugs(debugSection, debugLevel, HERE << "will not call " << name <<
-           " [call"<< id << ']' << " because of " << isCanceled);
+           " [" << id << ']' << " because of " << isCanceled);
 }
 
 bool
@@ -47,7 +47,7 @@
 {
     if (isCanceled)
         debugs(debugSection, debugLevel, HERE << "will not call " << name <<
-               " [call"<< id << ']' << " also because " << reason);
+               " [" << id << ']' << " also because " << reason);
     isCanceled = reason;
     return false;
 }
@@ -73,7 +73,7 @@
 ScheduleCall(const char *fileName, int fileLine, AsyncCall::Pointer &call)
 {
     debugs(call->debugSection, call->debugLevel, fileName << "(" << fileLine <<
-           ") will call " << *call << " [call"<< call->id << ']' );
+           ") will call " << *call << " [" << call->id << ']' );
     AsyncCallQueue::Instance().schedule(call);
     return true;
 }

=== modified file 'src/base/AsyncCall.h'
--- src/base/AsyncCall.h	2009-04-09 22:31:13 +0000
+++ src/base/AsyncCall.h	2010-09-29 16:13:21 +0000
@@ -6,6 +6,7 @@
 #define SQUID_ASYNCCALL_H
 
 //#include "cbdata.h"
+#include "base/InstanceId.h"
 #include "event.h"
 //#include "TextException.h"
 
@@ -69,7 +70,7 @@
     const char *const name;
     const int debugSection;
     const int debugLevel;
-    const unsigned int id;
+    const InstanceId<AsyncCall> id;
 
 protected:
     virtual bool canFire();
@@ -80,7 +81,6 @@
 
 private:
     const char *isCanceled; // set to the cancelation reason by cancel()
-    static unsigned int TheLastId;
 };
 
 inline

=== modified file 'src/base/AsyncJob.cc'
--- src/base/AsyncJob.cc	2010-09-12 00:10:47 +0000
+++ src/base/AsyncJob.cc	2010-09-29 18:15:38 +0000
@@ -10,8 +10,7 @@
 #include "cbdata.h"
 #include "MemBuf.h"
 
-
-unsigned int AsyncJob::TheLastId = 0;
+InstanceIdDefinitions(AsyncJob, "job");
 
 AsyncJob::Pointer AsyncJob::Start(AsyncJob *j)
 {
@@ -20,16 +19,16 @@
     return job;
 }
 
-AsyncJob::AsyncJob(const char *aTypeName): typeName(aTypeName), inCall(NULL), id(++TheLastId)
+AsyncJob::AsyncJob(const char *aTypeName): typeName(aTypeName), inCall(NULL)
 {
     debugs(93,5, "AsyncJob constructed, this=" << this <<
-           " type=" << typeName << " [job" << id << ']');
+           " type=" << typeName << " [" << id << ']');
 }
 
 AsyncJob::~AsyncJob()
 {
     debugs(93,5, "AsyncJob destructed, this=" << this <<
-           " type=" << typeName << " [job" << id << ']');
+           " type=" << typeName << " [" << id << ']');
 }
 
 void AsyncJob::start()
@@ -156,7 +155,7 @@
         buf.Printf("Stopped, reason:");
         buf.Printf("%s",stopReason);
     }
-    buf.Printf(" job%d]", id);
+    buf.Printf(" %s%u]", id.Prefix, id.value);
     buf.terminate();
 
     return buf.content();

=== modified file 'src/base/AsyncJob.h'
--- src/base/AsyncJob.h	2010-08-23 23:15:26 +0000
+++ src/base/AsyncJob.h	2010-09-29 16:57:30 +0000
@@ -6,6 +6,7 @@
 #define SQUID_ASYNC_JOB_H
 
 #include "base/AsyncCall.h"
+#include "base/InstanceId.h"
 
 template <class Cbc>
 class CbcPointer;
@@ -63,10 +64,7 @@
     const char *stopReason; ///< reason for forcing done() to be true
     const char *typeName; ///< kid (leaf) class name, for debugging
     AsyncCall::Pointer inCall; ///< the asynchronous call being handled, if any
-    const unsigned int id; ///< unique ID across all strand jobs, unless wraps
-
-private:
-    static unsigned int TheLastId; ///< makes job IDs unique until it wraps
+    const InstanceId<AsyncJob> id; ///< job identifier
 };
 
 #endif /* SQUID_ASYNC_JOB_H */

Reply via email to