Skip to content

Commit 9243cd0

Browse files
author
LoneWandererProductions
committed
smaller documentation touchups
1 parent 8004619 commit 9243cd0

1 file changed

Lines changed: 97 additions & 73 deletions

File tree

ExtendedSystemObjects/TransactionLogs.cs

Lines changed: 97 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,25 @@
33
* PROJECT: ExtendedSystemObjects
44
* FILE: ExtendedSystemObjects/TransactionLogs.cs
55
* PURPOSE: Basic Transaction Log, log Changes
6-
* PROGRAMER: Peter Geinitz (Wayfarer)
6+
* PROGRAMMER: Peter Geinitz (Wayfarer)
7+
* DESCRIPTION:
8+
* Basic Transaction Log for tracking Add, Remove, and Change operations with unique entries.
9+
* Designed as a minimal, thread-safe utility for logging changes in collections or objects.
10+
*
11+
* This class provides a bare-bones implementation intended for adaptation to specific use cases.
12+
* It focuses on tracking state changes without assumptions about persistence or complex undo-redo mechanisms.
13+
*
14+
* Usage Notes:
15+
* - Thread-safe via internal locking and concurrent dictionary.
16+
* - Uses integer keys managed internally; may need customization for key management.
17+
* - Does not enforce validation beyond basic checks; users should adapt as needed.
18+
* - Intended primarily for lightweight change tracking and simple transaction logging scenarios.
19+
*
20+
* Future improvements could include:
21+
* - Persistence support
22+
* - Undo/Redo operations
23+
* - More advanced query/filtering of logs
24+
* - Custom key strategies or identifiers
725
*/
826

