public void AddEvent(string user, DateTime day, string EventString)
{
List<Object> EventList = null;
String DateString = day.ToString ("yyyy-MM-dd");
String EventKeyString = FormKeyString(user, DateString, 1);
Key EventKey = new Key ("test", "user-events", EventKeyString);
Record eventRecord = client.Get (null, EventKey, "events", "total-records");
if (eventRecord != null) {
// Add a new event with a generation count for optimistic concurrency
int currentCount = eventRecord.GetInt("total-records");
if (currentCount < 0) {
// Another thread has this record locked. Either retry or throw an exception
throw new AerospikeException ("Record locked");
}
updatePolicy.generation = eventRecord.generation;
// Determine the sequence number to write this record to
int sequenceNumber = GetSequenceNumberFromRecordNumber(currentCount);
if (sequenceNumber == 1) {
// No need to lock, write to the base record
EventList = (List<Object>)eventRecord.GetValue ("events");
EventList.Add (EventString);
Bin recordsCount = new Bin ("total-records", currentCount + 1);
client.Put (updatePolicy, EventKey, recordsCount, new Bin ("events", EventList));
} else {
// we need to write a lock to the "head" (sequence 1) record, then write
// the data, then finally unlock the head record and correct it's count
client.Put (updatePolicy, EventKey, new Bin ("total-records", -1));
try {
// Now write the data. In this case we can always do a replace.
Key keyForSequence = new Key("test", "user-events", FormKeyString (user, DateString, sequenceNumber));
Record eventSequenceRecord = client.Get (null, keyForSequence, "events");
List<Object> eventSequenceList;
if (eventSequenceRecord == null || eventSequenceRecord.GetValue ("events") == null) {
// This is a new record
eventSequenceList = new List<Object> ();
} else {
eventSequenceList = (List<Object>)eventSequenceRecord.GetValue ("events");
}
eventSequenceList.Add (EventString);
// Add the user, date and sequence number for clarity. This is not needed in production
// systems as the base record (sequence 1) contains all this information
Bin User = new Bin ("user-id", user);
Bin Day = new Bin ("day", DateString);
Bin Sequence = new Bin ("sequence", sequenceNumber);
Bin events = new Bin ("events", eventSequenceList);
WritePolicy sequencePolicy = new WritePolicy ();
sequencePolicy.recordExistsAction = RecordExistsAction.REPLACE;
client.Put (sequencePolicy, keyForSequence, User, Day, Sequence, events);
// Finally, unlock the record and update the count on it.
updatePolicy.generation = updatePolicy.generation+1;
client.Put (updatePolicy, EventKey, new Bin ("total-records", currentCount + 1));
}
catch (Exception) {
// An error occurred, release the lock
client.Put (updatePolicy, EventKey, new Bin ("total-records", currentCount));
throw;
}
}
} else {
// Create a new event with CREATE_ONLY in case someone else has already created it.
Bin User = new Bin ("user-id", user);
Bin Day = new Bin ("day", DateString);
Bin Sequence = new Bin ("sequence", 1);
Bin TotalRecords = new Bin ("total-records", 1);
EventList = new List<Object> ();
EventList.Add (EventString);
client.Put (createPolicy, EventKey, User, Day, Sequence, TotalRecords, new Bin ("events", EventList));
}
Console.WriteLine ("Wrote event: " + EventKeyString + ":" + EventString.Substring (0, 10) + "...");
}