cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jbel...@apache.org
Subject svn commit: r791553 - in /incubator/cassandra/trunk: interface/ interface/gen-java/org/apache/cassandra/service/ src/java/org/apache/cassandra/cli/ src/java/org/apache/cassandra/cql/common/ src/java/org/apache/cassandra/db/ src/java/org/apache/cassandr...
Date Mon, 06 Jul 2009 17:50:16 GMT
Author: jbellis
Date: Mon Jul  6 17:50:16 2009
New Revision: 791553

URL: http://svn.apache.org/viewvc?rev=791553&view=rev
Log:
add offset support to get_slice.  patch by Jun Rao; reviewed by jbellis for CASSANDRA-261

Modified:
    incubator/cassandra/trunk/interface/cassandra.thrift
    incubator/cassandra/trunk/interface/gen-java/org/apache/cassandra/service/Cassandra.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/ColumnRangeQueryRSD.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/SuperColumnRangeQueryRSD.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SliceFromReadCommand.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java
    incubator/cassandra/trunk/test/system/test_server.py
    incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/ReadMessageTest.java
    incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TableTest.java

Modified: incubator/cassandra/trunk/interface/cassandra.thrift
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/interface/cassandra.thrift?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/interface/cassandra.thrift (original)
+++ incubator/cassandra/trunk/interface/cassandra.thrift Mon Jul  6 17:50:16 2009
@@ -107,7 +107,7 @@
   list<column_t> get_slice_by_names(1:string tablename, 2:string key, 3:string columnParent,
4:list<string> columnNames)
   throws (1: InvalidRequestException ire, 2: NotFoundException nfe),
   
-  list<column_t> get_slice(1:string tablename, 2:string key, 3:string columnParent,
4:bool isAscending, 5:i32 count=100)
+  list<column_t> get_slice(1:string tablename, 2:string key, 3:string columnParent,
4:bool isAscending, 5:i32 offset, 6:i32 count=100)
   throws (1: InvalidRequestException ire, 2: NotFoundException nfe),
 
   column_t       get_column(1:string tablename, 2:string key, 3:string columnPath)
@@ -128,7 +128,7 @@
   list<column_t> get_columns_since(1:string tablename, 2:string key, 3:string columnParent,
4:i64 timeStamp)
   throws (1: InvalidRequestException ire, 2: NotFoundException nfe),
 
-  list<superColumn_t> get_slice_super(1:string tablename, 2:string key, 3:string columnFamily,
4:bool isAscending, 5:i32 count=100)
+  list<superColumn_t> get_slice_super(1:string tablename, 2:string key, 3:string columnFamily,
4:bool isAscending, 5:i32 offset, 6:i32 count=100)
   throws (1: InvalidRequestException ire),
 
   list<superColumn_t> get_slice_super_by_names(1:string tablename, 2:string key, 3:string
columnFamily, 4:list<string> superColumnNames)

Modified: incubator/cassandra/trunk/interface/gen-java/org/apache/cassandra/service/Cassandra.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/interface/gen-java/org/apache/cassandra/service/Cassandra.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/interface/gen-java/org/apache/cassandra/service/Cassandra.java
(original)
+++ incubator/cassandra/trunk/interface/gen-java/org/apache/cassandra/service/Cassandra.java
Mon Jul  6 17:50:16 2009
@@ -26,7 +26,7 @@
 
     public List<column_t> get_slice_by_names(String tablename, String key, String columnParent,
List<String> columnNames) throws InvalidRequestException, NotFoundException, TException;
 
-    public List<column_t> get_slice(String tablename, String key, String columnParent,
boolean isAscending, int count) throws InvalidRequestException, NotFoundException, TException;
+    public List<column_t> get_slice(String tablename, String key, String columnParent,
boolean isAscending, int offset, int count) throws InvalidRequestException, NotFoundException,
TException;
 
     public column_t get_column(String tablename, String key, String columnPath) throws InvalidRequestException,
NotFoundException, TException;
 
@@ -40,7 +40,7 @@
 
     public List<column_t> get_columns_since(String tablename, String key, String columnParent,
long timeStamp) throws InvalidRequestException, NotFoundException, TException;
 
-    public List<superColumn_t> get_slice_super(String tablename, String key, String
columnFamily, boolean isAscending, int count) throws InvalidRequestException, TException;
+    public List<superColumn_t> get_slice_super(String tablename, String key, String
columnFamily, boolean isAscending, int offset, int count) throws InvalidRequestException,
TException;
 
     public List<superColumn_t> get_slice_super_by_names(String tablename, String key,
String columnFamily, List<String> superColumnNames) throws InvalidRequestException,
TException;
 
@@ -173,13 +173,13 @@
       throw new TApplicationException(TApplicationException.MISSING_RESULT, "get_slice_by_names
failed: unknown result");
     }
 
-    public List<column_t> get_slice(String tablename, String key, String columnParent,
boolean isAscending, int count) throws InvalidRequestException, NotFoundException, TException
+    public List<column_t> get_slice(String tablename, String key, String columnParent,
boolean isAscending, int offset, int count) throws InvalidRequestException, NotFoundException,
TException
     {
-      send_get_slice(tablename, key, columnParent, isAscending, count);
+      send_get_slice(tablename, key, columnParent, isAscending, offset, count);
       return recv_get_slice();
     }
 