927
// ReSharper disable MemberCanBeInternal
@@ -17,196 +35,202 @@
1735
namespace ExtendedSystemObjects
1836
{
1937
/// <summary>
20-
/// Basic Transaction Log with unique entries and generic entries
38+
/// Basic Transaction Log with unique entries and generic entries.
39+
/// Supports Add, Change, and Remove logging.
2140
/// </summary>
2241
public sealed class TransactionLogs
2342
{
2443
/// <summary>
25-
/// The lock for non-thread-safe operations.
44+
/// The lock used to synchronize operations that require thread safety beyond what the ConcurrentDictionary provides.
2645
/// </summary>
2746
private readonly object _lock = new();
2847

29-
private int _changedFlag; // 0 = false, 1 = true
48+
/// <summary>
49+
/// Flag used to track whether the changelog has been modified.
50+
/// </summary>
51+
private int _changedFlag;
3052

3153
/// <summary>
32-
/// Initializes a new instance of the <see cref="TransactionLogs" /> class.
54+
/// Initializes a new instance of the <see cref="TransactionLogs"/> class.
3355
/// </summary>
3456
public TransactionLogs()
3557
{
3658
Changelog = new ConcurrentDictionary<int, LogEntry>();
3759
}
3860

3961
/// <summary>
40-
/// The changelog
62+
/// Gets the changelog containing all tracked operations.
4163
/// </summary>
4264
public ConcurrentDictionary<int, LogEntry> Changelog { get; }
4365

4466
/// <summary>
45-
/// Gets a value indicating whether this <see cref="TransactionLogs" /> is changed.
67+
/// Gets a value indicating whether any changes have been logged.
4668
/// </summary>
47-
/// <value>
48-
/// <c>true</c> if changed; currentSequence-wise, <c>false</c>.
49-
/// </value>
5069
public bool Changed
5170
{
5271
get => Interlocked.CompareExchange(ref _changedFlag, 0, 0) == 1;
5372
private set => Interlocked.Exchange(ref _changedFlag, value ? 1 : 0);
5473
}
5574

5675
/// <summary>
57-
/// Adds the specified unique identifier.
76+
/// Adds a new log entry for an object.
5877
/// </summary>
59-
/// <param name="uniqueIdentifier">The unique identifier.</param>
60-
/// <param name="item">The item.</param>
61-
/// <param name="startData">if set to <c>true</c> [start data].</param>
78+
/// <param name="uniqueIdentifier">The unique identifier of the object.</param>
79+
/// <param name="item">The object being added.</param>
80+
/// <param name="startData">Whether this is initial state data (i.e., pre-existing before logging).</param>
6281
public void Add(int uniqueIdentifier, object item, bool startData)
6382
{
6483
lock (_lock)
6584
{
6685
var log = new LogEntry
6786
{
68-
State = LogState.Add, Data = item, UniqueIdentifier = uniqueIdentifier, StartData = startData
87+
State = LogState.Add,
88+
Data = item,
89+
UniqueIdentifier = uniqueIdentifier,
90+
StartData = startData
6991
};
7092

71-
// Add the new log entry to the Changelog
72-
Changelog[Changelog.Count] = log; // Using index as the key
93+
Changelog[GetNewKey()] = log;
7394
Changed = true;
7495
}
7596
}
7697

7798
/// <summary>
78-
/// Removes the specified unique identifier.
99+
/// Adds a remove log entry for an object if an 'Add' entry exists for it.
79100
/// </summary>
80-
/// <param name="uniqueIdentifier">The unique identifier.</param>
101+
/// <param name="uniqueIdentifier">The unique identifier of the object.</param>
81102
public void Remove(int uniqueIdentifier)
82103
{
83104
lock (_lock)
84105
{
85106
var id = GetItem(uniqueIdentifier, LogState.Add);
86-
if (id != -1)
107+
if (id == -1) return;
108+
109+
var item = Changelog[id].Data;
110+
111+
Changelog[GetNewKey()] = new LogEntry
87112
{
88-
var item = Changelog[id].Data;
89-
var log = new LogEntry
90-
{
91-
State = LogState.Remove, Data = item, UniqueIdentifier = uniqueIdentifier
92-
};
93-
Changelog[Changelog.Count] = log; // Add remove log entry
94-
Changed = true;
95-
}
113+
State = LogState.Remove,
114+
Data = item,
115+
UniqueIdentifier = uniqueIdentifier
116+
};
117+
118+
Changed = true;
96119
}
97120
}
98121

99122
/// <summary>
100-
/// Changes the specified unique identifier.
123+
/// Logs a change to an object, if the object has changed.
124+
/// Updates an existing change entry if one exists and differs.
101125
/// </summary>
102-
/// <param name="uniqueIdentifier">The unique identifier.</param>
103-
/// <param name="item">The item.</param>
126+
/// <param name="uniqueIdentifier">The unique identifier of the object.</param>
127+
/// <param name="item">The updated object.</param>
104128
public void Change(int uniqueIdentifier, object item)
105129
{
106130
lock (_lock)
107131
{
108-
if (GetItem(uniqueIdentifier, LogState.Change) is var entry && entry != -1)
132+
var entry = GetItem(uniqueIdentifier, LogState.Change);
133+
134+
if (entry != -1 && Changelog[entry].Data.Equals(item) == false)
109135
{
110-
var existingItem = Changelog[entry];
111-
if (!existingItem.Data.Equals(item))
136+
Changelog[entry] = new LogEntry
112137
{
113-
Changelog[entry] = new LogEntry
114-
{
115-
State = LogState.Change, Data = item, UniqueIdentifier = uniqueIdentifier
116-
};
117-
Changed = true;
118-
}
138+
State = LogState.Change,
139+
Data = item,
140+
UniqueIdentifier = uniqueIdentifier
141+
};
142+
Changed = true;
119143
}
120-
else
144+
else if (entry == -1)
121145
{
122-
var log = new LogEntry
146+
Changelog[GetNewKey()] = new LogEntry
123147
{
124-
State = LogState.Change, Data = item, UniqueIdentifier = uniqueIdentifier
148+
State = LogState.Change,
149+
Data = item,
150+
UniqueIdentifier = uniqueIdentifier
125151
};
126-
Changelog[Changelog.Count] = log; // Add change log entry
127152
Changed = true;
128153
}
129154
}
130155
}
131156

