1
2 /* Web Polygraph http://www.web-polygraph.org/
3 * Copyright 2003-2011 The Measurement Factory
4 * Licensed under the Apache License, Version 2.0 */
5
6 #include "base/polygraph.h"
7
8 #include "xstd/h/os_std.h"
9 #include "xstd/h/iomanip.h"
10
11 #include "xstd/ZFStream.h"
12 #include "xstd/gadgets.h"
13 #include "base/ILog.h"
14 #include "base/polyLogCats.h"
15 #include "base/polyLogTags.h"
16
17
18 /* LogEntryPx */
19
20 // XXX: we should log lgEnd/lgcEnd instead of using current constants!
good() const21 bool LogEntryPx::good() const {
22 return
23 0 <= theCat && theCat < lgcEnd &&
24 0 <= theTag && theTag < lgEnd &&
25 0 < theSize && theSize <= 10*1024*1024;
26 }
27
28 // assume buffer size is at least TheLoadSize
29 // XXX: we should log lgEnd/lgcEnd instead of using current constants!
load(const void * const buf)30 bool LogEntryPx::load(const void *const buf) {
31 const int *const ibuf = reinterpret_cast<const int *>(buf);
32 theSize = ntohl(ibuf[0]);
33 const int h = ntohl(ibuf[1]);
34 theTag = (h << 16) >> 16;
35 theCat = h >> 16; // XXX: assumes sizeof(int) == 32
36 return *this;
37 }
38
print(ostream & os) const39 ostream &LogEntryPx::print(ostream &os) const {
40 return os
41 << "tag: " << theCat << '/' << theTag
42 << " size: " << theSize;
43
44 }
45
46 /* ILog */
47
ILog()48 ILog::ILog(): theStream(0), theZStream(0), theEntryEnd(-1) {
49 }
50
~ILog()51 ILog::~ILog() {
52 delete theZStream;
53 }
54
stream(const String & aFileName,istream * aStream)55 void ILog::stream(const String &aFileName, istream *aStream) {
56 theFileName = aFileName;
57 theStream = aStream;
58 getHeader();
59 }
60
stream(const ILog & log)61 void ILog::stream(const ILog &log) {
62 log.theStream->clear();
63 log.theStream->seekg(0, ios::beg);
64 stream(log.theFileName, log.theStream);
65 }
66
67 // loads prefix of the current entry
68 // transparently loads progress entries
begEntry()69 LogEntryPx ILog::begEntry() {
70 theEntryEnd = pos();
71 char buf[LogEntryPx::TheLoadSize];
72 while (get(buf, LogEntryPx::TheLoadSize)) {
73 if (theCurPx.load(buf) && !theCurPx.good()) {
74 const streampos startOff = theEntryEnd;
75 clog << fileName() << ':' << theEntryEnd
76 << ": warning: corrupted log entry: " << theCurPx << endl;
77
78 do {
79 theEntryEnd += 1;
80 memmove(buf, buf + 1, LogEntryPx::TheLoadSize - 1);
81 buf[LogEntryPx::TheLoadSize - 1] = getc();
82 } while (!fail() && !(theCurPx.load(buf) &&
83 theCurPx.good() &&
84 theCurPx.theTag == lgProgress &&
85 theCurPx.theSize < 1024));
86 if (fail())
87 break;
88
89 clog << fileName() << ':' << theEntryEnd
90 << ": maybe recovered after skipping " << (theEntryEnd-startOff)
91 << " bytes: " << theCurPx << endl;
92 }
93
94 theEntryEnd += theCurPx.theSize;
95 if (theCurPx.theTag != lgProgress)
96 return theCurPx;
97 theProgress.load(*this);
98 endEntry();
99 }
100 theCurPx = LogEntryPx();
101 return theCurPx;
102 }
103
endEntry()104 void ILog::endEntry() {
105 const int nextEntryOffset = theEntryEnd - pos();
106 ignore(nextEntryOffset);
107 theCurPx = LogEntryPx();
108 }
109
getHeader()110 void ILog::getHeader() {
111 Assert(theStream);
112
113 // check magic
114 if (geti() != lgMagic1 || geti() != lgMagic2 || geti() != 0) {
115 if (!*theStream || theStream->bad())
116 cerr << theFileName << ": read error; " << Error::Last() << endl;
117 else
118 cerr << theFileName << ": unknown log file format" << endl;
119 exit(-2);
120 }
121
122 const int sver = 27; // supported version
123 const int cver = geti(); // current log version
124 const int rver = geti(); // required min version to support
125 int extraHdrSz = geti(); // size of extra headers
126
127 if (sver < rver) {
128 cerr << theFileName << ": log version " << cver << endl;
129 cerr << theFileName << ": requires support for log version " << rver << " or higher" << endl;
130 cerr << theFileName << ": this program supports version " << sver << endl;
131 exit(-2);
132 }
133
134 if (sver != cver) {
135 cerr << theFileName << ": log version " << cver << endl;
136 cerr << theFileName << ": this program supports version " << sver << endl;
137 cerr << theFileName << ": continuing at your own risk..." << endl;
138 sleep(3);
139 }
140
141 const int zlibHdrSz = 32;
142 bool doCompression = false;
143 if (extraHdrSz >= zlibHdrSz) {
144 char buf[zlibHdrSz + 1];
145 get(buf, zlibHdrSz);
146 buf[zlibHdrSz] = '\0';
147 extraHdrSz -= zlibHdrSz;
148
149 if (!strcmp(buf, "zlib")) {
150 if (!zlib::Supported) {
151 cerr << theFileName << ": log file is "
152 "compressed with zlib" << endl <<
153 "this program was built without zlib "
154 "support" << endl << xexit;
155 }
156 doCompression = true;
157 } else {
158 cerr << theFileName << ": log file is compressed with "
159 << buf << endl << "this program does not "
160 "support it" << endl << xexit;
161 }
162 }
163
164 ignore(extraHdrSz);
165 if (doCompression)
166 theZStream = new zlib::IFStream(*theStream);
167 }
168
geti(int * & xs,int & count)169 int ILog::geti(int *&xs, int &count) {
170 Must(geti(count) >= 0);
171 xs = new int[count];
172 for (int i = 0; i < count; ++i)
173 geti(xs[i]);
174 return count;
175 }
176
gets(String & s)177 String &ILog::gets(String &s) {
178 const int sz = geti();
179 if (Should(sz >= 0)) {
180 if (sz > 0) {
181 char *buf = s.alloc(sz);
182 get(buf, sz);
183 return s;
184 }
185 }
186 s = String();
187 return s;
188 }
189
get(void * const buf,const int len)190 bool ILog::get(void *const buf, const int len) {
191 char *const cbuf = reinterpret_cast<char *>(buf);
192 int count;
193 if (theZStream)
194 count = theZStream->read(cbuf, len);
195 else {
196 theStream->read(cbuf, len);
197 count = theStream->gcount();
198 }
199 return count == len;
200 }
201
fail() const202 bool ILog::fail() const {
203 return theZStream ? theZStream->fail() : theStream ? theStream->fail() :
204 true;
205 }
206
pos() const207 istream::pos_type ILog::pos() const {
208 return theZStream ? theZStream->pos() : theStream ? theStream->tellg() :
209 istream::pos_type(-1);
210 }
211
ignore(const int n)212 void ILog::ignore(const int n) {
213 Must(n >= 0);
214 if (theZStream)
215 theZStream->ignore(n);
216 else
217 theStream->ignore(n);
218 }
219