-    public void send_get_slice(String tablename, String key, String columnParent, boolean
isAscending, int count) throws TException
+    public void send_get_slice(String tablename, String key, String columnParent, boolean
isAscending, int offset, int count) throws TException
     {
       oprot_.writeMessageBegin(new TMessage("get_slice", TMessageType.CALL, seqid_));
       get_slice_args args = new get_slice_args();
@@ -187,6 +187,7 @@
       args.key = key;
       args.columnParent = columnParent;
       args.isAscending = isAscending;
+      args.offset = offset;
       args.count = count;
       args.write(oprot_);
       oprot_.writeMessageEnd();
@@ -455,13 +456,13 @@
       throw new TApplicationException(TApplicationException.MISSING_RESULT, "get_columns_since
failed: unknown result");
     }
 
-    public List<superColumn_t> get_slice_super(String tablename, String key, String
columnFamily, boolean isAscending, int count) throws InvalidRequestException, TException
+    public List<superColumn_t> get_slice_super(String tablename, String key, String
columnFamily, boolean isAscending, int offset, int count) throws InvalidRequestException,
TException
     {
-      send_get_slice_super(tablename, key, columnFamily, isAscending, count);
+      send_get_slice_super(tablename, key, columnFamily, isAscending, offset, count);
       return recv_get_slice_super();
     }
 
-    public void send_get_slice_super(String tablename, String key, String columnFamily, boolean
isAscending, int count) throws TException
+    public void send_get_slice_super(String tablename, String key, String columnFamily, boolean
isAscending, int offset, int count) throws TException
     {
       oprot_.writeMessageBegin(new TMessage("get_slice_super", TMessageType.CALL, seqid_));
       get_slice_super_args args = new get_slice_super_args();
@@ -469,6 +470,7 @@
       args.key = key;
       args.columnFamily = columnFamily;
       args.isAscending = isAscending;
+      args.offset = offset;
       args.count = count;
       args.write(oprot_);
       oprot_.writeMessageEnd();
@@ -906,7 +908,7 @@
         iprot.readMessageEnd();
         get_slice_result result = new get_slice_result();
         try {
-          result.success = iface_.get_slice(args.tablename, args.key, args.columnParent,
args.isAscending, args.count);
+          result.success = iface_.get_slice(args.tablename, args.key, args.columnParent,
args.isAscending, args.offset, args.count);
         } catch (InvalidRequestException ire) {
           result.ire = ire;
         } catch (NotFoundException nfe) {
@@ -1115,7 +1117,7 @@
         iprot.readMessageEnd();
         get_slice_super_result result = new get_slice_super_result();
         try {
-          result.success = iface_.get_slice_super(args.tablename, args.key, args.columnFamily,
args.isAscending, args.count);
+          result.success = iface_.get_slice_super(args.tablename, args.key, args.columnFamily,
args.isAscending, args.offset, args.count);
         } catch (InvalidRequestException ire) {
           result.ire = ire;
         } catch (Throwable th) {
@@ -3136,7 +3138,8 @@
     private static final TField KEY_FIELD_DESC = new TField("key", TType.STRING, (short)2);
     private static final TField COLUMN_PARENT_FIELD_DESC = new TField("columnParent", TType.STRING,
(short)3);
     private static final TField IS_ASCENDING_FIELD_DESC = new TField("isAscending", TType.BOOL,
(short)4);
-    private static final TField COUNT_FIELD_DESC = new TField("count", TType.I32, (short)5);
+    private static final TField OFFSET_FIELD_DESC = new TField("offset", TType.I32, (short)5);
+    private static final TField COUNT_FIELD_DESC = new TField("count", TType.I32, (short)6);
 
     public String tablename;
     public static final int TABLENAME = 1;
@@ -3146,12 +3149,15 @@
     public static final int COLUMNPARENT = 3;
     public boolean isAscending;
     public static final int ISASCENDING = 4;
+    public int offset;
+    public static final int OFFSET = 5;
     public int count;
-    public static final int COUNT = 5;
+    public static final int COUNT = 6;
 
     private final Isset __isset = new Isset();
     private static final class Isset implements java.io.Serializable {
       public boolean isAscending = false;
+      public boolean offset = false;
       public boolean count = false;
     }
 
@@ -3164,6 +3170,8 @@
           new FieldValueMetaData(TType.STRING)));
       put(ISASCENDING, new FieldMetaData("isAscending", TFieldRequirementType.DEFAULT, 
           new FieldValueMetaData(TType.BOOL)));
+      put(OFFSET, new FieldMetaData("offset", TFieldRequirementType.DEFAULT, 
+          new FieldValueMetaData(TType.I32)));
       put(COUNT, new FieldMetaData("count", TFieldRequirementType.DEFAULT, 
           new FieldValueMetaData(TType.I32)));
     }});
@@ -3182,6 +3190,7 @@
       String key,
       String columnParent,
       boolean isAscending,
+      int offset,
       int count)
     {
       this();
@@ -3190,6 +3199,8 @@
       this.columnParent = columnParent;
       this.isAscending = isAscending;
       this.__isset.isAscending = true;
+      this.offset = offset;
+      this.__isset.offset = true;
       this.count = count;
       this.__isset.count = true;
     }
@@ -3209,6 +3220,8 @@
       }
       __isset.isAscending = other.__isset.isAscending;
       this.isAscending = other.isAscending;
+      __isset.offset = other.__isset.offset;
+      this.offset = other.offset;
       __isset.count = other.__isset.count;
       this.count = other.count;
     }
