PageRenderTime 68ms CodeModel.GetById 13ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/externals/google-toolbox-for-mac/Foundation/GTMLoggerRingBufferWriter.m

http://macfuse.googlecode.com/
Objective C | 251 lines | 142 code | 65 blank | 44 comment | 21 complexity | 35aa466ffaa3eee04d24e2388ec60b88 MD5 | raw file
  1//
  2//  GTMLoggerRingBufferWriter.m
  3//
  4//  Copyright 2007-2008 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9// 
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11// 
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19#import "GTMLoggerRingBufferWriter.h"
 20
 21// Holds a message and a level.
 22struct GTMRingBufferPair {
 23  // Explicitly using CFStringRef instead of NSString because in a GC world, the
 24  // NSString will be collected because there is no way for the GC to know that
 25  // there is a strong reference to the NSString in this data structure. By
 26  // using a CFStringRef we can CFRetain it, and avoid the problem.
 27  CFStringRef logMessage_;
 28  GTMLoggerLevel level_;
 29};
 30
 31
 32// There are two operations that involve iterating over the buffer
 33// contents and doing Something to them.  This is a callback function
 34// that is called for every pair living in the buffer.
 35typedef void (GTMRingBufferPairCallback)(GTMLoggerRingBufferWriter *rbw,
 36                                         GTMRingBufferPair *pair);
 37
 38
 39@interface GTMLoggerRingBufferWriter (PrivateMethods)
 40
 41// Add the message and level to the ring buffer.
 42- (void)addMessage:(NSString *)message level:(GTMLoggerLevel)level;
 43
 44// Walk the buffer invoking the callback.
 45- (void)iterateBufferWithCallback:(GTMRingBufferPairCallback)callback;
 46
 47@end  // PrivateMethods
 48
 49
 50@implementation GTMLoggerRingBufferWriter
 51
 52+ (id)ringBufferWriterWithCapacity:(NSUInteger)capacity
 53                            writer:(id<GTMLogWriter>)writer {
 54  GTMLoggerRingBufferWriter *rbw =
 55    [[[self alloc] initWithCapacity:capacity
 56                            writer:writer] autorelease];
 57  return rbw;
 58
 59}  // ringBufferWriterWithCapacity
 60
 61
 62- (id)initWithCapacity:(NSUInteger)capacity
 63                writer:(id<GTMLogWriter>)writer {
 64  if ((self = [super init])) {
 65    writer_ = [writer retain];
 66    capacity_ = capacity;
 67
 68    // iVars are initialized to NULL.
 69    // Calling calloc with 0 is outside the standard.
 70    if (capacity_) {
 71      buffer_ = (GTMRingBufferPair *)calloc(capacity_,
 72                                            sizeof(GTMRingBufferPair));
 73    }
 74
 75    nextIndex_ = 0;
 76
 77    if (capacity_ == 0 || !buffer_ || !writer_) {
 78      [self release];
 79      self = nil;
 80    }
 81  }
 82  return self;
 83
 84}  // initWithCapacity
 85
 86
 87- (id)init {
 88  return [self initWithCapacity:0 writer:nil];
 89}  // init
 90
 91
 92- (void)dealloc {
 93  [self reset];
 94
 95  [writer_ release];
 96  if (buffer_) free(buffer_);
 97
 98  [super dealloc];
 99  
100}  // dealloc
101
102
103- (NSUInteger)capacity {
104  return capacity_;
105}  // capacity
106
107
108- (id<GTMLogWriter>)writer {
109  return writer_;
110}  // writer
111
112
113- (NSUInteger)count {
114  NSUInteger count = 0;
115  @synchronized(self) {
116    if ((nextIndex_ == 0 && totalLogged_ > 0)
117        || totalLogged_ >= capacity_) {
118      // We've wrapped around
119      count = capacity_;
120    } else {
121      count = nextIndex_;
122    }
123  }
124
125  return count;
126
127}  // count
128
129
130- (NSUInteger)droppedLogCount {
131  NSUInteger droppedCount = 0;
132  
133  @synchronized(self) {
134    if (capacity_ > totalLogged_) {
135      droppedCount = 0;
136    } else {
137      droppedCount = totalLogged_ - capacity_;
138    }
139  }
140  
141  return droppedCount;
142
143}  // droppedLogCount
144
145
146- (NSUInteger)totalLogged {
147  return totalLogged_;
148}  // totalLogged
149
150
151// Assumes caller will do any necessary synchronization.
152// This walks over the buffer, taking into account any wrap-around,
153// and calls the callback on each pair.
154- (void)iterateBufferWithCallback:(GTMRingBufferPairCallback)callback {
155  GTMRingBufferPair *scan, *stop;
156
157  // If we've wrapped around, print out the ring buffer from |nextIndex_|
158  // to the end.
159  if (totalLogged_ >= capacity_) {
160    scan = buffer_ + nextIndex_;
161    stop = buffer_ + capacity_;
162    while (scan < stop) {
163      callback(self, scan);
164      ++scan;
165    }
166  }
167
168  // And then print from the beginning to right before |nextIndex_|
169  scan = buffer_;
170  stop = buffer_ + nextIndex_;
171  while (scan < stop) {
172    callback(self, scan);
173    ++scan;
174  }
175
176}  // iterateBufferWithCallback
177
178
179// Used when resetting the buffer.  This frees the string and zeros out
180// the structure.
181static void ResetCallback(GTMLoggerRingBufferWriter *rbw,
182                          GTMRingBufferPair *pair) {
183  if (pair->logMessage_) {
184    CFRelease(pair->logMessage_);
185  }
186  pair->logMessage_ = nil;
187  pair->level_ = kGTMLoggerLevelUnknown;
188}  // ResetCallback
189
190
191// Reset the contents.
192- (void)reset {
193  @synchronized(self) {
194    [self iterateBufferWithCallback:ResetCallback];
195    nextIndex_ = 0;
196    totalLogged_ = 0;
197  }
198
199}  // reset
200
201
202// Go ahead and log the stored backlog, writing it through the
203// ring buffer's |writer_|.
204static void PrintContentsCallback(GTMLoggerRingBufferWriter *rbw,
205                                  GTMRingBufferPair *pair) {
206  [[rbw writer] logMessage:(NSString*)pair->logMessage_ level:pair->level_];
207}  // PrintContentsCallback
208
209
210- (void)dumpContents {
211  @synchronized(self) {
212    [self iterateBufferWithCallback:PrintContentsCallback];
213  }
214}  // printContents
215
216
217// Assumes caller will do any necessary synchronization.
218- (void)addMessage:(NSString *)message level:(GTMLoggerLevel)level {
219  NSUInteger newIndex = nextIndex_;
220  nextIndex_ = (nextIndex_ + 1) % capacity_;
221  
222  ++totalLogged_;
223  
224  // Now store the goodies.
225  GTMRingBufferPair *pair = buffer_ + newIndex;
226  if (pair->logMessage_) {
227    CFRelease(pair->logMessage_);
228    pair->logMessage_ = nil;
229  }
230  if (message) {
231    pair->logMessage_ = CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef)message);
232  }
233  pair->level_ = level;
234  
235}  // addMessage
236
237
238// From the GTMLogWriter protocol.
239- (void)logMessage:(NSString *)message level:(GTMLoggerLevel)level {
240  @synchronized(self) {
241    [self addMessage:(NSString*)message level:level];
242    
243    if (level >= kGTMLoggerLevelError) {
244      [self dumpContents];
245      [self reset];
246    }
247  }
248
249}  // logMessage
250
251@end  // GTMLoggerRingBufferWriter