132157
/// <summary>
133-
/// Gets the predecessor of a given entry.
158+
/// Gets the predecessor Add entry key for a given log entry key, if available.
134159
/// </summary>
135-
/// <param name="id">The identifier.</param>
136-
/// <returns>The predecessor's key or -1 if not found.</returns>
160+
/// <param name="id">The key of the log entry to search from.</param>
161+
/// <returns>The key of the matching Add entry, or -1 if not found.</returns>
137162
public int GetPredecessor(int id)
138163
{
139164
lock (_lock)
140165
{
141-
var unique = Changelog[id].UniqueIdentifier;
166+
if (!Changelog.TryGetValue(id, out var reference)) return -1;
167+
var unique = reference.UniqueIdentifier;
142168

143-
foreach (var item in Changelog.Reverse().Where(item =>
144-
item.Key < id && item.Value.UniqueIdentifier == unique &&
145-
item.Value.State == LogState.Add))
169+
foreach (var item in Changelog.Reverse())
146170
{
147-
return item.Key;
171+
if (item.Key >= id) continue;
172+
173+
if (item.Value.UniqueIdentifier == unique && item.Value.State == LogState.Add)
174+
return item.Key;
148175
}
149176

150177
return -1;
151178
}
152179
}
153180

154181
/// <summary>
155-
/// Gets the new items.
182+
/// Gets all newly added items (i.e., those not marked as StartData).
156183
/// </summary>
157-
/// <returns>Newly added items</returns>
184+
/// <returns>A dictionary of new items or null if none exist.</returns>
158185
public Dictionary<int, LogEntry> GetNewItems()
159186
{
160187
lock (_lock)
161188
{
162-
return Changelog.Count == 0
163-
? null
164-
: Changelog.Where(item => !item.Value.StartData).ToDictionary(item => item.Key, item => item.Value);
189+
if (Changelog.IsEmpty)
190+
return null;
191+
192+
return Changelog
193+
.Where(entry => !entry.Value.StartData)
194+
.ToDictionary(entry => entry.Key, entry => entry.Value);
165195
}
166196
}
167197

168198
/// <summary>
169-
/// Gets the item for a specific state.
199+
/// Gets the most recent entry matching the specified unique identifier and state.
170200
/// </summary>
171-
/// <param name="uniqueIdentifier">The unique identifier.</param>
172-
/// <param name="state">State of Item</param>
173-
/// <returns>ChangedItem</returns>
201+
/// <param name="uniqueIdentifier">The unique identifier of the object.</param>
202+
/// <param name="state">The state to match (Add, Remove, Change).</param>
203+
/// <returns>The key of the matching entry or -1 if not found.</returns>
174204
internal int GetItem(int uniqueIdentifier, LogState state)
175205
{
176206
lock (_lock)
177207
{
178-
if (Changelog == null || Changelog.Count == 0)
179-
{
208+
if (Changelog.IsEmpty)
180209
return -1;
181-
}
182210

183211
foreach (var (key, value) in Changelog.Reverse())
184212
{
185213
if (value.UniqueIdentifier == uniqueIdentifier && value.State == state)
186-
{
187214
return key;
188-
}
189215
}
190216

191217
return -1;
192218
}
193219
}
194220

195221
/// <summary>
196-
/// Gets the next available key.
222+
/// Gets the next available key in the changelog.
197223
/// </summary>
198-
/// <returns>First available Key</returns>
224+
/// <returns>The first unused integer key.</returns>
199225
public int GetNewKey()
200226
{
201227
lock (_lock)
202228
{
203-
if (Changelog?.IsEmpty != false)
204-
{
229+
if (Changelog.IsEmpty)
205230
return 0;
206-
}
207231

208-
var lst = Changelog.Keys.ToList();
209-
return Utility.GetFirstAvailableIndex(lst);
232+
var keys = Changelog.Keys.ToList();
233+
return Utility.GetFirstAvailableIndex(keys);
210234
}
211235
}
212236
}

0 commit comments

Comments
 (0)