@@ -3309,6 +3322,28 @@
       this.__isset.isAscending = value;
     }
 
+    public int getOffset() {
+      return this.offset;
+    }
+
+    public void setOffset(int offset) {
+      this.offset = offset;
+      this.__isset.offset = true;
+    }
+
+    public void unsetOffset() {
+      this.__isset.offset = false;
+    }
+
+    // Returns true if field offset is set (has been asigned a value) and false otherwise
+    public boolean isSetOffset() {
+      return this.__isset.offset;
+    }
+
+    public void setOffsetIsSet(boolean value) {
+      this.__isset.offset = value;
+    }
+
     public int getCount() {
       return this.count;
     }
@@ -3365,6 +3400,14 @@
         }
         break;
 
+      case OFFSET:
+        if (value == null) {
+          unsetOffset();
+        } else {
+          setOffset((Integer)value);
+        }
+        break;
+
       case COUNT:
         if (value == null) {
           unsetCount();
@@ -3392,6 +3435,9 @@
       case ISASCENDING:
         return new Boolean(isIsAscending());
 
+      case OFFSET:
+        return new Integer(getOffset());
+
       case COUNT:
         return new Integer(getCount());
 
@@ -3411,6 +3457,8 @@
         return isSetColumnParent();
       case ISASCENDING:
         return isSetIsAscending();
+      case OFFSET:
+        return isSetOffset();
       case COUNT:
         return isSetCount();
       default:
@@ -3467,6 +3515,15 @@
           return false;
       }
 
+      boolean this_present_offset = true;
+      boolean that_present_offset = true;
+      if (this_present_offset || that_present_offset) {
+        if (!(this_present_offset && that_present_offset))
+          return false;
+        if (this.offset != that.offset)
+          return false;
+      }
+
       boolean this_present_count = true;
       boolean that_present_count = true;
       if (this_present_count || that_present_count) {
@@ -3524,6 +3581,14 @@
               TProtocolUtil.skip(iprot, field.type);
             }
             break;
+          case OFFSET:
+            if (field.type == TType.I32) {
+              this.offset = iprot.readI32();
+              this.__isset.offset = true;
+            } else { 
+              TProtocolUtil.skip(iprot, field.type);
+            }
+            break;
           case COUNT:
             if (field.type == TType.I32) {
               this.count = iprot.readI32();
@@ -3567,6 +3632,9 @@
       oprot.writeFieldBegin(IS_ASCENDING_FIELD_DESC);
       oprot.writeBool(this.isAscending);
       oprot.writeFieldEnd();
+      oprot.writeFieldBegin(OFFSET_FIELD_DESC);
+      oprot.writeI32(this.offset);
+      oprot.writeFieldEnd();
       oprot.writeFieldBegin(COUNT_FIELD_DESC);
       oprot.writeI32(this.count);
       oprot.writeFieldEnd();
@@ -3607,6 +3675,10 @@
       sb.append(this.isAscending);
       first = false;
       if (!first) sb.append(", ");
+      sb.append("offset:");
+      sb.append(this.offset);
+      first = false;
+      if (!first) sb.append(", ");
       sb.append("count:");
       sb.append(this.count);
       first = false;
@@ -8290,7 +8362,8 @@
     private static final TField KEY_FIELD_DESC = new TField("key", TType.STRING, (short)2);
     private static final TField COLUMN_FAMILY_FIELD_DESC = new TField("columnFamily", TType.STRING,
(short)3);
     private static final TField IS_ASCENDING_FIELD_DESC = new TField("isAscending", TType.BOOL,
(short)4);
-    private static final TField COUNT_FIELD_DESC = new TField("count", TType.I32, (short)5);
+    private static final TField OFFSET_FIELD_DESC = new TField("offset", TType.I32, (short)5);
+    private static final TField COUNT_FIELD_DESC = new TField("count", TType.I32, (short)6);
 
     public String tablename;
     public static final int TABLENAME = 1;
@@ -8300,12 +8373,15 @@
     public static final int COLUMNFAMILY = 3;
     public boolean isAscending;
     public static final int ISASCENDING = 4;
+    public int offset;
+    public static final int OFFSET = 5;
     public int count;
-    public static final int COUNT = 5;
+    public static final int COUNT = 6;
 
     private final Isset __isset = new Isset();
     private static final class Isset implements java.io.Serializable {
       public boolean isAscending = false;
+      public boolean offset = false;
       public boolean count = false;
     }
 
@@ -8318,6 +8394,8 @@
           new FieldValueMetaData(TType.STRING)));
       put(ISASCENDING, new FieldMetaData("isAscending", TFieldRequirementType.DEFAULT, 
           new FieldValueMetaData(TType.BOOL)));
+      put(OFFSET, new FieldMetaData("offset", TFieldRequirementType.DEFAULT, 
+          new FieldValueMetaData(TType.I32)));
       put(COUNT, new FieldMetaData("count", TFieldRequirementType.DEFAULT, 
           new FieldValueMetaData(TType.I32)));
     }});
@@ -8336,6 +8414,7 @@
       String key,
       String columnFamily,
       boolean isAscending,
+      int offset,
       int count)
     {
       this();
@@ -8344,6 +8423,8 @@
       this.columnFamily = columnFamily;
       this.isAscending = isAscending;
       this.__isset.isAscending = true;
+      this.offset = offset;
+      this.__isset.offset = true;
       this.count = count;
       this.__isset.count = true;
     }
@@ -8363,6 +8444,8 @@
       }
       __isset.isAscending = other.__isset.isAscending;
       this.isAscending = other.isAscending;
+      __isset.offset = other.__isset.offset;
+      this.offset = other.offset;
       __isset.count = other.__isset.count;
       this.count = other.count;
     }
@@ -8463,6 +8546,28 @@
       this.__isset.isAscending = value;
     }
 
+    public int getOffset() {
+      return this.offset;
+    }
+
+    public void setOffset(int offset) {
+      this.offset = offset;
+      this.__isset.offset = true;
+    }
+
+    public void unsetOffset() {
+      this.__isset.offset = false;
+    }
+
+    // Returns true if field offset is set (has been asigned a value) and false otherwise
+    public boolean isSetOffset() {
+      return this.__isset.offset;
+    }
+
+    public void setOffsetIsSet(boolean value) {
+      this.__isset.offset = value;
+    }
+
     public int getCount() {
       return this.count;
     }
@@ -8519,6 +8624,14 @@
         }
         break;
 
+      case OFFSET:
+        if (value == null) {
+          unsetOffset();
+        } else {
+          setOffset((Integer)value);
+        }
+        break;
+
       case COUNT:
         if (value == null) {
           unsetCount();
@@ -8546,6 +8659,9 @@
       case ISASCENDING:
         return new Boolean(isIsAscending());
 
+      case OFFSET:
+        return new Integer(getOffset());
+
       case COUNT:
         return new Integer(getCount());
 
@@ -8565,6 +8681,8 @@
         return isSetColumnFamily();
       case ISASCENDING:
         return isSetIsAscending();
+      case OFFSET:
+        return isSetOffset();
       case COUNT:
         return isSetCount();
       default:
@@ -8621,6 +8739,15 @@
           return false;
       }
 
+      boolean this_present_offset = true;
+      boolean that_present_offset = true;
+      if (this_present_offset || that_present_offset) {
+        if (!(this_present_offset && that_present_offset))
+          return false;
+        if (this.offset != that.offset)
+          return false;
+      }
+
       boolean this_present_count = true;
       boolean that_present_count = true;
       if (this_present_count || that_present_count) {
@@ -8678,6 +8805,14 @@
               TProtocolUtil.skip(iprot, field.type);
             }
             break;
+          case OFFSET:
+            if (field.type == TType.I32) {
+              this.offset = iprot.readI32();
+              this.__isset.offset = true;
+            } else { 
+              TProtocolUtil.skip(iprot, field.type);
+            }
+            break;
           case COUNT:
             if (field.type == TType.I32) {
               this.count = iprot.readI32();
@@ -8721,6 +8856,9 @@
       oprot.writeFieldBegin(IS_ASCENDING_FIELD_DESC);
       oprot.writeBool(this.isAscending);
       oprot.writeFieldEnd();
+      oprot.writeFieldBegin(OFFSET_FIELD_DESC);
+      oprot.writeI32(this.offset);
+      oprot.writeFieldEnd();
       oprot.writeFieldBegin(COUNT_FIELD_DESC);
       oprot.writeI32(this.count);
       oprot.writeFieldEnd();
@@ -8761,6 +8899,10 @@
       sb.append(this.isAscending);
       first = false;
       if (!first) sb.append(", ");
+      sb.append("offset:");
+      sb.append(this.offset);
+      first = false;
+      if (!first) sb.append(", ");
       sb.append("count:");
       sb.append(this.count);
       first = false;

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java Mon Jul  6
17:50:16 2009
@@ -135,7 +135,7 @@
         {
             // table.cf['key']
         	List<column_t> columns = new ArrayList<column_t>();
-      		columns = thriftClient_.get_slice(tableName, key, columnFamily, true, 1000000);
+      		columns = thriftClient_.get_slice(tableName, key, columnFamily, true, 0, 1000000);
             int size = columns.size();
             for (Iterator<column_t> colIter = columns.iterator(); colIter.hasNext();
)
             {

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/ColumnRangeQueryRSD.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/ColumnRangeQueryRSD.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/ColumnRangeQueryRSD.java
(original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/ColumnRangeQueryRSD.java
Mon Jul  6 17:50:16 2009
@@ -97,7 +97,7 @@
         try
         {
             String key = (String)(rowKey_.get());
-            ReadCommand readCommand = new SliceFromReadCommand(cfMetaData_.tableName, key,
columnFamily_column, true, limit_);
+            ReadCommand readCommand = new SliceFromReadCommand(cfMetaData_.tableName, key,
columnFamily_column, true, offset_, limit_);
             row = StorageProxy.readProtocol(readCommand, StorageService.ConsistencyLevel.WEAK);
         }
         catch (Exception e)

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/SuperColumnRangeQueryRSD.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/SuperColumnRangeQueryRSD.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/SuperColumnRangeQueryRSD.java
(original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/cql/common/SuperColumnRangeQueryRSD.java
Mon Jul  6 17:50:16 2009
@@ -66,7 +66,7 @@
         try
         {
             String key = (String)(rowKey_.get());
-            ReadCommand readCommand = new SliceFromReadCommand(cfMetaData_.tableName, key,
cfMetaData_.cfName, true, limit_);
+            ReadCommand readCommand = new SliceFromReadCommand(cfMetaData_.tableName, key,
cfMetaData_.cfName, true, offset_, limit_);
             row = StorageProxy.readProtocol(readCommand, StorageService.ConsistencyLevel.WEAK);
         }
         catch (Exception e)

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java Mon
Jul  6 17:50:16 2009
@@ -1535,7 +1535,7 @@
      * get a list of columns starting from a given column, in a specified order
      * only the latest version of a column is returned
      */
-    public ColumnFamily getSliceFrom(String key, String cfName, String startColumn, boolean
isAscending, int count)
+    public ColumnFamily getSliceFrom(String key, String cfName, String startColumn, boolean
isAscending, int offset, int count)
     throws IOException, ExecutionException, InterruptedException
     {
         lock_.readLock().lock();
@@ -1620,16 +1620,18 @@
 
             // add unique columns to the CF container
             int liveColumns = 0;
+            int limit = offset + count;
             for (IColumn column : reduced)
             {
-                if (liveColumns >= count)
+                if (liveColumns >= limit)
                 {
                     break;
                 }
                 if (!column.isMarkedForDelete())
                     liveColumns++;
 
-                returnCF.addColumn(column);
+                if (liveColumns > offset)
+                    returnCF.addColumn(column);
             }
 
             return removeDeleted(returnCF);

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SliceFromReadCommand.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SliceFromReadCommand.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SliceFromReadCommand.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SliceFromReadCommand.java Mon
Jul  6 17:50:16 2009
@@ -25,13 +25,15 @@
 {
     public final String columnFamilyColumn;
     public final boolean isAscending;
+    public final int limit;
     public final int count;
 
-    public SliceFromReadCommand(String table, String key, String columnFamilyColumn, boolean
isAscending, int count)
+    public SliceFromReadCommand(String table, String key, String columnFamilyColumn, boolean
isAscending, int limit, int count)
     {
         super(table, key, CMD_TYPE_GET_SLICE_FROM);
         this.columnFamilyColumn = columnFamilyColumn;
         this.isAscending = isAscending;
+        this.limit = limit;
         this.count = count;
     }
 
@@ -44,7 +46,7 @@
     @Override
     public ReadCommand copy()
     {
-        ReadCommand readCommand = new SliceFromReadCommand(table, key, columnFamilyColumn,
isAscending, count);
+        ReadCommand readCommand = new SliceFromReadCommand(table, key, columnFamilyColumn,
isAscending, limit, count);
         readCommand.setDigestQuery(isDigestQuery());
         return readCommand;
     }
@@ -52,7 +54,7 @@
     @Override
     public Row getRow(Table table) throws IOException
     {
-        return table.getSliceFrom(key, columnFamilyColumn, isAscending, count);
+        return table.getSliceFrom(key, columnFamilyColumn, isAscending, limit, count);
     }
 
     @Override
@@ -63,6 +65,7 @@
                ", key='" + key + '\'' +
                ", columnFamily='" + columnFamilyColumn + '\'' +
                ", isAscending='" + isAscending + '\'' +
+               ", limit='" + limit + '\'' +
                ", count='" + count + '\'' +
                ')';
     }
@@ -79,6 +82,7 @@
         dos.writeUTF(realRM.key);
         dos.writeUTF(realRM.columnFamilyColumn);
         dos.writeBoolean(realRM.isAscending);
+        dos.writeInt(realRM.limit);
         dos.writeInt(realRM.count);
     }
 
@@ -90,9 +94,10 @@
         String key = dis.readUTF();
         String columnFamily = dis.readUTF();
         boolean isAscending = dis.readBoolean();
+        int limit = dis.readInt();
         int count = dis.readInt();
 
-        SliceFromReadCommand rm = new SliceFromReadCommand(table, key, columnFamily, isAscending,
count);
+        SliceFromReadCommand rm = new SliceFromReadCommand(table, key, columnFamily, isAscending,
limit, count);
         rm.setDigestQuery(isDigest);
         return rm;
     }

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java Mon Jul  6 17:50:16
2009
@@ -605,7 +605,7 @@
     /**
      * Selects a list of columns in a column family from a given column for the specified
key.
     */
-    public Row getSliceFrom(String key, String cf, boolean isAscending, int count) throws
IOException
+    public Row getSliceFrom(String key, String cf, boolean isAscending, int limit, int count)
throws IOException
     {
         Row row = new Row(table_, key);
         String[] values = cf.split(":", -1);
@@ -615,7 +615,7 @@
         long start1 = System.currentTimeMillis();
         try
         {
-            ColumnFamily columnFamily = cfStore.getSliceFrom(key, cfName, startWith, isAscending,
count);
+            ColumnFamily columnFamily = cfStore.getSliceFrom(key, cfName, startWith, isAscending,
limit, count);
             if (columnFamily != null)
                 row.addColumnFamily(columnFamily);
             long timeTaken = System.currentTimeMillis() - start1;

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java Mon
Jul  6 17:50:16 2009
@@ -167,7 +167,7 @@
         }
     }
 
-    public List<column_t> get_slice(String tablename, String key, String columnParent,
boolean isAscending, int count) throws InvalidRequestException
+    public List<column_t> get_slice(String tablename, String key, String columnParent,
boolean isAscending, int offset, int count) throws InvalidRequestException
     {
         logger.debug("get_slice_from");
         String[] values = columnParent.split(":", -1); // allow empty column specifier
@@ -178,7 +178,7 @@
         if ("Name".compareTo(DatabaseDescriptor.getCFMetaData(tablename, values[0]).indexProperty_)
!= 0)
             throw new InvalidRequestException("get_slice_from requires CF indexed by name");
 
-        ColumnFamily cfamily = readColumnFamily(new SliceFromReadCommand(tablename, key,
columnParent, isAscending, count));
+        ColumnFamily cfamily = readColumnFamily(new SliceFromReadCommand(tablename, key,
columnParent, isAscending, offset, count));
         if (cfamily == null)
         {
             return EMPTY_COLUMNS;
@@ -232,7 +232,7 @@
         ColumnFamily cfamily;
         if (DatabaseDescriptor.isNameSortingEnabled(tablename, values[0]))
         {
-            cfamily = readColumnFamily(new SliceFromReadCommand(tablename, key, columnParent
+ ":", true, Integer.MAX_VALUE));
+            cfamily = readColumnFamily(new SliceFromReadCommand(tablename, key, columnParent
+ ":", true, 0, Integer.MAX_VALUE));
         }
         else
         {
@@ -341,7 +341,7 @@
         return thriftSuperColumns;
     }
 
-    public List<superColumn_t> get_slice_super(String tablename, String key, String
columnFamily, boolean isAscending, int count) throws InvalidRequestException
+    public List<superColumn_t> get_slice_super(String tablename, String key, String
columnFamily, boolean isAscending, int offset, int count) throws InvalidRequestException
     {
         logger.debug("get_slice_super");
         String[] values = columnFamily.split(":", -1);
@@ -350,7 +350,7 @@
         if (count <= 0)
             throw new InvalidRequestException("get_slice_super requires positive count");
 
-        ColumnFamily cfamily = readColumnFamily(new SliceFromReadCommand(tablename, key,
columnFamily, isAscending, count));
+        ColumnFamily cfamily = readColumnFamily(new SliceFromReadCommand(tablename, key,
columnFamily, isAscending, offset, count));
         if (cfamily == null)
         {
             return EMPTY_SUPERCOLUMNS;

Modified: incubator/cassandra/trunk/test/system/test_server.py
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/system/test_server.py?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/test/system/test_server.py (original)
+++ incubator/cassandra/trunk/test/system/test_server.py Mon Jul  6 17:50:16 2009
@@ -43,13 +43,13 @@
 
 def _verify_batch():
     _verify_simple()
-    L = client.get_slice('Table1', 'key1', 'Standard2:', True, 1000)
+    L = client.get_slice('Table1', 'key1', 'Standard2:', True, 0, 1000)
     assert L == _SIMPLE_COLUMNS, L
 
 def _verify_simple():
     assert client.get_column('Table1', 'key1', 'Standard1:c1') == \
         column_t(columnName='c1', value='value1', timestamp=0)
-    L = client.get_slice('Table1', 'key1', 'Standard1:', True, 1000)
+    L = client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000)
     assert L == _SIMPLE_COLUMNS, L
 
 def _insert_super():
@@ -80,7 +80,7 @@
 def _verify_super(supercolumn='Super1'):
     assert client.get_column('Table1', 'key1', supercolumn + ':sc1:c4') == \
         column_t(columnName='c4', value='value4', timestamp=0)
-    slice = client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000)
+    slice = client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000)
     assert slice == _SUPER_COLUMNS, slice
 
 def _expect_exception(fn, type_):
@@ -101,10 +101,10 @@
         _verify_simple()
 
     def test_empty_slice(self):
-        assert client.get_slice('Table1', 'key1', 'Standard2:', True, 1000) == []
+        assert client.get_slice('Table1', 'key1', 'Standard2:', True, 0, 1000) == []
 
     def test_empty_slice_super(self):
-        assert client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000) == []
+        assert client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000) == []
 
     def test_missing_super(self):
         _expect_missing(lambda: client.get_column('Table1', 'key1', 'Super1:sc1:c1'))
@@ -160,24 +160,24 @@
         _expect_missing(lambda: client.get_column('Table1', 'key1', 'Standard1:c1'))
         assert client.get_column('Table1', 'key1', 'Standard1:c2') == \
             column_t(columnName='c2', value='value2', timestamp=0)
-        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 1000) == \
+        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000) == \
             [column_t(columnName='c2', value='value2', timestamp=0)]
 
         # New insert, make sure it shows up post-remove:
         client.insert('Table1', 'key1', 'Standard1:c3', 'value3', 0, True)
-        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 1000) == \
+        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000) == \
             [column_t(columnName='c2', value='value2', timestamp=0), 
              column_t(columnName='c3', value='value3', timestamp=0)]
 
         # Test resurrection.  First, re-insert the value w/ older timestamp, 
         # and make sure it stays removed:
         client.insert('Table1', 'key1', 'Standard1:c1', 'value1', 0, True)
-        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 1000) == \
+        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000) == \
             [column_t(columnName='c2', value='value2', timestamp=0), 
              column_t(columnName='c3', value='value3', timestamp=0)]
         # Next, w/ a newer timestamp; it should come back:
         client.insert('Table1', 'key1', 'Standard1:c1', 'value1', 2, True)
-        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 1000) == \
+        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000) == \
             [column_t(columnName='c1', value='value1', timestamp=2),
              column_t(columnName='c2', value='value2', timestamp=0), 
              column_t(columnName='c3', value='value3', timestamp=0)]
@@ -189,16 +189,16 @@
 
         # Remove the key1:Standard1 cf:
         client.remove('Table1', 'key1', 'Standard1', 3, True)
-        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 1000) == []
+        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000) == []
         _verify_super()
 
         # Test resurrection.  First, re-insert a value w/ older timestamp, 
         # and make sure it stays removed:
         client.insert('Table1', 'key1', 'Standard1:c1', 'value1', 0, True)
-        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 1000) == []
+        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000) == []
         # Next, w/ a newer timestamp; it should come back:
         client.insert('Table1', 'key1', 'Standard1:c1', 'value1', 4, True)
-        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 1000) == \
+        assert client.get_slice('Table1', 'key1', 'Standard1:', True, 0, 1000) == \
             [column_t(columnName='c1', value='value1', timestamp=4)]
 
 
@@ -209,7 +209,7 @@
         # Make sure remove clears out what it's supposed to, and _only_ that:
         client.remove('Table1', 'key1', 'Super1:sc2:c5', 5, True)
         _expect_missing(lambda: client.get_column('Table1', 'key1', 'Super1:sc2:c5'))
-        assert client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000) == \
+        assert client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000) == \
             [superColumn_t(name='sc1', 
                            columns=[column_t(columnName='c4', value='value4', timestamp=0)]),
              superColumn_t(name='sc2', 
@@ -224,17 +224,17 @@
                              columns=[column_t(columnName='c6', value='value6', timestamp=0),
                                       column_t(columnName='c7', value='value7', timestamp=0)])]
 
-        assert client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000) == scs
+        assert client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000) == scs
 
         # Test resurrection.  First, re-insert the value w/ older timestamp, 
         # and make sure it stays removed:
         client.insert('Table1', 'key1', 'Super1:sc2:c5', 'value5', 0, True)
-        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000)
+        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000)
         assert actual == scs, actual
 
         # Next, w/ a newer timestamp; it should come back
         client.insert('Table1', 'key1', 'Super1:sc2:c5', 'value5', 6, True)
-        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000)
+        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000)
         assert actual == \
             [superColumn_t(name='sc1', 
                            columns=[column_t(columnName='c4', value='value4', timestamp=0)]),

@@ -254,19 +254,19 @@
         assert actual == [], actual
         scs = [superColumn_t(name='sc1', 
                              columns=[column_t(columnName='c4', value='value4', timestamp=0)])]
-        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000)
+        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000)
         assert actual == scs, actual
         _verify_simple()
 
         # Test resurrection.  First, re-insert the value w/ older timestamp, 
         # and make sure it stays removed:
         client.insert('Table1', 'key1', 'Super1:sc2:c5', 'value5', 0, True)
-        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000)
+        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000)
         assert actual == scs, actual
 
         # Next, w/ a newer timestamp; it should come back
         client.insert('Table1', 'key1', 'Super1:sc2:c5', 'value5', 6, True)
-        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 1000)
+        actual = client.get_slice_super('Table1', 'key1', 'Super1:', True, 0, 1000)
         assert actual == \
             [superColumn_t(name='sc1', 
                            columns=[column_t(columnName='c4', value='value4', timestamp=0)]),

Modified: incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/ReadMessageTest.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/ReadMessageTest.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/ReadMessageTest.java (original)
+++ incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/ReadMessageTest.java Mon Jul
 6 17:50:16 2009
@@ -57,7 +57,7 @@
         rm2 = serializeAndDeserializeReadMessage(rm);
         assert rm2.toString().equals(rm.toString());
 
-        rm = new SliceFromReadCommand("Table1", "row1", "foo", true, 2);
+        rm = new SliceFromReadCommand("Table1", "row1", "foo", true, 0, 2);
         rm2 = serializeAndDeserializeReadMessage(rm);
         assert rm2.toString().equals(rm.toString());
         

Modified: incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TableTest.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TableTest.java?rev=791553&r1=791552&r2=791553&view=diff
==============================================================================
--- incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TableTest.java (original)
+++ incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TableTest.java Mon Jul  6
17:50:16 2009
@@ -146,12 +146,12 @@
         ColumnFamily cf;
 
         // key before the rows that exists
-        result = table.getSliceFrom("a", "Standard2:", true, 0);
+        result = table.getSliceFrom("a", "Standard2:", true, 0, 1);
         cf = result.getColumnFamily("Standard2");
         assertColumns(cf);
 
         // key after the rows that exist
-        result = table.getSliceFrom("z", "Standard2:", true, 0);
+        result = table.getSliceFrom("z", "Standard2:", true, 0, 1);
         cf = result.getColumnFamily("Standard2");
         assertColumns(cf);
     }
@@ -190,27 +190,27 @@
                 Row result;
                 ColumnFamily cf;
 
-                result = table.getSliceFrom(ROW, "Standard1:col5", true, 2);
+                result = table.getSliceFrom(ROW, "Standard1:col5", true, 0, 2);
                 cf = result.getColumnFamily("Standard1");
                 assertColumns(cf, "col5", "col7");
 
-                result = table.getSliceFrom(ROW, "Standard1:col4", true, 2);
+                result = table.getSliceFrom(ROW, "Standard1:col4", true, 0, 2);
                 cf = result.getColumnFamily("Standard1");
-                assertColumns(cf, "col4", "col5", "col7");
+                assertColumns(cf, "col5", "col7");
 
-                result = table.getSliceFrom(ROW, "Standard1:col5", false, 2);
+                result = table.getSliceFrom(ROW, "Standard1:col5", false, 0, 2);
                 cf = result.getColumnFamily("Standard1");
                 assertColumns(cf, "col3", "col4", "col5");
 
-                result = table.getSliceFrom(ROW, "Standard1:col6", false, 2);
+                result = table.getSliceFrom(ROW, "Standard1:col6", false, 0, 2);
                 cf = result.getColumnFamily("Standard1");
                 assertColumns(cf, "col3", "col4", "col5");
 
-                result = table.getSliceFrom(ROW, "Standard1:col95", true, 2);
+                result = table.getSliceFrom(ROW, "Standard1:col95", true, 0, 2);
                 cf = result.getColumnFamily("Standard1");
                 assertColumns(cf);
 
-                result = table.getSliceFrom(ROW, "Standard1:col0", false, 2);
+                result = table.getSliceFrom(ROW, "Standard1:col0", false, 0, 2);
                 cf = result.getColumnFamily("Standard1");
                 assertColumns(cf);
             }
@@ -258,7 +258,7 @@
                 Row result;
                 ColumnFamily cfres;
 
-                result = table.getSliceFrom(ROW, "Standard1:col2", true, 3);
+                result = table.getSliceFrom(ROW, "Standard1:col2", true, 0, 3);
                 cfres = result.getColumnFamily("Standard1");
                 assertColumns(cfres, "col2", "col3", "col4");
                 assertEquals(new String(cfres.getColumn("col2").value()), "valx");
@@ -286,28 +286,42 @@
 
         Row result;
         ColumnFamily cfres;
-        result = table.getSliceFrom(ROW, "Standard1:col1000", true, 3);
+        result = table.getSliceFrom(ROW, "Standard1:col1000", true, 0, 3);
         cfres = result.getColumnFamily("Standard1");
         assertColumns(cfres, "col1000", "col1001", "col1002");
         assertEquals(new String(cfres.getColumn("col1000").value()), "vvvvvvvvvvvvvvvv1000");
         assertEquals(new String(cfres.getColumn("col1001").value()), "vvvvvvvvvvvvvvvv1001");
         assertEquals(new String(cfres.getColumn("col1002").value()), "vvvvvvvvvvvvvvvv1002");
 
-        result = table.getSliceFrom(ROW, "Standard1:col1195", true, 3);
+        result = table.getSliceFrom(ROW, "Standard1:col1195", true, 0, 3);
         cfres = result.getColumnFamily("Standard1");
         assertColumns(cfres, "col1195", "col1196", "col1197");
         assertEquals(new String(cfres.getColumn("col1195").value()), "vvvvvvvvvvvvvvvv1195");
         assertEquals(new String(cfres.getColumn("col1196").value()), "vvvvvvvvvvvvvvvv1196");
         assertEquals(new String(cfres.getColumn("col1197").value()), "vvvvvvvvvvvvvvvv1197");
 
-        result = table.getSliceFrom(ROW, "Standard1:col1196", false, 3);
+        result = table.getSliceFrom(ROW, "Standard1:col1195", true, 10, 3);
+        cfres = result.getColumnFamily("Standard1");
+        assertColumns(cfres, "col1205", "col1206", "col1207");
+        assertEquals(new String(cfres.getColumn("col1205").value()), "vvvvvvvvvvvvvvvv1205");
+        assertEquals(new String(cfres.getColumn("col1206").value()), "vvvvvvvvvvvvvvvv1206");
+        assertEquals(new String(cfres.getColumn("col1207").value()), "vvvvvvvvvvvvvvvv1207");
+
+        result = table.getSliceFrom(ROW, "Standard1:col1196", false, 0, 3);
         cfres = result.getColumnFamily("Standard1");
         assertColumns(cfres, "col1194", "col1195", "col1196");
         assertEquals(new String(cfres.getColumn("col1194").value()), "vvvvvvvvvvvvvvvv1194");
         assertEquals(new String(cfres.getColumn("col1195").value()), "vvvvvvvvvvvvvvvv1195");
         assertEquals(new String(cfres.getColumn("col1196").value()), "vvvvvvvvvvvvvvvv1196");
 
-        result = table.getSliceFrom(ROW, "Standard1:col1990", true, 3);
+        result = table.getSliceFrom(ROW, "Standard1:col1196", false, 10, 3);
+        cfres = result.getColumnFamily("Standard1");
+        assertColumns(cfres, "col1184", "col1185", "col1186");
+        assertEquals(new String(cfres.getColumn("col1184").value()), "vvvvvvvvvvvvvvvv1184");
+        assertEquals(new String(cfres.getColumn("col1185").value()), "vvvvvvvvvvvvvvvv1185");
+        assertEquals(new String(cfres.getColumn("col1186").value()), "vvvvvvvvvvvvvvvv1186");
+
+        result = table.getSliceFrom(ROW, "Standard1:col1990", true, 0, 3);
         cfres = result.getColumnFamily("Standard1");
         assertColumns(cfres, "col1990", "col1991", "col1992");
         assertEquals(new String(cfres.getColumn("col1990").value()), "vvvvvvvvvvvvvvvv1990");
@@ -342,7 +356,7 @@
                 Row result;
                 ColumnFamily cfres;
 
-                result = table.getSliceFrom(ROW, "Super1:", true, 10);
+                result = table.getSliceFrom(ROW, "Super1:", true, 0, 10);
                 cfres = result.getColumnFamily("Super1");
                 assertColumns(cfres, "sc1");
                 assertEquals(new String(cfres.getColumn("sc1").getSubColumn("col1").value()),
"val1");



Mime
View raw message